Skip to content

Commit d85cd90

Browse files
committed
feat!: move the MCP implementation into the optional @devframes/agentic peer
The MCP implementation, the connect gateway, and the MCP SDK behind them move out of devframe into the new @devframes/agentic package, an optional peer of devframe and @devframes/hub. devframe stays slim; installing the peer is what turns the agent surface on. Users never import agentic: devframe/adapters/mcp stays the user-facing API and loads the peer lazily. - @devframes/agentic ships /mcp and /connect entries consumed by devframe's loaders; the bare root throws. Signatures are typed against devframe's own contract, so no SDK type leaks and the SDK stays swappable. - The mcp enable matrix: 'auto' mounts iff the agent surface is non-empty AND the peer resolves (missing peer: one DF0078 warning per process); an explicit setting - or importing devframe/adapters/mcp - throws DF0079 without the peer; false stays silent. - devframe/adapters/mcp keeps its exports unchanged, built in its own graph so its top-level await cannot reshape the server chunking. - The peer probe routes through resolveServicePackage (an opaque-parameter createRequire), not a literal createRequire(import.meta.url).resolve, which turbopack rewrites into a throwing stub inside a bundled Next hub. - Pure agent projections (to-json-schema, stringify) stay in devframe under src/agent/, shared by browser WebMCP and agentic via devframe/internal. - devframe drops @modelcontextprotocol/server (dep) and /client (optional peer); DF0046 now points at @devframes/agentic. The reference hubs install the peer, as any consumer wanting MCP now does.
1 parent 582920e commit d85cd90

68 files changed

Lines changed: 943 additions & 373 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

