Skip to content

Commit 70e95ad

Browse files
antfubotantfu
andauthored
feat!: move the MCP implementation into the optional @devframes/agentic peer (0.10) (#391)
Co-authored-by: Anthony Fu <github@antfu.me>
1 parent 0df34f9 commit 70e95ad

73 files changed

Lines changed: 937 additions & 371 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: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ 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'
@@ -18,7 +24,7 @@ await createMcpServer(myDevframe, { transport: 'stdio' })
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, 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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
title: 'Migrating to 0.10'
3+
description: '0.10 moves the MCP implementation and the MCP SDK into @devframes/agentic, a new optional peer: install it to serve agent tools over MCP; imports are unchanged.'
4+
---
5+
6+
0.10 moves the MCP implementation and the MCP SDK out of `devframe` into [`@devframes/agentic`](/adapters/mcp), a new **optional peer**. A devframe without an agent surface ships slimmer (no MCP SDK installed at all); one that exposes agent tools adds a single install. Your imports do not change.
7+
8+
## MCP requires `@devframes/agentic`
9+
10+
`devframe/adapters/mcp` stays the user-facing API and now lazy-loads its implementation from the `@devframes/agentic` peer; the peer itself is never imported directly. Install it wherever an MCP surface should be served:
11+
12+
```sh
13+
npm install @devframes/agentic
14+
```
15+
16+
Every surface reacts to the missing peer the same way:
17+
18+
| `mcp` setting | peer installed | peer missing |
19+
| ------------- | -------------- | ------------ |
20+
| omitted / `'auto'` | mounts once the agent surface is non-empty | non-empty surface: warns once ([DF0078](/errors/DF0078)), mounts nothing; empty surface: silent, no MCP code loads |
21+
| `true` / route options object | always mounts | throws [DF0079](/errors/DF0079) |
22+
| `false` | never mounts, never probes | same |
23+
24+
This applies everywhere the `mcp` setting exists: `createCac` / `--mcp`, `createDevServer`, `initDevframe`, `initHub`'s aggregate endpoint, and the framework kits.
25+
26+
The exports are unchanged - `createMcpServer`, `createMcpFetchHandler`, `mountMcpHttp`, and their option types (also importable from `devframe/types`). Importing `devframe/adapters/mcp` without the peer installed throws the usual module-not-found error, exactly like `devframe/adapters/cac` with its optional `cac` peer. The `<your-app> mcp` stdio subcommand keeps working with the peer installed.
27+
28+
## `devframe connect` requires `@devframes/agentic`
29+
30+
The connector's gateway moved into the same peer, replacing the former `@modelcontextprotocol/client` optional peer. `devframe connect` without it throws [DF0046](/errors/DF0046):
31+
32+
| 0.9.x | 0.10 |
33+
|-------|------|
34+
| `npm install @modelcontextprotocol/client` (optional peer for `devframe connect`) | `npm install @devframes/agentic` |
35+
36+
## `devframe` no longer depends on the MCP SDK
37+
38+
`@modelcontextprotocol/server` left `devframe`'s dependencies and `@modelcontextprotocol/client` left its optional peers; both are now regular dependencies of `@devframes/agentic`, so installing the peer is the whole story. If you had installed `@modelcontextprotocol/client` only for `devframe connect`, you can drop it:
39+
40+
```sh
41+
npm uninstall @modelcontextprotocol/client
42+
npm install @devframes/agentic
43+
```
44+
45+
Code that imported SDK types directly for devframe's MCP options no longer needs to: the full option surface is typed on `devframe/adapters/mcp` and `devframe/types` without any SDK types.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)