diff --git a/docs/adapters/index.md b/docs/adapters/index.md index 30dd58e4..a4f0a7ab 100644 --- a/docs/adapters/index.md +++ b/docs/adapters/index.md @@ -6,7 +6,7 @@ outline: deep An adapter takes a `DevframeDefinition` and deploys it into a specific runtime — a standalone CLI, a Vite plugin, a static snapshot, an embedded host, or an MCP server. Each adapter ships at its own entry point (`devframe/adapters/`); the bundler pulls in only the ones you use. -Every adapter factory has the shape `createXxx(devframeDef, options?)`. Some adapters draw on an optional peer dependency, installed only when you opt into that adapter: `cac` pulls in [`cac`](https://github.com/cacjs/cac), and `mcp` pulls in [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk). +Every adapter factory has the shape `createXxx(devframeDef, options?)`. Some adapters draw on an optional peer dependency, installed only when you opt into that adapter: `cac` pulls in [`cac`](https://github.com/cacjs/cac), and `mcp` pulls in [`@modelcontextprotocol/server`](https://github.com/modelcontextprotocol/typescript-sdk). ## Comparison diff --git a/docs/adapters/mcp.md b/docs/adapters/mcp.md index fc58b07d..1772282f 100644 --- a/docs/adapters/mcp.md +++ b/docs/adapters/mcp.md @@ -16,7 +16,7 @@ import devframe from './devframe' await createMcpServer(devframe, { transport: 'stdio' }) ``` -`@modelcontextprotocol/sdk` is a peer dependency — install it when shipping MCP support. `createMcpServer` speaks the `stdio` transport, spawned per session by the client. +`@modelcontextprotocol/server` is a peer dependency — install it when shipping MCP support. `createMcpServer` speaks the `stdio` transport, spawned per session by the client. ## Route-based server diff --git a/docs/errors/DF0017.md b/docs/errors/DF0017.md index 49743e22..b49ad483 100644 --- a/docs/errors/DF0017.md +++ b/docs/errors/DF0017.md @@ -16,13 +16,13 @@ The agent-native surface is experimental and may change without a major version The MCP server failed while initializing. Common reasons: -- `@modelcontextprotocol/sdk` is not installed. This is a peer dependency — add it to your devtool's dependencies. +- `@modelcontextprotocol/server` is not installed. This is a peer dependency — add it to your devtool's dependencies. - The stdio transport threw during `connect()` (e.g. stdin/stdout is not available). - The route-based MCP server (`cli.mcp`) could not load its transport module — usually the missing SDK peer dependency. ## Fix -- **Missing SDK**: `pnpm add @modelcontextprotocol/sdk` (or npm/yarn equivalent) in the package that imports `devframe/adapters/mcp` or enables `cli.mcp`. +- **Missing SDK**: `pnpm add @modelcontextprotocol/server` (or npm/yarn equivalent) in the package that imports `devframe/adapters/mcp` or enables `cli.mcp`. - **Transport init failure**: check the underlying error (attached as `cause`) for specifics. ## Source diff --git a/docs/guide/agent-native.md b/docs/guide/agent-native.md index f1fc382c..f1646322 100644 --- a/docs/guide/agent-native.md +++ b/docs/guide/agent-native.md @@ -99,7 +99,7 @@ const devframe = defineDevframe({ /* … */ }) await createMcpServer(devframe, { transport: 'stdio' }) ``` -`@modelcontextprotocol/sdk` is a peer dependency — add it to your package when you want to ship an MCP-enabled devframe. +`@modelcontextprotocol/server` is a peer dependency — add it to your package when you want to ship an MCP-enabled devframe. ## Connecting Claude Desktop diff --git a/docs/guide/index.md b/docs/guide/index.md index 78ad0a37..83edbf67 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -40,7 +40,7 @@ Devframe keeps its surface focused on one tool, so the same definition stays por pnpm add devframe ``` -`devframe` ships ESM-only and has no Vite dependency. Adapters with optional peers (the MCP adapter needs `@modelcontextprotocol/sdk`) surface the requirement at import time. +`devframe` ships ESM-only and has no Vite dependency. Adapters with optional peers (the MCP adapter needs `@modelcontextprotocol/server`) surface the requirement at import time. ## Hello, Devframe diff --git a/packages/devframe/package.json b/packages/devframe/package.json index 0333afa4..eb98692a 100644 --- a/packages/devframe/package.json +++ b/packages/devframe/package.json @@ -70,11 +70,11 @@ "prepack": "pnpm build && mkdir -p ./skills && cp -r ../../skills/devframe ./skills/devframe" }, "peerDependencies": { - "@modelcontextprotocol/sdk": "^1.0.0", + "@modelcontextprotocol/server": "^2.0.0", "cac": "^7.0.0" }, "peerDependenciesMeta": { - "@modelcontextprotocol/sdk": { + "@modelcontextprotocol/server": { "optional": true }, "cac": { @@ -94,7 +94,8 @@ "valibot": "catalog:deps" }, "devDependencies": { - "@modelcontextprotocol/sdk": "catalog:deps", + "@modelcontextprotocol/client": "catalog:deps", + "@modelcontextprotocol/server": "catalog:deps", "cac": "catalog:deps", "get-port-please": "catalog:deps", "immer": "catalog:deps", diff --git a/packages/devframe/src/adapters/mcp/__tests__/mcp-http.test.ts b/packages/devframe/src/adapters/mcp/__tests__/mcp-http.test.ts index 46441f2b..1480a6af 100644 --- a/packages/devframe/src/adapters/mcp/__tests__/mcp-http.test.ts +++ b/packages/devframe/src/adapters/mcp/__tests__/mcp-http.test.ts @@ -1,7 +1,6 @@ import type { StartedServer } from '../../../node/server' import type { DevframeDefinition } from '../../../types/devframe' -import { Client } from '@modelcontextprotocol/sdk/client/index.js' -import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js' +import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client' import { afterEach, describe, expect, it } from 'vitest' import { createDevServer } from '../../dev' diff --git a/packages/devframe/src/adapters/mcp/__tests__/mcp-server.test.ts b/packages/devframe/src/adapters/mcp/__tests__/mcp-server.test.ts index c6751aaf..445f543e 100644 --- a/packages/devframe/src/adapters/mcp/__tests__/mcp-server.test.ts +++ b/packages/devframe/src/adapters/mcp/__tests__/mcp-server.test.ts @@ -1,6 +1,5 @@ import type { DevframeHost } from '../../../types/host' -import { Client } from '@modelcontextprotocol/sdk/client/index.js' -import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js' +import { Client, InMemoryTransport } from '@modelcontextprotocol/client' import { createHostContext } from 'devframe/node' import { describe, expect, it } from 'vitest' import { buildMcpServerFromContext } from '../build-server' diff --git a/packages/devframe/src/adapters/mcp/build-server.ts b/packages/devframe/src/adapters/mcp/build-server.ts index 5bb0ba4f..8a9dad9e 100644 --- a/packages/devframe/src/adapters/mcp/build-server.ts +++ b/packages/devframe/src/adapters/mcp/build-server.ts @@ -1,15 +1,10 @@ +import type { Tool } from '@modelcontextprotocol/server' import type { RpcFunctionDefinitionAnyWithContext } from 'devframe/rpc' import type { AgentTool, DevframeDefinition, DevframeHost, DevframeNodeContext } from 'devframe/types' import type { GenericSchema } from 'valibot' import { homedir } from 'node:os' import process from 'node:process' -import { Server } from '@modelcontextprotocol/sdk/server/index.js' -import { - CallToolRequestSchema, - ListResourcesRequestSchema, - ListToolsRequestSchema, - ReadResourceRequestSchema, -} from '@modelcontextprotocol/sdk/types.js' +import { Server } from '@modelcontextprotocol/server' import { createHostContext } from 'devframe/node' import { join } from 'pathe' import { diagnostics } from '../../node/diagnostics' @@ -152,12 +147,12 @@ export async function createMcpServer( } function registerToolHandlers(server: Server, ctx: DevframeNodeContext): void { - server.setRequestHandler(ListToolsRequestSchema, async () => { + server.setRequestHandler('tools/list', async () => { const tools = ctx.agent.list().tools.map(tool => projectTool(tool, ctx)) return { tools } }) - server.setRequestHandler(CallToolRequestSchema, async (request) => { + server.setRequestHandler('tools/call', async (request) => { const { name, arguments: args } = request.params try { const tool = ctx.agent.getTool(name) @@ -194,7 +189,7 @@ function registerResourceHandlers( ctx: DevframeNodeContext, exposeSharedState: boolean | ((key: string) => boolean), ): void { - server.setRequestHandler(ListResourcesRequestSchema, async () => { + server.setRequestHandler('resources/list', async () => { const resources = ctx.agent.list().resources.map(resource => ({ uri: resource.uri, name: resource.name, @@ -219,7 +214,7 @@ function registerResourceHandlers( return { resources } }) - server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + server.setRequestHandler('resources/read', async (request) => { const { uri } = request.params const parsed = parseResourceUri(uri) @@ -253,7 +248,7 @@ function registerResourceHandlers( }) } -function projectTool(tool: AgentTool, ctx: DevframeNodeContext): Record { +function projectTool(tool: AgentTool, ctx: DevframeNodeContext): Tool { const inputSchema = tool.inputSchema ?? computeInputSchema(tool, ctx) const outputSchema = tool.outputSchema ?? computeOutputSchema(tool, ctx) return { @@ -267,7 +262,7 @@ function projectTool(tool: AgentTool, ctx: DevframeNodeContext): Record=20'} + + '@modelcontextprotocol/core@2.0.0': + resolution: {integrity: sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==} + engines: {node: '>=20'} + '@modelcontextprotocol/sdk@1.30.0': resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} engines: {node: '>=18'} @@ -2660,6 +2674,10 @@ packages: '@cfworker/json-schema': optional: true + '@modelcontextprotocol/server@2.0.0': + resolution: {integrity: sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==} + engines: {node: '>=20'} + '@napi-rs/wasm-runtime@1.1.6': resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} peerDependencies: @@ -10317,6 +10335,7 @@ snapshots: '@hono/node-server@1.19.14(hono@4.12.18)': dependencies: hono: 4.12.18 + optional: true '@humanfs/core@0.19.2': dependencies: @@ -10565,6 +10584,20 @@ snapshots: dependencies: '@chevrotain/types': 11.1.2 + '@modelcontextprotocol/client@2.0.0': + dependencies: + '@modelcontextprotocol/core': 2.0.0 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.8 + jose: 6.2.3 + pkce-challenge: 5.0.1 + zod: 4.4.3 + + '@modelcontextprotocol/core@2.0.0': + dependencies: + zod: 4.4.3 + '@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@4.4.3)': dependencies: '@hono/node-server': 1.19.14(hono@4.12.18) @@ -10586,6 +10619,12 @@ snapshots: zod-to-json-schema: 3.25.2(zod@4.4.3) transitivePeerDependencies: - supports-color + optional: true + + '@modelcontextprotocol/server@2.0.0': + dependencies: + '@modelcontextprotocol/core': 2.0.0 + zod: 4.4.3 '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: @@ -13131,6 +13170,7 @@ snapshots: dependencies: mime-types: 3.0.2 negotiator: 1.0.0 + optional: true acorn-import-attributes@1.9.5(acorn@8.16.0): dependencies: @@ -13149,6 +13189,7 @@ snapshots: ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 + optional: true ajv@6.15.0: dependencies: @@ -13163,6 +13204,7 @@ snapshots: fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + optional: true alien-signals@3.2.1: {} @@ -13356,6 +13398,7 @@ snapshots: type-is: 2.0.1 transitivePeerDependencies: - supports-color + optional: true boolbase@1.0.0: {} @@ -13406,7 +13449,8 @@ snapshots: dependencies: run-applescript: 7.1.0 - bytes@3.1.2: {} + bytes@3.1.2: + optional: true c12@3.3.4(magicast@0.5.2): dependencies: @@ -13556,9 +13600,11 @@ snapshots: '@babel/parser': 7.29.7 '@babel/types': 7.29.7 - content-disposition@1.1.0: {} + content-disposition@1.1.0: + optional: true - content-type@1.0.5: {} + content-type@1.0.5: + optional: true convert-hrtime@5.0.0: {} @@ -13570,9 +13616,11 @@ snapshots: cookie-es@3.1.1: {} - cookie-signature@1.2.2: {} + cookie-signature@1.2.2: + optional: true - cookie@0.7.2: {} + cookie@0.7.2: + optional: true core-js-compat@3.49.0: dependencies: @@ -13584,6 +13632,7 @@ snapshots: dependencies: object-assign: 4.1.1 vary: 1.1.2 + optional: true cose-base@1.0.3: dependencies: @@ -14412,6 +14461,7 @@ snapshots: dependencies: express: 5.2.1(supports-color@10.2.2) ip-address: 10.2.0 + optional: true express@5.2.1(supports-color@10.2.2): dependencies: @@ -14445,6 +14495,7 @@ snapshots: vary: 1.1.2 transitivePeerDependencies: - supports-color + optional: true exsolve@1.1.0: {} @@ -14476,7 +14527,8 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.2: {} + fast-uri@3.1.2: + optional: true fast-wrap-ansi@0.2.0: dependencies: @@ -14514,6 +14566,7 @@ snapshots: statuses: 2.0.2 transitivePeerDependencies: - supports-color + optional: true find-up-simple@1.0.1: {} @@ -14555,7 +14608,8 @@ snapshots: format@0.2.2: {} - forwarded@0.2.0: {} + forwarded@0.2.0: + optional: true fraction.js@5.3.4: {} @@ -14746,7 +14800,8 @@ snapshots: dependencies: ansi-styles: 3.2.1 - hono@4.12.18: {} + hono@4.12.18: + optional: true hookable@5.5.3: {} @@ -14786,6 +14841,7 @@ snapshots: iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 + optional: true identifier-regex@1.1.0: dependencies: @@ -14853,9 +14909,11 @@ snapshots: transitivePeerDependencies: - supports-color - ip-address@10.2.0: {} + ip-address@10.2.0: + optional: true - ipaddr.js@1.9.1: {} + ipaddr.js@1.9.1: + optional: true iron-webcrypto@1.2.1: {} @@ -14908,7 +14966,8 @@ snapshots: is-promise@2.2.2: {} - is-promise@4.0.0: {} + is-promise@4.0.0: + optional: true is-reference@1.2.1: dependencies: @@ -14980,9 +15039,11 @@ snapshots: json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} + json-schema-traverse@1.0.0: + optional: true - json-schema-typed@8.0.2: {} + json-schema-typed@8.0.2: + optional: true json-stable-stringify-without-jsonify@1.0.1: {} @@ -15359,13 +15420,15 @@ snapshots: mdn-data@2.28.1: {} - media-typer@1.1.0: {} + media-typer@1.1.0: + optional: true merge-anything@5.1.7: dependencies: is-what: 4.1.16 - merge-descriptors@2.0.0: {} + merge-descriptors@2.0.0: + optional: true merge-stream@2.0.0: {} @@ -15669,7 +15732,8 @@ snapshots: natural-orderby@5.0.0: {} - negotiator@1.0.0: {} + negotiator@1.0.0: + optional: true next@16.2.12(@babel/core@7.29.0(supports-color@10.2.2))(@playwright/test@1.62.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: @@ -16004,7 +16068,8 @@ snapshots: object-identity@0.2.3: {} - object-inspect@1.13.4: {} + object-inspect@1.13.4: + optional: true obug@2.1.4: {} @@ -16027,6 +16092,7 @@ snapshots: once@1.4.0: dependencies: wrappy: 1.0.2 + optional: true onetime@6.0.0: dependencies: @@ -16270,7 +16336,8 @@ snapshots: lru-cache: 11.3.6 minipass: 7.1.3 - path-to-regexp@8.4.2: {} + path-to-regexp@8.4.2: + optional: true pathe@1.1.2: {} @@ -16530,6 +16597,7 @@ snapshots: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 + optional: true pug-attrs@3.0.0: dependencies: @@ -16603,6 +16671,7 @@ snapshots: qs@6.15.1: dependencies: side-channel: 1.1.0 + optional: true quansync@0.2.11: {} @@ -16622,6 +16691,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 unpipe: 1.0.0 + optional: true rc9@3.0.1: dependencies: @@ -16757,7 +16827,8 @@ snapshots: transitivePeerDependencies: - '@vue/composition-api' - require-from-string@2.0.2: {} + require-from-string@2.0.2: + optional: true reserved-identifiers@1.2.0: {} @@ -16915,6 +16986,7 @@ snapshots: path-to-regexp: 8.4.2 transitivePeerDependencies: - supports-color + optional: true run-applescript@7.1.0: {} @@ -17043,6 +17115,7 @@ snapshots: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 + optional: true side-channel-map@1.0.1: dependencies: @@ -17050,6 +17123,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 object-inspect: 1.13.4 + optional: true side-channel-weakmap@1.0.2: dependencies: @@ -17058,6 +17132,7 @@ snapshots: get-intrinsic: 1.3.0 object-inspect: 1.13.4 side-channel-map: 1.0.1 + optional: true side-channel@1.1.0: dependencies: @@ -17066,6 +17141,7 @@ snapshots: side-channel-list: 1.0.1 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + optional: true siginfo@2.0.0: {} @@ -17555,6 +17631,7 @@ snapshots: content-type: 1.0.5 media-typer: 1.1.0 mime-types: 3.0.2 + optional: true type-level-regexp@0.1.17: {} @@ -17713,7 +17790,8 @@ snapshots: transitivePeerDependencies: - vite - unpipe@1.0.0: {} + unpipe@1.0.0: + optional: true unplugin-utils@0.3.2: dependencies: @@ -17806,7 +17884,8 @@ snapshots: optionalDependencies: typescript: 6.0.3 - vary@1.1.2: {} + vary@1.1.2: + optional: true verkit@0.1.2: {} @@ -18226,7 +18305,8 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.2.0 - wrappy@1.0.2: {} + wrappy@1.0.2: + optional: true ws@8.21.1: {} @@ -18334,6 +18414,7 @@ snapshots: zod-to-json-schema@3.25.2(zod@4.4.3): dependencies: zod: 4.4.3 + optional: true zod@4.4.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c5d35479..b6b4fb75 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -57,7 +57,8 @@ catalogs: vite-plugin-solid: ^2.11.14 deps: '@json-render/core': ^0.19.0 - '@modelcontextprotocol/sdk': ^1.30.0 + '@modelcontextprotocol/client': ^2.0.0 + '@modelcontextprotocol/server': ^2.0.0 '@valibot/to-json-schema': ^1.7.1 birpc: ^4.0.0 cac: ^7.0.0 diff --git a/skills/devframe/SKILL.md b/skills/devframe/SKILL.md index fa844f1c..5bbc5c80 100644 --- a/skills/devframe/SKILL.md +++ b/skills/devframe/SKILL.md @@ -485,7 +485,7 @@ import { createMcpServer } from 'devframe/adapters/mcp' await createMcpServer(devframe, { transport: 'stdio' }) ``` -`@modelcontextprotocol/sdk` is a peer dependency. The CLI adapter also exposes `my-devframe mcp` — route host logs to stderr (stdout is the MCP transport). Safety classifications (`'read' | 'action' | 'destructive'`) drive MCP hint annotations that agent clients use to prompt for confirmation. +`@modelcontextprotocol/server` is a peer dependency. The CLI adapter also exposes `my-devframe mcp` — route host logs to stderr (stdout is the MCP transport). Safety classifications (`'read' | 'action' | 'destructive'`) drive MCP hint annotations that agent clients use to prompt for confirmation. ## Author SPA