Skip to content
Open
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
2 changes: 1 addition & 1 deletion docs/adapters/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<name>`); 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

Expand Down
2 changes: 1 addition & 1 deletion docs/adapters/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions docs/errors/DF0017.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/agent-native.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 4 additions & 3 deletions packages/devframe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -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'

Expand Down
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
21 changes: 8 additions & 13 deletions packages/devframe/src/adapters/mcp/build-server.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -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)

Expand Down Expand Up @@ -253,7 +248,7 @@ function registerResourceHandlers(
})
}

function projectTool(tool: AgentTool, ctx: DevframeNodeContext): Record<string, unknown> {
function projectTool(tool: AgentTool, ctx: DevframeNodeContext): Tool {
const inputSchema = tool.inputSchema ?? computeInputSchema(tool, ctx)
const outputSchema = tool.outputSchema ?? computeOutputSchema(tool, ctx)
return {
Expand All @@ -267,7 +262,7 @@ function projectTool(tool: AgentTool, ctx: DevframeNodeContext): Record<string,
readOnlyHint: tool.safety === 'read',
destructiveHint: tool.safety === 'destructive',
},
}
} as Tool
}

function computeInputSchema(tool: AgentTool, ctx: DevframeNodeContext): unknown {
Expand Down
3 changes: 1 addition & 2 deletions packages/devframe/src/adapters/mcp/http.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { DevframeNodeContext } from 'devframe/types'
import type { H3, H3Event } from 'h3'
import { randomUUID } from 'node:crypto'
import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js'
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js'
import { isInitializeRequest, WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server'
import { isAllowedOrigin } from 'devframe/rpc/transports/ws-server'
import { defineHandler } from 'h3'
import { buildMcpServerFromContext } from './build-server'
Expand Down
2 changes: 1 addition & 1 deletion packages/devframe/src/adapters/mcp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// import { createMcpServer } from 'devframe/adapters/mcp'
// await createMcpServer(definition, { transport: 'stdio' })
//
// Requires `@modelcontextprotocol/sdk` to be installed as a peer
// Requires `@modelcontextprotocol/server` to be installed as a peer
// dependency. Importing this entry without the SDK throws at load time
// with the usual Node module-not-found error.
//
Expand Down
4 changes: 2 additions & 2 deletions packages/devframe/src/adapters/mcp/transports.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import type { Server } from '@modelcontextprotocol/server'
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio'

/**
* Start the MCP server on stdio. Returns a stop function.
Expand Down
3 changes: 1 addition & 2 deletions packages/devframe/src/helpers/__tests__/vite.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
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 { getPort } from 'get-port-please'
import { afterEach, describe, expect, it } from 'vitest'
import { viteDevBridge } from '../vite'
Expand Down
Loading
Loading