Skip to content

fix(mcp): use type for cursor/codebuddy remote servers and keep secrets off disk - #260

Merged
jeff-r2026 merged 1 commit into
mainfrom
fix/mcp-remote-format-and-env-expansion
Jul 29, 2026
Merged

fix(mcp): use type for cursor/codebuddy remote servers and keep secrets off disk#260
jeff-r2026 merged 1 commit into
mainfrom
fix/mcp-remote-format-and-env-expansion

Conversation

@jeff-r2026

Copy link
Copy Markdown
Collaborator

Problem

After the project-scope secret work landed (#258/#259), CodeBuddy and Cursor remote MCP servers still failed to authenticate — CodeBuddy returned 401 缺少或无效的 Bearer Token on both streamable-HTTP and SSE.

Two independent bugs:

  1. Wrong transport field. teamai wrote remote servers for codebuddy/cursor as transportType: "streamable-http". Both tools ignore that field — they key the transport off type, exactly like the claude family. With no recognized transport, the Authorization header was never sent → 401.
  2. Secrets on disk. feat(mcp): resolve secrets into project-scope configs for all tools #258 made these tools resolve ${VAR} to the literal value and write it into their config file (which lives in the repo and is typically committed). Both tools can actually expand env vars themselves; we just weren't using it.

Fix

  • renderBuddy / renderCursor now emit type: def.transport for remote servers (matching the claude family), instead of the ignored transportType.
  • supportsEnvExpansion returns true for cursor and buddy in every scope, so the placeholder is passed through and the secret stays off disk.
  • Per-tool placeholder syntax in the renderers:
    • CodeBuddy interpolates the bare ${VAR} → passed through unchanged.
    • Cursor interpolates ${env:NAME}${VAR} is rewritten into that syntax.
  • The resolve-to-plaintext path remains only as a fallback: user-scope claude, and codex placeholders it cannot express as a whole-header variable.

Test Plan

  • npx tsc --noEmit — clean
  • npx vitest run — 1827 passing (updated the project-scope secret test to assert per-tool placeholder syntax; scoped the "unresolved ${VAR} skips" test to claude, the only resolving target)
  • npm run build
  • End-to-end against the real test repo (teamai-dev-repo, project scope in ../llm):
    • claude .mcp.json: type:"http" + Bearer ${GPU_ANALYSIS_TOKEN}
    • codebuddy .codebuddy/mcp.json: type:"http" + Bearer ${GPU_ANALYSIS_TOKEN} (was transportType)
    • cursor .cursor/mcp.json: type:"http" + Bearer ${env:GPU_ANALYSIS_TOKEN}
    • No plaintext token in any project file.
    • curl -X POST to the backend with the resolved token + streamable-HTTP headers → HTTP 200, confirming the header now ships and the 401 is resolved.
  • Docs updated in both languages (docs/usage-guide.md + docs/usage-guide.zh-CN.md).

🤖 Generated with Claude Code

…rets off disk

CodeBuddy and Cursor were getting remote (http/sse) MCP servers written with
`transportType: "streamable-http"`, a field both tools ignore — so the
Authorization header never shipped and the server 401'd. Both key the transport
off `type`, exactly like the claude family. Emit `type` for them.

While fixing the format, restore placeholder passthrough for these two tools so
team secrets no longer land on disk (undoing that part of #258 for them):
- CodeBuddy interpolates the bare `${VAR}` in every scope — pass it through.
- Cursor interpolates `${env:NAME}` — rewrite `${VAR}` into that syntax.

`supportsEnvExpansion` now returns true for cursor/buddy; the renderers carry
the per-tool placeholder syntax. The resolve-to-plaintext path remains only as a
fallback (user-scope claude, codex placeholders it cannot name as a whole
header).

Verified end-to-end against the real test repo in a project-scope install:
claude keeps `${VAR}`, codebuddy `type:"http"` + `${VAR}`, cursor `type:"http"`
+ `${env:VAR}`; a POST to the backend with the resolved token returns HTTP 200,
confirming the header now ships. Docs (EN + zh-CN) updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jeff-r2026
jeff-r2026 merged commit 529b183 into main Jul 29, 2026
6 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