Skip to content
Merged
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
5 changes: 4 additions & 1 deletion alias.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ export const alias = {
'devframe/adapters/build': r('devframe/src/adapters/build.ts'),
'devframe/adapters/embedded': r('devframe/src/adapters/embedded.ts'),
'devframe/initiate': r('devframe/src/adapters/initiate.ts'),
'devframe/adapters/mcp': r('devframe/src/adapters/mcp/index.ts'),
'devframe/adapters/mcp': r('devframe/src/adapters/mcp.ts'),
'@devframes/agentic/mcp': r('agentic/src/mcp/index.ts'),
'@devframes/agentic/connect': r('agentic/src/connect/index.ts'),
'@devframes/agentic': r('agentic/src/index.ts'),
'@devframes/hub/build': r('hub/src/node/build.ts'),
'@devframes/hub/client': r('hub/src/client/index.ts'),
'@devframes/hub/constants': r('hub/src/constants.ts'),
Expand Down
2 changes: 1 addition & 1 deletion docs/content/1.guide/15.agent-native.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ Every `ctx.rpc.sharedState` key is exposed as a `devframe://state/<key>` resourc

## Starting the MCP server

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

For a stdio server instead, via the CLI:

Expand Down
12 changes: 10 additions & 2 deletions docs/content/2.adapters/7.mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ description: 'Exposes a devframe''s agent-facing API as a Model Context Protocol

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

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:

```sh
npm install @devframes/agentic
```

```ts
import { createMcpServer } from 'devframe/adapters/mcp'
import myDevframe from './my-tool'
Expand All @@ -18,7 +24,7 @@ await createMcpServer(myDevframe, { transport: 'stdio' })

## Route-based server

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

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:

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

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.

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.
The connector needs the same optional `@devframes/agentic` peer as the adapter; `devframe connect` without it throws [DF0046](/errors/DF0046).

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).

See [Agent-Native](/guide/agent-native) for the API and safety model.
14 changes: 7 additions & 7 deletions docs/content/6.errors/DF0046.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
---
title: 'DF0046: Connector Requires the MCP SDK'
description: 'devframe connect requires the optional peer dependency @modelcontextprotocol/client: {reason}'
title: 'DF0046: Connector Requires @devframes/agentic'
description: 'devframe connect requires the optional peer dependency @devframes/agentic: {reason}'
---

## Message

> `devframe connect` requires the optional peer dependency @modelcontextprotocol/client: `{reason}`
> `devframe connect` requires the optional peer dependency @devframes/agentic: `{reason}`

## Cause

`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.
`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.

## Fix

Install the SDK next to devframe and run the connector again:
Install the package next to devframe and run the connector again:

```sh
npm install @modelcontextprotocol/client
npm install @devframes/agentic
devframe connect
```

## Source

- [`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.
- [`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.
28 changes: 28 additions & 0 deletions docs/content/6.errors/DF0078.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: 'DF0078: Agent Surface Without @devframes/agentic'
description: 'This devframe exposes agent tools, but the MCP endpoint stays off: the optional peer "@devframes/agentic" is not installed.'
---

## Message

> This devframe exposes agent tools, but the MCP endpoint stays off: the optional peer "@devframes/agentic" is not installed.

## Cause

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.

The warning is reported once per process; the instance keeps running without an MCP endpoint.

## Fix

Install the peer so the agent surface is served over MCP:

```sh
npm install @devframes/agentic
```

Or, if the tools should deliberately stay unexposed, set `mcp: false` to opt out silently.

## Source

- [`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.
26 changes: 26 additions & 0 deletions docs/content/6.errors/DF0079.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: 'DF0079: MCP Enabled Without @devframes/agentic'
description: 'The mcp option is enabled, but the optional peer "@devframes/agentic" could not be loaded: {reason}'
---

## Message

> The `mcp` option is enabled, but the optional peer "@devframes/agentic" could not be loaded: `{reason}`

## Cause

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.

## Fix

Install the peer next to devframe:

```sh
npm install @devframes/agentic
```

Or remove the explicit `mcp` setting (or pass `mcp: false`) if the endpoint isn't wanted. The underlying import error is attached as `cause`.

## Source

- [`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.
4 changes: 3 additions & 1 deletion docs/content/6.errors/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Emitted by `devframe`: the framework-neutral host, RPC, streaming, assets, servi
| [DF0043](/errors/DF0043) | error | Invalid RPC Argument |
| [DF0044](/errors/DF0044) | error | Invalid RPC Return Value |
| [DF0045](/errors/DF0045) | warn | Instance Registry Update Failed |
| [DF0046](/errors/DF0046) | error | Connector Requires the MCP SDK |
| [DF0046](/errors/DF0046) | error | Connector Requires @devframes/agentic |
| [DF0047](/errors/DF0047) | warn | Agent Tool Wire-Name Collision |
| [DF0048](/errors/DF0048) | error | Unknown Shared-State Key |
| [DF0049](/errors/DF0049) | error | Connector Call Requires Port and Tool |
Expand Down Expand Up @@ -84,6 +84,8 @@ Emitted by `devframe`: the framework-neutral host, RPC, streaming, assets, servi
| [DF0075](/errors/DF0075) | warn | No RPC Transport On This Runtime |
| [DF0076](/errors/DF0076) | error | WebSocket Upgrade Unsupported On This Runtime |
| [DF0077](/errors/DF0077) | error | In-Page Channel Function Not Registered |
| [DF0078](/errors/DF0078) | warn | Agent Surface Without @devframes/agentic |
| [DF0079](/errors/DF0079) | error | MCP Enabled Without @devframes/agentic |

## Hub: context & lifecycle (DF80xx)

Expand Down
45 changes: 45 additions & 0 deletions docs/content/7.migrations/1.migration-0.10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
title: 'Migrating to 0.10'
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.'
---

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.

## MCP requires `@devframes/agentic`

`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:

```sh
npm install @devframes/agentic
```

Every surface reacts to the missing peer the same way:

| `mcp` setting | peer installed | peer missing |
| ------------- | -------------- | ------------ |
| 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 |
| `true` / route options object | always mounts | throws [DF0079](/errors/DF0079) |
| `false` | never mounts, never probes | same |

This applies everywhere the `mcp` setting exists: `createCac` / `--mcp`, `createDevServer`, `initDevframe`, `initHub`'s aggregate endpoint, and the framework kits.

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.

## `devframe connect` requires `@devframes/agentic`

The connector's gateway moved into the same peer, replacing the former `@modelcontextprotocol/client` optional peer. `devframe connect` without it throws [DF0046](/errors/DF0046):

| 0.9.x | 0.10 |
|-------|------|
| `npm install @modelcontextprotocol/client` (optional peer for `devframe connect`) | `npm install @devframes/agentic` |

## `devframe` no longer depends on the MCP SDK

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

```sh
npm uninstall @modelcontextprotocol/client
npm install @devframes/agentic
```

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.
1 change: 1 addition & 0 deletions docs/content/7.migrations/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Upgrade guides for devframe and `@devframes/hub`, newest first. Each one lists e

| Version | What changed |
| ------- | ------------ |
| [Migrating to 0.10](/migrations/migration-0.10) | Moves the MCP implementation and the MCP SDK into `@devframes/agentic`, a new optional peer; imports are unchanged. |
| [Migrating to 0.9](/migrations/migration-0.9) | Removes the compatibility shims deprecated across the 0.7 series, trims the public API, and moves the MCP surface to the stateless MCP 2026-07-28 protocol. |
| [Migrating to 0.8](/migrations/migration-0.8) | Makes RPC schemas validator-neutral and runtime-validated, and adds the agent-native MCP API. |
| [Migrating to 0.7](/migrations/migration-0.7) | Makes `cac` an optional peer and moves json-render into an opt-in package. |
Expand Down
1 change: 1 addition & 0 deletions examples/custom-hub-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"dependencies": {
"@antfu/design": "catalog:frontend",
"@devframes/agentic": "workspace:*",
"@devframes/hub": "workspace:*",
"@devframes/json-render": "workspace:*",
"@devframes/json-render-ui": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions examples/custom-hub-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
},
"dependencies": {
"@antfu/design": "catalog:frontend",
"@devframes/agentic": "workspace:*",
"@devframes/hub": "workspace:*",
"@devframes/json-render": "workspace:*",
"@devframes/json-render-ui": "workspace:*",
Expand Down
6 changes: 4 additions & 2 deletions knip.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@
// listed explicitly instead. Keep this in sync with the `exports` map.
"entry": [
"src/{index,constants}.ts",
"src/adapters/{build,cac,dev,embedded,initiate}.ts",
"src/adapters/mcp/index.ts",
"src/adapters/{build,cac,dev,embedded,initiate,mcp}.ts",
"src/client/index.ts",
"src/in-page-channel/index.ts",
"src/internal/index.ts",
Expand All @@ -151,6 +150,9 @@
"src/utils/*.ts"
]
},
"packages/agentic": {
"entry": ["src/{mcp,connect}/index.ts"]
},
"packages/hub": {
"entry": ["src/{index,constants}.ts", "src/{client,node,types}/index.ts", "src/node/{index,initiate,build}.ts"]
},
Expand Down
55 changes: 55 additions & 0 deletions packages/agentic/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "@devframes/agentic",
"type": "module",
"version": "0.9.19",
"description": "Agent-surface implementation for devframe: installing it next to devframe enables the MCP adapter (devframe/adapters/mcp) and the devframe connect gateway.",
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
"license": "MIT",
"homepage": "https://github.com/devframes/devframe#readme",
"repository": {
"directory": "packages/agentic",
"type": "git",
"url": "git+https://github.com/devframes/devframe.git"
},
"bugs": "https://github.com/devframes/devframe/issues",
"keywords": [
"devtools",
"devframe",
"mcp",
"agent"
],
"sideEffects": false,
"exports": {
".": "./dist/index.mjs",
"./mcp": "./dist/mcp/index.mjs",
"./connect": "./dist/connect/index.mjs",
"./package.json": "./package.json"
},
"types": "./dist/index.d.mts",
"files": [
"dist"
],
"scripts": {
"build": "tsdown",
"watch": "tsdown --watch",
"typecheck": "tsc --noEmit",
"prepack": "turbo run build --filter=@devframes/agentic"
},
"peerDependencies": {
"devframe": "workspace:*"
},
"dependencies": {
"@modelcontextprotocol/client": "catalog:deps",
"@modelcontextprotocol/server": "catalog:deps",
"@standard-schema/spec": "catalog:deps",
"h3": "catalog:deps",
"pathe": "catalog:deps",
"ufo": "catalog:deps"
},
"devDependencies": {
"@types/node": "catalog:types",
"devframe": "workspace:*",
"tsdown": "catalog:build",
"valibot": "catalog:deps"
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import type { DevframeInstanceRecord } from '../node/instance-registry'
import type { StartedServer } from '../node/instance-shell'
import type { DevframeDefinition } from '../types/devframe'
import type { DevframeInstanceRecord, StartedServer } from 'devframe/internal'
import type { DevframeDefinition } from 'devframe/types'
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client'
import { createDevServer } from 'devframe/adapters/dev'
import { afterEach, describe, expect, it } from 'vitest'
import { createDevServer } from '../adapters/dev'
import { buildInstanceRequestHeaders, resolveAuthToken } from './connect'
import { buildInstanceRequestHeaders, resolveAuthToken } from '../index'

const TOKEN = 'a-high-entropy-connect-test-token'

Expand Down
Loading
Loading