Skip to content

Add Cursor as an MCP client#192

Open
sunishsheth2009 wants to merge 1 commit into
databricks:mainfrom
sunishsheth2009:sunish-sheth_data/cursor-mcp-support
Open

Add Cursor as an MCP client#192
sunishsheth2009 wants to merge 1 commit into
databricks:mainfrom
sunishsheth2009:sunish-sheth_data/cursor-mcp-support

Conversation

@sunishsheth2009

@sunishsheth2009 sunishsheth2009 commented Jul 8, 2026

Copy link
Copy Markdown

Summary

Adds Cursor as an MCP client in ucode, so ucode configure mcp can register Databricks managed MCP servers into ~/.cursor/mcp.json, plus a ucode cursor launcher that keeps them authenticated.

Cursor is MCP-only: cursor-agent runs models on the user's own Cursor account and exposes no gateway base URL, so ucode configures no models for it (it stays out of agents.__init__._MODULES). What ucode does is wire Databricks MCP servers into Cursor's config via the existing ucode configure mcp flow and authenticate them with a Databricks OAuth token.

Auth: literal token + background refresh

cursor-agent does not expand environment variables in ~/.cursor/mcp.json header values. Given an unresolved ${env:OAUTH_TOKEN}, it sends an empty credential, the server answers 401 with OAuth metadata, and cursor-agent then falls into a dynamic-client-registration flow that Databricks managed MCP does not support (Incompatible auth server: does not support dynamic client registration).

So ucode embeds the resolved bearer token literally in the entry's Authorization header. Cursor's mcp.json supports no per-request credential-helper command (the model apiKeyHelper mechanism Claude/Codex use is unavailable for MCP here), so to keep the token fresh ucode cursor uses the same background-refresh pattern as the other literal-token agents (Copilot/OpenCode/Gemini): mint a token, rewrite the managed entries, spawn cursor-agent as a child, and re-mint + rewrite every ~30 min until it exits.

Changes

  • src/ucode/agents/cursor.py (new): write_/remove_mcp_server_config merge surgically into the shared ~/.cursor/mcp.json (preserving the user's own entries); refresh_mcp_tokens rewrites the ucode-managed entries with a fresh token; launch() refreshes, spawns cursor-agent, and runs a daemon refresh thread.
  • src/ucode/mcp.py: register cursor in MCP_CLIENTS; configure/remove branches; MCP_ONLY_CLIENTS so cursor is eligible whenever cursor-agent is installed (it never lands in available_tools); thread the cursor bearer token through apply_mcp_server_changes / configure_client_mcp_server.
  • src/ucode/cli.py: ucode cursor launch command.
  • Tests + README.

Verification

Verified end-to-end against a live workspace (e2-dogfood UC):

  • cursor-agent mcp listdatabricks-system-ai: ready
  • cursor-agent mcp list-tools databricks-system-ai → 4 live tools (system__ai__ai_classify, ai_extract, ai_parse_document, python_exec)
  • Wrote a deliberately stale placeholder token, ran the launch refresh, and confirmed the file header was replaced with a real token and cursor-agent listed tools with OAUTH_TOKEN unset — proving auth comes from the refreshed file header.
  • Confirmed the failure mode with ${env:...} (DCR error) vs. success with a literal token, same endpoint/env.

uv run pytest → 868 passed (2 pre-existing test_e2e_user_agent network failures unrelated to this change); uv run ruff check clean.

Known limitation

The background thread bounds token staleness to the ~30-min refresh interval and keeps ~/.cursor/mcp.json current, but whether Cursor picks up the rewritten token mid-session depends on cursor-agent re-reading mcp.json on change (not documented). This matches the freshness story of the other literal-token agents; a per-request helper isn't possible because Cursor's mcp.json has no credential-command field.

This pull request and its description were written by Isaac.

Register Databricks managed MCP servers in Cursor's ~/.cursor/mcp.json and
add a `ucode cursor` launcher that authenticates them.

Cursor is MCP-only: cursor-agent runs models on the user's own Cursor account
and exposes no gateway base URL, so ucode configures no models for it (it stays
out of agents.__init__._MODULES). What ucode does is wire Databricks MCP servers
into ~/.cursor/mcp.json via the existing `ucode configure mcp` flow and mint the
OAuth token they authenticate with.

- agents/cursor.py: write_/remove_mcp_server_config merge surgically into the
  shared ~/.cursor/mcp.json (preserving the user's own entries), using Cursor's
  `Bearer ${env:OAUTH_TOKEN}` header form. launch() sets OAUTH_TOKEN and execs
  cursor-agent, mirroring the claude/codex token-at-launch pattern.
- mcp.py: register cursor in MCP_CLIENTS; configure/remove branches; add
  MCP_ONLY_CLIENTS so cursor is eligible whenever cursor-agent is installed
  (it never lands in available_tools). Revert is handled by the generic
  per-client removal loop.
- cli.py: `ucode cursor` launch command.
- Tests + README.

Co-authored-by: Isaac
@sunishsheth2009 sunishsheth2009 force-pushed the sunish-sheth_data/cursor-mcp-support branch from 7e10377 to a40057e Compare July 8, 2026 18:10
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.

2 participants