Skip to content

ug mcp add: register connection-backed MCP services as direct HTTP for OAuth-client-capable agents - #555

Closed
sunishsheth2009 wants to merge 1 commit into
databricks:mainfrom
sunishsheth2009:mcp-claude-code-http
Closed

ug mcp add: register connection-backed MCP services as direct HTTP for OAuth-client-capable agents#555
sunishsheth2009 wants to merge 1 commit into
databricks:mainfrom
sunishsheth2009:mcp-claude-code-http

Conversation

@sunishsheth2009

@sunishsheth2009 sunishsheth2009 commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

What

Give Claude Code and Cursor their native connection-login experience for connection-backed AI Gateway mcp-services endpoints (e.g. system.ai.github): the agent itself is the OAuth client and drives the /oidc/mcp-service-login login, so /mcp shows a real "Authenticate" (Claude) / login (Cursor) prompt instead of a token silently injected by the proxy. This is a much better UX than the generic stdio-proxy path for the agents that can do it.

It is probe-driven with a safe fallback: only used when the agent's OAuth app is actually published on the workspace; otherwise (and for every other agent) it falls back to the generic ug mcp-proxy stdio path (#557).

How

/oidc has no dynamic client registration, so the agent must present a pre-registered public client whose loopback /callback redirect is registered:

  • Claude Codeclaude mcp add --transport http --client-id claude-code (Claude drives MCP OAuth with the RFC 8707 resource indicator).
  • Cursor → a url + auth: {CLIENT_ID: cursor-desktop} entry in ~/.cursor/mcp.json (Cursor supports a pre-registered client; its fixed http://localhost:8787/callback redirect matches by path, RFC 8252 §8.4).

mcp_oauth.oauth_client_available(workspace, client_id) back-channel-probes /oidc/v1/token (401 invalid_client = absent, else present) and caches the answer per workspace (weekly TTL). configure_client_mcp_server registers direct-HTTP only when: the URL is a connection-backed mcp-services endpoint, the agent has a mapped OAuth client (AGENT_OAUTH_CLIENT), that client is published, and it isn't a --use-pat / skills-registry registration. Everything else keeps the stdio proxy.

Relationship to the generic proxy (#557)

Complementary. #557 gives every agent a working login via the proxy (connect-time databricks auth login --resource). This PR is a UX upgrade layered on top: where an agent can be the OAuth client and its app exists, we let it drive the login natively. Same server-side flow underneath (/oidc/mcp-service-login), same §2/§3 dependency.

Dependencies

Same server side as #557: AI Gateway §1 (WWW-Authenticate 401, already on staging) + login §2 (/oidc resource-indicator redirect) + webapp §3 (/mcp-service-login return_to). No CLI dependency for the native path (the agent is the OAuth client, not the CLI).

Scope / fallback

  • Connection-backed mcp-services + Claude/Cursor + published app → native direct-HTTP.
  • No published app, other agents (codex/gemini/copilot/opencode), PAT, non-connection MCPs, skills registry → generic stdio proxy (unchanged).

Tests

test_mcp_oauth (probe: present/absent/network-fail, cache TTL). test_mcp.TestConfigureClientMcpServer (Claude + Cursor each: direct-HTTP when the app is available, proxy fallback when not, proxy under --use-pat, proxy for non-connection URLs; an OAuth-less agent proxies and never probes). test_agent_cursor (the url+auth entry shape and merge). uv run pytest green (pre-existing unrelated failures in test_codex_smart_routing_v2 / test_e2e_user_agent confirmed on main); ruff + ty clean.

This pull request and its description were written by Isaac.

…r OAuth-client-capable agents

Connection-backed AI Gateway MCP services (…/ai-gateway/mcp-services/…) need a
per-user connection login before their tools can be called. Registered as the
stdio proxy, an agent only ever sees "connected" (the proxy injects a workspace
token) and the login can't be triggered from /mcp. Registered as a direct-HTTP
server, the agent does the OAuth itself: /mcp shows "needs authentication" →
Authenticate → /oidc → /mcp-service-login → login → connected.

/oidc has no dynamic client registration, so the agent must present a
pre-registered public client. Only Claude Code's `mcp add` supports pinning one
(--client-id); its published claude-code app has the loopback /callback redirect
Claude uses. Other agents' `mcp add` accept only a static bearer, not an OAuth
client — codex (--bearer-token-env-var), gemini (--header), cursor (config) — so
despite their published apps (codex-cli, cursor-desktop, …) they can't drive
this flow and stay on the stdio proxy.

ug mcp add now registers these services as direct HTTP with the agent's OAuth
client (AGENT_OAUTH_CLIENT — today just claude → claude-code) when that client is
registered on the workspace, probed via a back-channel token-endpoint check
(401 invalid_client = absent, cached per workspace+client). Everything else keeps
the stdio proxy: non-connection MCPs, the skills registry, PAT auth, agents with
no mapped OAuth client, and workspaces where the client isn't published.

Co-authored-by: Isaac <no-reply@databricks.com>
@sunishsheth2009

Copy link
Copy Markdown
Collaborator Author

Closing: superseded by the simpler setup-time login approach. The Claude-only direct-HTTP path can't cover codex/gemini/etc.; instead ucode will run databricks auth login --resource <mcp-url> at ug mcp add time (needs CLI flag databricks/cli#6621), which works for every agent with no per-agent OAuth app or proxy change. Tracked in the reworked #557.

@sunishsheth2009

Copy link
Copy Markdown
Collaborator Author

Revived and superseded by #560, which rebases this onto current main and extends the native direct-HTTP OAuth path to Cursor (~/.cursor/mcp.json url+auth.CLIENT_ID) alongside Claude Code, still probe-driven with the stdio proxy (#557) as the fallback. Continuing there.

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