anthropics / anthropics/claude-code
Plugin MCP OAuth is per-session and not durable; Cowork sessions can never authenticate one at all
- Ngôn ngữ chính
- Python
- Star
- 145k
- Fork
- 23.1k
- Chỉ số merge pull request
- Chỉ số pull request đang chờ
Mô tả
# Plugin MCP OAuth is per-session and not durable; Cowork sessions can never authenticate one at all
## Summary
A plugin-delivered remote MCP server can be authenticated from a **Code** session, but the connection is bound to that session and does not survive — the same session needed a full browser consent four times in six minutes, and a second session needed its own. **Cowork sessions cannot authenticate one at all**: they load the plugin, they record the server as needing auth, and there is no affordance anywhere to connect it, so the plugin's tools are permanently unavailable in Cowork.
This is distinct from #93671 (see below).
## Environment
- Claude Desktop **1.52386.6**, 3P deployment (gateway inference provider)
- Bundled Claude Code **2.1.270** (earlier observations on 2.1.266)
- macOS (Darwin 25.6)
- Plugin installed from an **organization marketplace, `url` source** served over HTTPS, declaring one remote MCP server:
```json
{ "mcpServers": { "atlassian": { "type": "http", "url": "https://mcp.atlassian.com/v1/mcp/authv2", "oauth": true } } }
```
- SDK server key: `plugin:atlassian:atlassian`
## Part A — Cowork sessions can never authenticate the server
The plugin **is** delivered to Cowork. From a Cowork session's `sdkOptions`:
```
plugins: [
{ type: 'local', path: '…/claude-hostloop-plugins//' },
{ type: 'local', path: '…/claude-hostloop-plugins//atlassian' }
]
```
and its CLI config records `pluginUsage: { "atlassian@inline": { … } }`.
But every Cowork session records the server as unauthenticated, in its own per-session CLI home:
```
local-agent-mode-sessions//00000000/31991e06/.claude/mcp-needs-auth-cache.json
{"plugin:atlassian:atlassian":{"timestamp":1789401264697}} # 2026-09-14 16:54
local-agent-mode-sessions//00000000/203d1886/.claude/mcp-needs-auth-cache.json
{"plugin:atlassian:atlassian":{"timestamp":1789395131601}} # 2026-09-14 15:12
```
The 16:54 entry was created **after** a successful sign-in from a Code session at 15:17, so nothing carries over.
Two structural details that appear to make this unreachable for a user:
1. **`mcpAuthenticate` is per-session.** Every call in the log carries a session id:
`LocalSessions.mcpAuthenticate: sessionId=local_…, server=plugin:atlassian:atlassian`.
No such call has ever been made for a Cowork session — not because it failed, but because nothing initiates one.
2. **Each Cowork session gets a fresh `.claude` home** under
`local-agent-mode-sessions//00000000//.claude/`, with a synthetic identity
(`oauthAccount.emailAddress = "cowork-3p@localhost"`), so per-home state cannot accumulate.
Settings → Plugins → *(plugin)* → **Connect** is the only visible entry point, and it is disabled unless it can borrow a session that advertises the key:
```js
disabled: !borrowedSessionId || busy
// tooltip: "Open a Code session that loads this connector, then try again"
```
## Part B — In Code, the connection is not durable
The same Code session ran the **full** OAuth cycle (`authUrl` → callback → reconnect) four times in six minutes:
```
15:10:51 mcpAuthenticate sessionId=local_6c377534 → authUrl= callbackExpected=true redirectScheme=custom error=none
15:11:20 mcpSubmitOAuthCallbackUrl → error=none
15:11:20 mcpReconnect → connected
15:12:58 mcpAuthenticate (same session, full cycle again)
15:13:32 mcpAuthenticate (again)
15:16:54 mcpAuthenticate (again) → connected at 15:17:24
```
A second Code session used the tools successfully at 16:55, then required its own full cycle at 17:14:
```
17:14:54 mcpAuthenticate sessionId=local_53073f69 → authUrl= …
17:15:04 mcpReconnect → connected
```
Each of those is a browser consent, not a silent token refresh.
## Why this is not #93671
#93671 reports the desktop sending `redirect_uri=claude://claude.ai/mcp-auth-callback/sdk`, which Cloudflare's authorization server **refuses**, and the CLI's connection not being visible to the desktop.
Here the custom scheme is **accepted** — `redirectScheme=custom … error=none`, callback submitted, `mcpReconnect → connected` — so OAuth completes end to end against this authorization server. The failures are different:
- the connection does not persist for the session that authorized it, and
- Cowork sessions have no path to authorize one at all.
## Expected
- A plugin MCP server authorized once is reachable from subsequent sessions without re-consent, or at most a silent reconnect.
- Cowork sessions can authenticate a plugin-delivered MCP server, or the UI states why they cannot.
## Impact
Plugins are the documented way for an organization to distribute an MCP server together with its skills. On this build the skills load in Cowork while the server's tools never do, so an org plugin silently delivers half of itself on that surface. In Code it works but asks for consent repeatedly.
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Đánh giá
Issue này chưa được đánh giá.