Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mcp-sdk-2-4-cimd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"agents": patch
---

Update `@modelcontextprotocol/client` and `@modelcontextprotocol/server` to 2.4.0 and `@modelcontextprotocol/sdk` to 1.32.2, and add a `clientMetadataUrl` option to `DurableObjectOAuthClientProvider` for OAuth Client ID Metadata Documents. See [MCP client](https://developers.cloudflare.com/agents/model-context-protocol/apis/client-api/).
24 changes: 23 additions & 1 deletion docs/agents/mcp-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ available.
Install the exact MCP client peer used by this Agents release:

```sh
pnpm add agents @modelcontextprotocol/client@2.3.1
pnpm add agents @modelcontextprotocol/client@2.4.0
```

The MCP client does not need `@modelcontextprotocol/sdk` or `@modelcontextprotocol/server`. Those packages are optional peers used only by the MCP server APIs.
Expand Down Expand Up @@ -367,6 +367,28 @@ class MyAgent extends Agent {
}
```

#### Client ID Metadata Documents

Some authorization servers accept a [Client ID Metadata Document](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization#client-id-metadata-documents) instead of dynamic client registration. Pass `clientMetadataUrl` to use one. When a server advertises `client_id_metadata_document_supported`, the agent sends that URL as its `client_id`. Servers that don't advertise it still get dynamic client registration.

```typescript
import { Agent, DurableObjectOAuthClientProvider } from "agents";
import type { AgentMcpOAuthProvider } from "agents";

class MyAgent extends Agent {
createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {
return new DurableObjectOAuthClientProvider(
this.ctx.storage,
this.name,
callbackUrl,
{ clientMetadataUrl: "https://my-app.example.com/oauth/client.json" }
);
}
}
```

Serve the document at that URL. `provider.clientMetadataDocument` returns its JSON: `client_id` is the URL and `redirect_uris` holds the callback URL. The authorization server checks every redirect URI against the document, so pass a fixed `callbackPath` to `addMcpServer` rather than relying on the per-instance default.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 CIMD guide lacks a serving example

clientMetadataDocument produces JSON but installs no route. A Worker must serve it at the configured URL; otherwise authorization servers cannot fetch the document. A route example would make the integration reproducible.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.


## Using MCP Capabilities

Once connected, access the server's capabilities:
Expand Down
4 changes: 2 additions & 2 deletions docs/agents/mcp-servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Build an MCP server on Workers with `createMcpHandler` from `agents/mcp/server`
## Install

```sh
pnpm add agents @modelcontextprotocol/server@2.3.1 zod
pnpm add agents @modelcontextprotocol/server@2.4.0 zod
```

`@modelcontextprotocol/server` is an optional peer dependency of `agents`, so your package manager does not install it for you. Use the exact version required by your installed Agents release.
Expand Down Expand Up @@ -279,7 +279,7 @@ If the handler lifecycle does not fit, use the SDK's `WebStandardStreamableHTTPS
`McpAgent` is deprecated, but existing servers keep working. It is built on MCP SDK v1, which is an optional peer dependency of `agents`, so your package manager no longer installs it for you. Add the exact version your Agents release expects before you upgrade:

```sh
pnpm add agents @modelcontextprotocol/sdk@1.32.1 zod
pnpm add agents @modelcontextprotocol/sdk@1.32.2 zod
```

Keep importing `McpServer` from `@modelcontextprotocol/sdk/server/mcp.js` in an `McpAgent`. An SDK v2 server from `@modelcontextprotocol/server` cannot run inside `McpAgent`. The same applies to `WorkerTransport` and `createLegacyMcpHandler` from `agents/mcp`.
Expand Down
2 changes: 1 addition & 1 deletion examples/assistant/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@cloudflare/computer": "^0.8.0",
"@cloudflare/kumo": "^2.6.0",
"@cloudflare/think": "*",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@phosphor-icons/react": "^2.1.10",
"@streamdown/code": "^1.1.1",
"agents": "*",
Expand Down
2 changes: 1 addition & 1 deletion examples/codemode-connectors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@cloudflare/ai-chat": "*",
"@cloudflare/codemode": "*",
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@phosphor-icons/react": "^2.1.10",
"@streamdown/code": "^1.1.1",
"agents": "*",
Expand Down
4 changes: 2 additions & 2 deletions examples/codemode-mcp-openapi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
},
"dependencies": {
"@cloudflare/codemode": "*",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@modelcontextprotocol/server": "2.4.0",
"agents": "*"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions examples/codemode-mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
},
"dependencies": {
"@cloudflare/codemode": "*",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@modelcontextprotocol/server": "2.4.0",
"agents": "*",
"zod": "^4.6.7"
},
Expand Down
2 changes: 1 addition & 1 deletion examples/mcp-elicitation-mrtr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"types": "wrangler types env.d.ts --include-runtime false"
},
"dependencies": {
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/server": "2.4.0",
"agents": "*",
"zod": "^4.6.7"
},
Expand Down
2 changes: 1 addition & 1 deletion examples/mcp-elicitation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"type": "module",
"dependencies": {
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"agents": "*",
"zod": "^4.6.7"
}
Expand Down
2 changes: 1 addition & 1 deletion examples/mcp-rpc-transport/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"dependencies": {
"@cloudflare/ai-chat": "*",
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@phosphor-icons/react": "^2.1.10",
"agents": "*",
"ai": "^7.0.0",
Expand Down
2 changes: 1 addition & 1 deletion examples/mcp-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"types": "wrangler types env.d.ts --include-runtime false"
},
"dependencies": {
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/server": "2.4.0",
"zod": "^4.6.7"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions examples/mcp-worker-authenticated/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"dependencies": {
"@cloudflare/kumo": "^2.6.0",
"@cloudflare/workers-oauth-provider": "^1.2.4",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@modelcontextprotocol/server": "2.4.0",
"@phosphor-icons/react": "^2.1.10",
"agents": "*",
"hono": "^4.13.5",
Expand Down
4 changes: 2 additions & 2 deletions examples/mcp-worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
},
"dependencies": {
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@modelcontextprotocol/server": "2.4.0",
"@phosphor-icons/react": "^2.1.10",
"agents": "*",
"react": "^19.2.7",
Expand Down
2 changes: 1 addition & 1 deletion examples/mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@phosphor-icons/react": "^2.1.10",
"agents": "*",
"react": "^19.2.7",
Expand Down
2 changes: 1 addition & 1 deletion examples/next/mcp-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"dependencies": {
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/client": "2.3.1",
"@modelcontextprotocol/client": "2.4.0",
"@phosphor-icons/react": "^2.1.10",
"agents": "*",
"react": "^19.2.7",
Expand Down
4 changes: 2 additions & 2 deletions examples/playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"@cloudflare/ai-chat": "*",
"@cloudflare/codemode": "*",
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@modelcontextprotocol/server": "2.4.0",
"@phosphor-icons/react": "^2.1.10",
"@streamdown/code": "^1.1.1",
"agents": "*",
Expand Down
2 changes: 1 addition & 1 deletion examples/webmcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@phosphor-icons/react": "^2.1.10",
"agents": "*",
"zod": "^4.6.7"
Expand Down
2 changes: 1 addition & 1 deletion examples/x402-mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
},
"dependencies": {
"@cloudflare/kumo": "^2.6.0",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@phosphor-icons/react": "^2.1.10",
"@x402/evm": "^2.17.0",
"agents": "*",
Expand Down
4 changes: 2 additions & 2 deletions openai-sdk/chess-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
},
"dependencies": {
"@cloudflare/vite-plugin": "1.62.3",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/server": "2.3.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@modelcontextprotocol/server": "2.4.0",
"@vitejs/plugin-react": "^6.0.3",
"agents": "*",
"chess.js": "^1.4.0",
Expand Down
2 changes: 1 addition & 1 deletion openai-sdk/pizzaz/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"start": "wrangler dev"
},
"dependencies": {
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"agents": "*",
"zod": "^4.6.7"
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"@cloudflare/vite-plugin": "1.62.3",
"@cloudflare/vitest-pool-workers": "^0.19.1",
"@cloudflare/workers-types": "^5.20261014.1",
"@modelcontextprotocol/sdk": "1.32.1",
"@modelcontextprotocol/sdk": "1.32.2",
"@openai/agents": "^0.12.0",
"@openai/agents-extensions": "^0.12.0",
"@phosphor-icons/react": "^2.1.10",
Expand Down
4 changes: 2 additions & 2 deletions packages/agents/conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ the current protocol lane.

| Command | Server protocol/referee selection | Scenarios | Current result |
| ------------------------------------ | --------------------------------- | --------- | ------------------------------ |
| `test:conformance:client:stateless` | `2026-07-28` | 33 | 30 clean / 3 expected failures |
| `test:conformance:client:2025-11-25` | `2025-11-25` | 19 | 17 clean / 2 expected failures |
| `test:conformance:client:stateless` | `2026-07-28` | 33 | 31 clean / 2 expected failures |
| `test:conformance:client:2025-11-25` | `2025-11-25` | 19 | 18 clean / 1 expected failure |
| `test:conformance:client:2025-06-18` | `2025-06-18` | 5 | 5 clean |
| `test:conformance:client:2025-03-26` | `2025-03-26` OAuth/backcompat | 2 | 2 clean |

Expand Down
9 changes: 2 additions & 7 deletions packages/agents/conformance/baseline-client-2025-11-25.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# SDK v2 client against 2025-11-25 stateful servers.
client:
# SHOULD-level only: the built-in provider uses Dynamic Client Registration
# instead of a URL-based Client ID Metadata Document.
# Impact if unchanged: servers that require CIMD rather than DCR need a
# custom OAuth provider.
- auth/basic-cimd

# The default scope step-up budget produces four authorization attempts;
# the referee's SHOULD-level limit is three or fewer.
# the referee's SHOULD-level limit is three or fewer. Fixed by the
# step-up round limit in cloudflare/agents#2663; remove this entry with it.
# Impact if unchanged: a permanently unsatisfiable insufficient_scope
# challenge can send the user through one additional OAuth round-trip before
# the client stops retrying.
Expand Down
18 changes: 7 additions & 11 deletions packages/agents/conformance/baseline-client-2026-07-28.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
# SDK v2 client against the latest published conformance protocol revision.
# Every entry is executed by alpha.12; run-suite.mjs rejects unseen entries.
client:
# SHOULD-level only: the built-in provider uses Dynamic Client Registration
# instead of a URL-based Client ID Metadata Document.
# Impact if unchanged: servers that require CIMD rather than DCR need a
# custom OAuth provider.
- auth/basic-cimd

# The default scope step-up budget produces four authorization attempts;
# the referee's SHOULD-level limit is three or fewer.
# the referee's SHOULD-level limit is three or fewer. Fixed by the
# step-up round limit in cloudflare/agents#2663; remove this entry with it.
# Impact if unchanged: a permanently unsatisfiable insufficient_scope
# challenge can send the user through one additional OAuth round-trip before
# the client stops retrying.
- auth/scope-retry-limit

# Alpha.12 omits resultType after negotiating 2026-07-28. The final draft
# requires servers implementing that revision to include it; the
# absent-means-complete bridge applies only to earlier revisions. All five
# MRTR wire assertions pass before the fixture's invalid final result.
# Referee bug (modelcontextprotocol/conformance#475): test_mrtr_no_result_type
# omits resultType after negotiating 2026-07-28. The released spec
# (basic/index, ResultType) requires 2026-07-28 servers to include it and
# limits absent-means-complete to earlier-revision servers, so the SDK v2
# client rejects the result. All five MRTR wire checks pass first.
# Impact if unchanged: none for conforming 2026-07-28 servers.
- sep-2322-client-request-state
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# SDK v2 handler's explicit Legacy compatibility path.
# SDK v2 handler's explicit Legacy compatibility path (deprecated).
# These need a server-to-client channel or a durable event stream, which a
# stateless request does not have; they are kept rather than fixed.
# All 33 scenarios execute; this is not the alpha harness's smaller `active`
# subset. Complete sessionful compatibility is tested in the legacy lanes.
server:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# createLegacyMcpHandler + WorkerTransport at 2025-11-25.
# Deprecated surface: these stay baselined rather than fixed. createMcpHandler
# passes all three at 2026-07-28 (server-handler lane).
server:
# SDK v1's Zod conversion emits draft-07 and strips JSON Schema 2020-12
# $defs/additionalProperties fields.
Expand Down
2 changes: 2 additions & 0 deletions packages/agents/conformance/baseline-server-mcp-agent.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Retained SDK v1 McpAgent endpoint at 2025-11-25.
# Deprecated surface: these stay baselined rather than fixed. createMcpHandler
# passes all three at 2026-07-28 (server-handler lane).
server:
# SDK v1's Zod conversion emits draft-07 and strips JSON Schema 2020-12
# $defs/additionalProperties fields.
Expand Down
2 changes: 1 addition & 1 deletion packages/agents/conformance/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ case "$MODE" in
;;
server-handler-legacy)
run_server "$WORKER_ORIGIN/mcp-handler-legacy" 2025-11-25 \
conformance/baseline-server-handler.yml "$@"
conformance/baseline-server-handler-legacy.yml "$@"
;;
server-mcp-agent)
run_server "$WORKER_ORIGIN/mcp-agent" 2025-11-25 \
Expand Down
10 changes: 6 additions & 4 deletions packages/agents/conformance/vendor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
v2 conformance fixture:

- repository: `https://github.com/modelcontextprotocol/typescript-sdk`
- package tag: `@modelcontextprotocol/server@2.3.1`
- commit: `fcef852f6cdafea07f36cf6fae69b37c8adf85be`
- package tag: `@modelcontextprotocol/server@2.4.0`
- commit: `951fe5603a7ec0b2dcb6a0b95d92cd86f93ad9e5`
- source: `test/conformance/src/everythingServer.ts`
- source SHA-256: `2442aebdd2f97995ff60c80ee8688603323b7c33cb9ac07ba87f47771ac5d119`
- source SHA-256: `1ec5c8e22fc4a9daf37d6b34ee692c6ec4d097f314fcde4d7f26d241fdbbc408`

The local fixture keeps the upstream registrations while removing the
Node/Express entrypoint, Node transports, session registry, and Node event
store. It exports one factory for the Agents workerd conformance worker and uses
Web Crypto for request-state integrity. The scope-challenge registrations are
kept, but the upstream entrypoint's middleware that stamps `AuthInfo` from fixed
bearer tokens is not, so those checks always pass here.
bearer tokens is not, so those checks always pass here. The SEP-2640 skills
catalog (`conformanceSkills.attach`, added in 2.4.0) is also left out: skills
are an extension, and the core lanes never select extension scenarios.

When updating the SDK pin, fetch the source at the recorded commit, verify its
SHA-256, inspect a no-index diff against this file, and port only registration
Expand Down
19 changes: 19 additions & 0 deletions packages/agents/conformance/worker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
Agent,
type AgentMcpOAuthProvider,
type AgentNamespace,
DurableObjectOAuthClientProvider,
getAgentByName,
routeAgentRequest
} from "../src/index.ts";
Expand Down Expand Up @@ -47,6 +49,10 @@ type Env = {

const SERVER_NAME = "conformance";

// Fixed client_id the referee's auth/basic-cimd scenario expects.
const CIMD_CLIENT_METADATA_URL =
"https://conformance-test.local/client-metadata.json";

type RunRequest = { scenario: string; serverUrl: string; context?: string };

type RunResult =
Expand All @@ -59,6 +65,19 @@ export class ConformanceHost extends Agent<Env> {
private _scenario: string | undefined;
private _mrtrIsolationCallMade = false;

// Offer a Client ID Metadata Document URL. Authorization servers that
// advertise CIMD support receive it as the client_id; the rest still use
// dynamic client registration. The referee accepts this fixed URL without
// fetching it.
createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {
return new DurableObjectOAuthClientProvider(
this.ctx.storage,
this.name,
callbackUrl,
{ clientMetadataUrl: CIMD_CLIENT_METADATA_URL }
);
}

onStart() {
// Accept elicitation requests. Form-mode defaults are applied by the SDK
// client because the connection advertises `form.applyDefaults` (SEP-1034).
Expand Down
Loading
Loading