Skip to content

Commit 7a51e65

Browse files
agents-git-bot[bot]github-actions[bot]claudeopencode-agent[bot]elithrar
authored
Fix MCP OAuth callback URL leaking instance name (#28183)
* Document callbackPath option for MCP OAuth callback security Add documentation for the new callbackPath parameter in addMcpServer() that allows custom OAuth callback URL paths. This is required when sendIdentityOnConnect is false to prevent instance name leakage. Changes: - Add callbackPath parameter to addMcpServer() API reference - Add security section explaining when and why callbackPath is required - Include example showing how to route custom callback paths with getAgentByName - Note that callback matching uses state parameter, not URL path Relates to cloudflare/agents#868 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> * Fix export and await in code example Co-authored-by: elithrar <elithrar@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: elithrar <elithrar@users.noreply.github.com>
1 parent 698ad8c commit 7a51e65

1 file changed

Lines changed: 64 additions & 1 deletion

File tree

src/content/docs/agents/model-context-protocol/mcp-client-api.mdx

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,67 @@ For example: `https://my-worker.workers.dev/agents/my-agent/default/callback`
190190

191191
OAuth tokens are securely stored in SQLite, and persist across agent restarts.
192192

193+
### Protecting instance names in OAuth callbacks
194+
195+
When using `sendIdentityOnConnect: false` to hide sensitive instance names (like session IDs or user IDs), the default OAuth callback URL would expose the instance name. To prevent this security issue, you must provide a custom `callbackPath`.
196+
197+
<TypeScriptExample>
198+
199+
```ts
200+
import { Agent, routeAgentRequest, getAgentByName } from "agents";
201+
202+
export class SecureAgent extends Agent {
203+
static options = { sendIdentityOnConnect: false };
204+
205+
async onRequest(request: Request) {
206+
// callbackPath is required when sendIdentityOnConnect is false
207+
const result = await this.addMcpServer(
208+
"github",
209+
"https://mcp.github.com/mcp",
210+
{
211+
callbackPath: "mcp-oauth-callback", // Custom path without instance name
212+
},
213+
);
214+
215+
if (result.state === "authenticating") {
216+
return Response.redirect(result.authUrl);
217+
}
218+
219+
return new Response("Connected!");
220+
}
221+
}
222+
223+
// Route the custom callback path to the agent
224+
export default {
225+
async fetch(request: Request, env: Env) {
226+
const url = new URL(request.url);
227+
228+
// Route custom MCP OAuth callback to agent instance
229+
if (url.pathname.startsWith("/mcp-oauth-callback")) {
230+
// Implement this to extract the instance name from your session/auth mechanism
231+
const instanceName = await getInstanceNameFromSession(request);
232+
233+
const agent = await getAgentByName(env.SecureAgent, instanceName);
234+
return agent.fetch(request);
235+
}
236+
237+
// Standard agent routing
238+
return (
239+
(await routeAgentRequest(request, env)) ??
240+
new Response("Not found", { status: 404 })
241+
);
242+
},
243+
};
244+
```
245+
246+
</TypeScriptExample>
247+
248+
:::note[How callback matching works]
249+
250+
OAuth callbacks are matched by the `state` query parameter (format: `{serverId}:{stateValue}`), not by URL path. This means your custom `callbackPath` can be any path you choose, as long as requests to that path are routed to the correct agent instance.
251+
252+
:::
253+
193254
### Custom OAuth callback handling
194255

195256
Configure how OAuth completion is handled. By default, successful authentication redirects to your application origin, while failed authentication displays an HTML error page.
@@ -419,6 +480,7 @@ async addMcpServer(
419480
url: string,
420481
options?: {
421482
callbackHost?: string;
483+
callbackPath?: string;
422484
agentsPrefix?: string;
423485
client?: ClientOptions;
424486
transport?: {
@@ -438,7 +500,8 @@ async addMcpServer(
438500
- `url` (string, required) — URL of the MCP server endpoint
439501
- `options` (object, optional) — Connection configuration:
440502
- `callbackHost` — Host for OAuth callback URL. If omitted, automatically derived from the incoming request
441-
- `agentsPrefix` — URL prefix for OAuth callback path. Default: `"agents"`
503+
- `callbackPath` — Custom callback URL path that bypasses the default `/agents/{class}/{name}/callback` construction. **Required when `sendIdentityOnConnect` is `false`** to prevent leaking the instance name. When set, the callback URL becomes `{callbackHost}/{callbackPath}`. You must route this path to the agent instance via `getAgentByName`
504+
- `agentsPrefix` — URL prefix for OAuth callback path. Default: `"agents"`. Ignored when `callbackPath` is provided
442505
- `client` — MCP client configuration options (passed to `@modelcontextprotocol/sdk` Client constructor). By default, includes `CfWorkerJsonSchemaValidator` for validating tool parameters against JSON schemas
443506
- `transport` — Transport layer configuration:
444507
- `headers` — Custom HTTP headers for authentication

0 commit comments

Comments
 (0)