alias.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ export const alias = {
4747
'devframe/adapters/build': r('devframe/src/adapters/build.ts'),
4848
'devframe/adapters/embedded': r('devframe/src/adapters/embedded.ts'),
4949
'devframe/initiate': r('devframe/src/adapters/initiate.ts'),
50-
'devframe/adapters/mcp': r('devframe/src/adapters/mcp/index.ts'),
50+
'devframe/adapters/mcp': r('devframe/src/adapters/mcp.ts'),
51+
'@devframes/agentic/mcp': r('agentic/src/mcp/index.ts'),
52+
'@devframes/agentic/connect': r('agentic/src/connect/index.ts'),
53+
'@devframes/agentic': r('agentic/src/index.ts'),
5154
'@devframes/hub/build': r('hub/src/node/build.ts'),
5255
'@devframes/hub/client': r('hub/src/client/index.ts'),
5356
'@devframes/hub/constants': r('hub/src/constants.ts'),

docs/content/1.guide/15.agent-native.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ Every `ctx.rpc.sharedState` key is exposed as a `devframe://state/<key>` resourc
100100

101101
## Starting the MCP server
102102

103-
The dev server serves the agent surface over HTTP on its own: the `mcp: 'auto'` default mounts the route at `/__mcp` once anything above exists (an `agent`-flagged RPC, a registered tool or resource) - one flagged function is the whole setup. See the [MCP adapter](/adapters/mcp#route-based-server) for forcing it on or off and hardening the route.
103+
The dev server serves the agent surface over HTTP on its own: the `mcp: 'auto'` default mounts the route at `/__mcp` once anything above exists (an `agent`-flagged RPC, a registered tool or resource) and the optional [`@devframes/agentic`](/adapters/mcp) peer is installed - one flagged function plus one install is the whole setup. See the [MCP adapter](/adapters/mcp#route-based-server) for forcing it on or off and hardening the route.
104104

105105
For a stdio server instead, via the CLI:
106106

docs/content/2.adapters/7.mcp.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,24 @@ description: 'Exposes a devframe''s agent-facing API as a Model Context Protocol
77

88
Exposes a devframe's agent-facing API as a [Model Context Protocol](https://modelcontextprotocol.io) server: coding agents call flagged RPCs and read resources.
99

10+
The implementation (and the MCP SDK behind it) lives in **`@devframes/agentic`**, an optional peer of `devframe`: install it to enable the agent surface, and keep importing everything from `devframe/adapters/mcp` - the peer is loaded for you, never imported directly. A devframe without an agent surface ships with neither the peer nor the SDK installed:
11+
12+
```sh
13+
npm install @devframes/agentic
14+
```
15+
1016
```ts
1117
import { createMcpServer } from 'devframe/adapters/mcp'
1218
import myDevframe from './my-tool'
1319

1420
await createMcpServer(myDevframe, { transport: 'stdio' })
1521
```
1622

17-
`createMcpServer` serves `stdio` through the MCP SDK's `serveStdio`, pinning one server instance per connection.
23+
`createMcpServer` serves `stdio` through the MCP SDK's `serveStdio`, pinning one server instance per connection. Importing `devframe/adapters/mcp` without the peer installed throws [DF0079](/errors/DF0079).
1824

1925
## Route-based server
2026

21-
The dev server exposes the same MCP API over HTTP, live. The default setting is **`'auto'`**: the route mounts once the devframe exposes an agent surface (an `agent`-flagged RPC, a registered tool or resource) - flag your first function and the agent view is on. A devframe with nothing flagged mounts no route and loads no MCP code.
27+
The dev server exposes the same MCP API over HTTP, live. The default setting is **`'auto'`**: the route mounts once the devframe exposes an agent surface (an `agent`-flagged RPC, a registered tool or resource) *and* `@devframes/agentic` is installed - flag your first function, install the peer, and the agent view is on. A devframe with nothing flagged mounts no route and loads no MCP code; an agent surface without the peer warns once ([DF0078](/errors/DF0078)) and mounts nothing, while an explicit `mcp` setting without the peer throws ([DF0079](/errors/DF0079)). `mcp: false` stays silent either way.
2228

2329
Pin the behavior where you host the tool - it's a hosting decision, so pass `mcp` to `createCac` when you assemble the CLI (or to `createDevServer` / `initDevframe` / `initHub` when you host it programmatically): `true` always mounts, `false` never mounts, an object customises the route:
2430

@@ -103,6 +109,8 @@ Two gateway tools (`devframe:connect:*` ids; see [tool ids and wire names](/guid
103109

104110
Discovery reads the **instance registry**: every `createDevServer` writes `~/.devframe/instances/<pid>-<port>.json`, dialed with a loopback origin. In-process host frameworks register via `registerDevframeInstance` (`devframe/node`). `--port <n>` probes a port; `DEVFRAME_INSTANCES_DIR` relocates the registry, `DEVFRAME_DISABLE_INSTANCE_REGISTRY=1` opts out.
105111

106-
Most instances trust same-machine callers, so the connector reaches them with no credential. For an instance you *hardened* with a bearer, the connector reads `DEVFRAME_MCP_AUTH_TOKEN` and presents it (never a CLI flag, since command-line arguments are visible to other processes). Connect to a fleet with distinct credentials by driving `startConnectServer` with a per-instance `authToken` resolver.
112+
The connector needs the same optional `@devframes/agentic` peer as the adapter; `devframe connect` without it throws [DF0046](/errors/DF0046).
113+
114+
Most instances trust same-machine callers, so the connector reaches them with no credential. For an instance you *hardened* with a bearer, the connector reads `DEVFRAME_MCP_AUTH_TOKEN` and presents it (never a CLI flag, since command-line arguments are visible to other processes).
107115

108116
See [Agent-Native](/guide/agent-native) for the API and safety model.

docs/content/6.errors/DF0046.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
---
2-
title: 'DF0046: Connector Requires the MCP SDK'
3-
description: 'devframe connect requires the optional peer dependency @modelcontextprotocol/client: {reason}'
2+
title: 'DF0046: Connector Requires @devframes/agentic'
3+
description: 'devframe connect requires the optional peer dependency @devframes/agentic: {reason}'
44
---
55

66
## Message
77

8-
> `devframe connect` requires the optional peer dependency @modelcontextprotocol/client: `{reason}`
8+
> `devframe connect` requires the optional peer dependency @devframes/agentic: `{reason}`
99
1010
## Cause
1111

12-
`devframe connect` was started but `@modelcontextprotocol/client` could not be imported. The client SDK is an optional peer dependency of `devframe`: only the connector dials other instances, so only it needs the package installed.
12+
`devframe connect` was started but `@devframes/agentic/connect` could not be imported. The connector lives in `@devframes/agentic` (together with the MCP SDK), an optional peer dependency of `devframe`: only agent-facing features need the package installed.
1313

1414
## Fix
1515

16-
Install the SDK next to devframe and run the connector again:
16+
Install the package next to devframe and run the connector again:
1717

1818
```sh
19-
npm install @modelcontextprotocol/client
19+
npm install @devframes/agentic
2020
devframe connect
2121
```
2222

2323
## Source
2424

25-
- [`packages/devframe/src/cli/connect.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/connect.ts): `startConnectServer()` throws this when the dynamic SDK import fails.
25+
- [`packages/devframe/src/cli/main.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/cli/main.ts): the `connect` subcommand throws this when the dynamic `@devframes/agentic/connect` import fails.

docs/content/6.errors/DF0078.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
title: 'DF0078: Agent Surface Without @devframes/agentic'
3+
description: 'This devframe exposes agent tools, but the MCP endpoint stays off: the optional peer "@devframes/agentic" is not installed.'
4+
---
5+
6+
## Message
7+
8+
> This devframe exposes agent tools, but the MCP endpoint stays off: the optional peer "@devframes/agentic" is not installed.
9+
10+
## Cause
11+
12+
The devframe (or hub) left a non-empty agent surface (RPC functions with an `agent` field, registered agent tools, resources, or providers) and the `mcp` setting is the omitted `'auto'` default, which would mount the MCP route. But `@devframes/agentic`, the optional peer carrying the MCP adapter and the MCP SDK, is not installed, so no route can be served.
13+
14+
The warning is reported once per process; the instance keeps running without an MCP endpoint.
15+
16+
## Fix
17+
18+
Install the peer so the agent surface is served over MCP:
19+
20+
```sh
21+
npm install @devframes/agentic
22+
```
23+
24+
Or, if the tools should deliberately stay unexposed, set `mcp: false` to opt out silently.
25+
26+
## Source
27+
28+
- [`packages/devframe/src/adapters/_shared.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/adapters/_shared.ts): `loadAutoMcpAdapter()` reports this (once) when the agent surface is non-empty but the peer probe fails.

docs/content/6.errors/DF0079.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title: 'DF0079: MCP Enabled Without @devframes/agentic'
3+
description: 'The mcp option is enabled, but the optional peer "@devframes/agentic" could not be loaded: {reason}'
4+
---
5+
6+
## Message
7+
8+
> The `mcp` option is enabled, but the optional peer "@devframes/agentic" could not be loaded: `{reason}`
9+
10+
## Cause
11+
12+
An explicit `mcp` setting (`true`, a route options object, the `--mcp` flag, or the `mcp` CLI subcommand) asked for an MCP surface - or `devframe/adapters/mcp` was imported directly - but the implementation could not be loaded from the optional `@devframes/agentic` peer, typically because it is not installed. Unlike the omitted `'auto'` default (which degrades to a one-time [DF0078](/errors/DF0078) warning), an explicit opt-in fails fast rather than silently running without MCP.
13+
14+
## Fix
15+
16+
Install the peer next to devframe:
17+
18+
```sh
19+
npm install @devframes/agentic
20+
```
21+
22+
Or remove the explicit `mcp` setting (or pass `mcp: false`) if the endpoint isn't wanted. The underlying import error is attached as `cause`.
23+
24+
## Source
25+
26+
- [`packages/devframe/src/node/agentic.ts`](https://github.com/devframes/devframe/blob/main/packages/devframe/src/node/agentic.ts): `importAgenticMcp()` maps a failed load of `@devframes/agentic/mcp` to this error.

docs/content/6.errors/index.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Emitted by `devframe`: the framework-neutral host, RPC, streaming, assets, servi
5454
| [DF0043](/errors/DF0043) | error | Invalid RPC Argument |
5555
| [DF0044](/errors/DF0044) | error | Invalid RPC Return Value |
5656
| [DF0045](/errors/DF0045) | warn | Instance Registry Update Failed |
57-
| [DF0046](/errors/DF0046) | error | Connector Requires the MCP SDK |
57+
| [DF0046](/errors/DF0046) | error | Connector Requires @devframes/agentic |
5858
| [DF0047](/errors/DF0047) | warn | Agent Tool Wire-Name Collision |
5959
| [DF0048](/errors/DF0048) | error | Unknown Shared-State Key |
6060
| [DF0049](/errors/DF0049) | error | Connector Call Requires Port and Tool |
@@ -84,6 +84,8 @@ Emitted by `devframe`: the framework-neutral host, RPC, streaming, assets, servi
8484
| [DF0075](/errors/DF0075) | warn | No RPC Transport On This Runtime |
8585
| [DF0076](/errors/DF0076) | error | WebSocket Upgrade Unsupported On This Runtime |
8686
| [DF0077](/errors/DF0077) | error | In-Page Channel Function Not Registered |
87+
| [DF0078](/errors/DF0078) | warn | Agent Surface Without @devframes/agentic |
88+
| [DF0079](/errors/DF0079) | error | MCP Enabled Without @devframes/agentic |
8789

8890
## Hub: context & lifecycle (DF80xx)
8991

docs/content/7.migrations/1.migration-0.9.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ description: '0.9 removes the compatibility shims deprecated across the 0.7 seri
55

66
0.9 removes the compatibility shims deprecated across the 0.7 series and trims the public API of `devframe` and `@devframes/hub`. Each change has a drop-in replacement. It also moves the [MCP](/adapters/mcp) surface to the stateless [MCP 2026-07-28 protocol](https://modelcontextprotocol.io/specification/2026-07-28). The devframe API is unchanged; see [The MCP endpoints are stateless](#the-mcp-endpoints-are-stateless).
77

8+
Late in the 0.9 series the MCP implementation moved into the new optional peer `@devframes/agentic`; see [MCP requires `@devframes/agentic`](#mcp-requires-devframesagentic).
9+
10+
## MCP requires `@devframes/agentic`
11+
12+
The MCP implementation and the MCP SDK moved out of `devframe` into `@devframes/agentic`, an **optional peer**: install it to serve agent tools over MCP, skip it for a slimmer install without an MCP surface. Your imports do not change - `devframe/adapters/mcp` stays the user-facing API and loads the peer for you; `@devframes/agentic` is never imported directly.
13+
14+
> [!WARNING]
15+
> This is a behavior change within the 0.9 series: `devframe` no longer depends on the MCP SDK, so MCP now requires `@devframes/agentic` to be installed. Without it, the omitted `'auto'` default warns once ([DF0078](/errors/DF0078)) and mounts nothing; an explicit `mcp` setting - and importing `devframe/adapters/mcp` itself - throws ([DF0079](/errors/DF0079)); `mcp: false` stays silent.
16+
17+
```sh
18+
npm install @devframes/agentic
19+
```
20+
21+
The `devframe/adapters/mcp` exports are unchanged: `createMcpServer`, `createMcpFetchHandler`, `mountMcpHttp`, and their option types (the types are also importable from `devframe/types`). `devframe connect` needs the peer too and throws [DF0046](/errors/DF0046) without it, replacing the former `@modelcontextprotocol/client` optional peer.
22+
823
## `devframe/adapters/cli` is removed
924

1025
The `devframe/adapters/cli` entry is gone; import from `devframe/adapters/cac`:

examples/custom-hub-next/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"dependencies": {
1414
"@antfu/design": "catalog:frontend",
15+
"@devframes/agentic": "workspace:*",
1516
"@devframes/hub": "workspace:*",
1617
"@devframes/json-render": "workspace:*",
1718
"@devframes/json-render-ui": "workspace:*",

examples/custom-hub-vite/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"dependencies": {
1414
"@antfu/design": "catalog:frontend",
15+
"@devframes/agentic": "workspace:*",
1516
"@devframes/hub": "workspace:*",
1617
"@devframes/json-render": "workspace:*",
1718
"@devframes/json-render-ui": "workspace:*",

0 commit comments

Comments
 (0)