Skip to content

Commit aa52aaa

Browse files
committed
feat!: move the MCP adapter into the optional @devframes/agentic peer
The MCP adapter, 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. - @devframes/agentic ships /mcp (createMcpServer, createMcpFetchHandler, mountMcpHttp) and /connect (the devframe connect gateway); 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 throws DF0079 without the peer; false stays silent. - devframe/adapters/mcp keeps working as an alias for @devframes/agentic/mcp (same exports; throws DF0079 when the peer is absent), built in its own graph so its top-level await cannot reshape the server chunking. - 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.
1 parent 582920e commit aa52aaa

71 files changed

Lines changed: 922 additions & 383 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/10.standalone-cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ version.on('updated', () => fetchPayload().then(setData))
274274

275275
## Use your own CLI framework
276276

277-
Own a CLI framework (commander, yargs, oclif)? Use the three factories `createCac` wraps against one `DevframeDefinition`: `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`devframe/adapters/mcp`); see the [CLI adapter](/adapters/cac#use-your-own-cli-framework).
277+
Own a CLI framework (commander, yargs, oclif)? Use the three factories `createCac` wraps against one `DevframeDefinition`: `createDevServer` (`devframe/adapters/dev`), `createBuild` (`devframe/adapters/build`), and `createMcpServer` (`@devframes/agentic/mcp`); see the [CLI adapter](/adapters/cac#use-your-own-cli-framework).
278278

279279
```ts [src/cli.ts]
280280
import process from 'node:process'

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Devframe exposes its API (RPC functions, resources, shared state) to agents, ove
99

1010
## How it works
1111

12-
Three pieces: the **`agent` field** on `defineRpcFunction`, **`ctx.agent`** (non-RPC tools + resources), and the **MCP adapter** (`devframe/adapters/mcp`) serving an [MCP](https://modelcontextprotocol.io) server. The same `agent` field on a *client* RPC function surfaces it [over WebMCP](#browser-side-tools-over-webmcp) instead.
12+
Three pieces: the **`agent` field** on `defineRpcFunction`, **`ctx.agent`** (non-RPC tools + resources), and the **MCP adapter** (`@devframes/agentic/mcp`) serving an [MCP](https://modelcontextprotocol.io) server. The same `agent` field on a *client* RPC function surfaces it [over WebMCP](#browser-side-tools-over-webmcp) instead.
1313

1414
## Exposing an RPC function
1515

@@ -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

@@ -112,8 +112,8 @@ devframe mcp
112112
Programmatically:
113113

114114
```ts
115+
import { createMcpServer } from '@devframes/agentic/mcp'
115116
import { defineDevframe } from 'devframe'
116-
import { createMcpServer } from 'devframe/adapters/mcp'
117117

118118
const myDevframe = defineDevframe({ /**/ })
119119

docs/content/1.guide/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,11 @@ The handler serves the web interface, connection metadata, live RPC, authenticat
6363
[Higher-level adapters](/adapters) package the foundation as a standalone CLI, dev server, Vite DevTools plugin, MCP server, or static report:
6464

6565
```ts
66+
import { createMcpServer } from '@devframes/agentic/mcp'
6667
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
6768
import { createBuild } from 'devframe/adapters/build'
6869
import { createCac } from 'devframe/adapters/cac'
6970
import { createDevServer } from 'devframe/adapters/dev'
70-
import { createMcpServer } from 'devframe/adapters/mcp'
7171
import devframe from './devframe'
7272

7373
/** Pick the entry points your package ships: */

docs/content/2.adapters/2.cac.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Peer factories for a commander/yargs program:
104104
|----------------|-------|---------|
105105
| [`createDevServer()`](/adapters/dev) | `devframe/adapters/dev` | h3 + WebSocket RPC + SPA mount |
106106
| [`createBuild()`](/adapters/build) | `devframe/adapters/build` | Static deploy |
107-
| [`createMcpServer()`](/adapters/mcp) | `devframe/adapters/mcp` | stdio MCP server |
107+
| [`createMcpServer()`](/adapters/mcp) | `@devframes/agentic/mcp` | stdio MCP server |
108108
| `parseCliFlags(schema, raw)` | `devframe/adapters/cac` | Validate flags (`CliFlagsSchema`) |
109109

110110
See the [Standalone CLI guide](/guide/standalone-cli#use-your-own-cli-framework).

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,26 @@ 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 adapter lives in **`@devframes/agentic`**, an optional peer of `devframe` that carries the MCP SDK, so a devframe without an agent surface ships with neither installed:
11+
12+
```sh
13+
npm install @devframes/agentic
14+
```
15+
1016
```ts
11-
import { createMcpServer } from 'devframe/adapters/mcp'
17+
import { createMcpServer } from '@devframes/agentic/mcp'
1218
import myDevframe from './my-tool'
1319

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

1723
`createMcpServer` serves `stdio` through the MCP SDK's `serveStdio`, pinning one server instance per connection.
1824

25+
`devframe/adapters/mcp` still resolves as an alias for `@devframes/agentic/mcp` with the same exports; it requires the peer to be installed (importing it without throws [DF0079](/errors/DF0079)).
26+
1927
## Route-based server
2028

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.
29+
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.
2230

2331
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:
2432

@@ -72,7 +80,7 @@ Both honor the same contract: omitted is `'auto'`, `true` forces the origin-only
7280
`createMcpFetchHandler(ctx, options)` returns the endpoint as a `Request → Response` handler plus a `dispose()`; mount it on any fetch server.
7381

7482
```ts
75-
import { createMcpFetchHandler } from 'devframe/adapters/mcp'
83+
import { createMcpFetchHandler } from '@devframes/agentic/mcp'
7684

7785
const mcp = createMcpFetchHandler(ctx, {
7886
serverName: 'my-tool (devframe)',
@@ -103,6 +111,8 @@ Two gateway tools (`devframe:connect:*` ids; see [tool ids and wire names](/guid
103111

104112
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.
105113

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.
114+
The connector's gateway lives in `@devframes/agentic/connect` (the same optional peer as the adapter; `devframe connect` without it throws [DF0046](/errors/DF0046)).
115+
116+
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` (`@devframes/agentic/connect`) with a per-instance `authToken` resolver.
107117

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

docs/content/2.adapters/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Adapters wrap it as `createXxx(def, options?)` at `devframe/adapters/<name>`. `c
1919
| [`build`](/adapters/build) | `devframe/adapters/build` | `createBuild()` | Static snapshots |
2020
| [`vite`](/adapters/vite) | `@vitejs/devtools-kit/node` | `createPluginFromDevframe()` | Vite DevTools |
2121
| [`embedded`](/adapters/embedded) | `devframe/adapters/embedded` | `createEmbedded(def, { ctx })` | Runtime |
22-
| [`mcp`](/adapters/mcp) | `devframe/adapters/mcp` | `createMcpServer()` | Coding agents |
22+
| [`mcp`](/adapters/mcp) | `@devframes/agentic/mcp` | `createMcpServer()` | Coding agents |
2323

2424
## Mount paths
2525

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 `@devframes/agentic/mcp` could not be imported, typically because the optional peer 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.

0 commit comments

Comments
 (0)