You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
Summary
Add a plugin hook that lets plugins inject HTTP headers into outbound MCP tool calls, with the current sessionID (and callID, server, tool) available in scope. This enables per-session/per-request
header forwarding (e.g. X-Session-Id, X-User-Id) to remote MCP servers — something the existing static headers config and OAuth cannot express, because headers today are bound at transport construction
time.
Current behavior
Remote MCP headers (packages/opencode/src/config/mcp.ts:41) are a static Record<string,string> resolved once at config load via {env:...}/{file:...} substitution.
Those headers are passed to StreamableHTTPClientTransport / SSEClientTransport via requestInit.headers at construction time (packages/opencode/src/mcp/index.ts:335,342). After construction the
transport is shared across all sessions, so headers cannot vary per call.
The tool execute(args) closure at packages/opencode/src/mcp/index.ts:168 does not carry any session context, so even a per-call template like {session:id} would have nothing to resolve against.
There is therefore no way today — via config, plugin, or otherwise — to attach the current sessionID (or any other per-call value) as a header on outbound MCP HTTP requests.
Proposed shape
A new plugin hook modeled on the existing chat.headers hook (packages/plugin/src/index.ts:256), but fired before each outbound MCP request:
Hook fires once per client.callTool (and ideally per listTools / getPrompt / readResource too, for consistency — happy to scope down to callTool only in v1).
output.headers is pre-populated with the static headers from config; the hook may add, override, or remove keys.
Resulting headers are merged into the outbound HTTP request via a custom fetch passed to the SDK transports (requestInit.fetch), since the SDK does not expose per-call header injection. The transport remains
shared across sessions; only the fetch wrapper is per-call-aware.
Per-call context (sessionID, callID, server, tool) is propagated from the tool execute boundary in packages/opencode/src/session/prompt.ts via AsyncLocalStorage (or Effect Context), read inside the
wrapper-fetch.
If multiple plugins register the hook, they run in order and each sees the previous plugin's mutations to output.headers (matching existing hook semantics).
Static config headers continues to work unchanged. {env:...}/{file:...} substitution still resolves at load time.
Why this would help
Lets users correlate MCP server logs/observability with opencode sessions (one of the most common asks for any tool-running agent).
Lets multi-tenant or per-user deployments forward identity to MCP servers without spinning up a separate opencode process per user.
Matches the precedent already set by chat.headers for LLM provider HTTP calls — same surface, applied to MCP HTTP calls.
Does not introduce a new config schema, new substitution token, or new dependency. Pure plugin addition + one fetch wrapper.
Out of scope (suggested follow-ups)
Forwarding inbound REST request headers (from POST /session/:id/message) into MCP calls. That's a separate concern (header allowlist + request-scoped context on the REST side) and can be layered on top of
this hook later by a plugin once the hook exists.
Happy to open a focused PR with the hook, the AsyncLocalStorage plumbing in session/prompt.ts, the fetch wrapper in mcp/index.ts, tests, docs, and generated SDK/types — if the core team confirms the hook name
and shape are acceptable.
Feature hasn't been suggested before.
Describe the enhancement you want to request
Summary
Add a plugin hook that lets plugins inject HTTP headers into outbound MCP tool calls, with the current
sessionID(andcallID,server,tool) available in scope. This enables per-session/per-requestheader forwarding (e.g.
X-Session-Id,X-User-Id) to remote MCP servers — something the existing staticheadersconfig and OAuth cannot express, because headers today are bound at transport constructiontime.
Current behavior
headers(packages/opencode/src/config/mcp.ts:41) are a staticRecord<string,string>resolved once at config load via{env:...}/{file:...}substitution.StreamableHTTPClientTransport/SSEClientTransportviarequestInit.headersat construction time (packages/opencode/src/mcp/index.ts:335,342). After construction thetransport is shared across all sessions, so headers cannot vary per call.
execute(args)closure atpackages/opencode/src/mcp/index.ts:168does not carry any session context, so even a per-call template like{session:id}would have nothing to resolve against.There is therefore no way today — via config, plugin, or otherwise — to attach the current
sessionID(or any other per-call value) as a header on outbound MCP HTTP requests.Proposed shape
A new plugin hook modeled on the existing
chat.headershook (packages/plugin/src/index.ts:256), but fired before each outbound MCP request:Plugin usage:
Proposed behavior
shared across sessions; only the fetch wrapper is per-call-aware.
wrapper-fetch.
Why this would help
Out of scope (suggested follow-ups)
this hook later by a plugin once the hook exists.
Notes
Happy to open a focused PR with the hook, the AsyncLocalStorage plumbing in session/prompt.ts, the fetch wrapper in mcp/index.ts, tests, docs, and generated SDK/types — if the core team confirms the hook name
and shape are acceptable.