Skip to content

fix(mcp): auto-authorize UC connections when proxy returns JSON-RPC auth error#12

Merged
DoyleDev merged 7 commits into
mainfrom
fix/uc-mcp-jsonrpc-auth
May 20, 2026
Merged

fix(mcp): auto-authorize UC connections when proxy returns JSON-RPC auth error#12
DoyleDev merged 7 commits into
mainfrom
fix/uc-mcp-jsonrpc-auth

Conversation

@DoyleDev
Copy link
Copy Markdown
Collaborator

Summary

Mason's UC external MCP connect path silently fails for first-time connections that need per-user authorization. The Databricks MCP proxy returns "needs authorization" as an HTTP-200 JSON-RPC error (code -32600) with a message like:

Credential for user identity('…') is not found for the connection ''. Please login first to the connection by visiting https://…/explore/connections/?o=

Mason's existing auto-authorize flow only fired on HTTP 401/403, so users saw `[MCP] Found 0 tools` and were stuck.

Changes

  • main.ts `mcpRequest`: detect JSON-RPC error responses matching the auth-required patterns and throw a 401-flavored error. Extract the embedded authorize URL from the message when present (it includes the workspace `?o=` param, which a reconstructed URL wouldn't).
  • src/mcp.ts: new `detectAuthError(msg)` helper covers HTTP-401 wording AND the proxy's "Please login first" / "Credential for user identity" text. Both the manual UC "Connect" button path and `autoConnectMcp` use it. Prefer the message-embedded authorize URL.

Bumps to 1.4.1.

Test plan

  • First-time connect a UC external connection (e.g. `system_ai_agent_atlassian_mcp`) — Mason should open the Authorize window automatically instead of silently returning 0 tools.
  • Already-authorized connections still connect on the first try, no auth window.
  • Genuine HTTP 401 still works.
  • Non-auth JSON-RPC errors (bad method, etc.) still surface as user-visible errors and don't open an authorize window.

This pull request and its description were written by Isaac.

DoyleDev added 7 commits May 19, 2026 20:27
…uth error

The Databricks MCP proxy returns "needs authorization" as an HTTP-200
JSON-RPC error with code -32600 and a message like:

  Credential for user identity('...') is not found for the connection
  '<name>'. Please login first to the connection by visiting
  https://<host>/explore/connections/<name>?o=<workspaceId>

Mason's existing auto-authorize flow only fired on HTTP 401/403, so the
proxy's auth-required path silently logged "Found 0 tools" and the user
was stuck. They had to copy the URL out of the console and visit it
manually before retrying.

This change:
- main.ts mcpRequest: detect JSON-RPC error responses matching the auth
  patterns and throw a 401-flavored error. Extract the embedded
  authorize URL from the message when present.
- src/mcp.ts: add detectAuthError() that covers HTTP-401 wording AND
  the proxy's "Please login first" / "Credential for user identity"
  text. Both the manual UC Connect button and the autoConnectMcp loop
  use it. Prefer the message-embedded authorize URL over a
  reconstructed /explore/connections/<name> path so the workspace id
  ("?o=...") is preserved when the proxy provides it.

Co-authored-by: Isaac
Co-authored-by: Isaac
The renderer's mcpUrlFor() treated any UC connection with a directHost
as if it were an MCP-speaking endpoint and built "<host>/mcp". That
shortcut was added for Databricks Apps that host their own MCP server
(mcp-salesforce-XXX.aws.databricksapps.com), where bypassing the UC
proxy is intentional.

But for SaaS endpoints — mcp.atlassian.com, www.googleapis.com,
api.githubcopilot.com, graph.microsoft.com — the UC proxy is the only
correct path: it handles credential translation, per-user OAuth, and
the MCP shim. Hitting those hosts directly with /mcp produces a 404
HTML error page from the upstream SaaS.

Gate the directHost shortcut on the hostname matching
*.databricksapps.com. Everything else routes through the UC proxy
at <workspace>/api/2.0/mcp/external/<name>, which combined with
the earlier JSON-RPC auth detection makes UC external connections
(Atlassian, GitHub, Gmail, SharePoint, …) connect cleanly on the
first authorize.

Co-authored-by: Isaac
For tools that take no parameters (e.g. atlassianUserInfo,
getAccessibleAtlassianResources), Anthropic via the Databricks AI
Gateway streams the tool_call with an empty function.arguments
delta. Mason's stream accumulator initialized arguments to "" and
never normalized when no delta came in, so the assistant message
landed in history with arguments: "". The next chat-loop turn sent
that message back to the Gateway, which rightly rejected it:

  API 400: Param 'arguments' in the tool_calls function specification
  is not a valid JSON string. No content to map due to end-of-input

OpenAI/Anthropic client SDKs normalize empty arguments to "{}" for
exactly this reason. Do the same here after the SSE loop finishes
accumulating tool_calls — affects every model+tool combination that
the gateway round-trips through chat completions, not just Atlassian.

Co-authored-by: Isaac
Many system-managed UC HTTP connections (Google Drive, SharePoint,
Gmail, GitHub Copilot API, Tavily REST, etc.) are credential-only
OAuth shims for SaaS REST APIs — they share connection_type "HTTP"
with real MCP-speaking connections but the Databricks MCP proxy at
/api/2.0/mcp/external/<name> returns 404 for them (the proxy
forwards to googleapis.com/sharepoint/etc., which 404 on /initialize).

The UC API exposes this via the is_mcp_connection field. Filter
list-uc-connections to require it be truthy (or absent for legacy
workspaces that pre-date the field — backward compatible).

Result: Mason's UC MCP picker now only shows connections that
actually speak MCP, eliminating the dead-end 404 attempts on Google
Drive / SharePoint / etc.

Co-authored-by: Isaac
autoConnectMcp loops over every URL ever saved to ~/.mason/config/
workspaces.json. When the UC discovery filter (is_mcp_connection
gating) started dropping non-MCP connections from the picker, the
URLs from earlier sessions stayed in saved config and kept retrying
on every launch — producing repeated 404 spam for connections that
will never work (Google Drive, SharePoint, Gmail, etc.).

This change prunes them in place. When auto-connect fails on a UC
proxy URL with a non-auth 4xx (either immediately or after the
authorize-then-retry path), Mason flags the URL as "not actually an
MCP server" and drops it from workspace config at the end of the
auto-connect loop. The write happens once per session and only when
something was actually dropped.

Only UC proxy URLs are eligible for auto-pruning — arbitrary
user-pasted HTTP MCP URLs aren't touched (transient outage there
shouldn't auto-destroy their config).

Co-authored-by: Isaac
A user hit:

  API 400: Param 'arguments' in the tool_calls function specification
  is not a valid JSON string. Unexpected end-of-input...
  [Source: {"compute_type": "serverless", "language": "python"; ...]

The model started streaming a tool call, then the stream cut off mid-
JSON (max_tokens hit, abort, or network glitch). Mason's accumulator
kept the partial string {"...":"python" with no closing brace, sent it
back to the Gateway on the next turn, and the Gateway rejected the
whole request — wedging the conversation until reload.

The previous fix only normalized *empty* arguments to "{}". This adds
JSON-validity sanity: if arguments fail JSON.parse, replace with "{}"
and log a warning. Tool runs with no args; model recovers on the next
turn instead of the entire conversation breaking.

Factor into a shared sanitizeToolCalls() helper used on all three
return paths: streamed chat completions, non-streamed chat completions,
and the Responses API translation.

Co-authored-by: Isaac
@DoyleDev DoyleDev merged commit 45b83eb into main May 20, 2026
0 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant