@procedures/mcp-dev-tools 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +3 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/host.d.ts +7 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +46 -57
- package/dist/host.js.map +1 -1
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +9 -1
- package/dist/server.js.map +1 -1
- package/package.json +6 -6
- package/src/host.ts +54 -60
- package/src/server.ts +12 -4
package/dist/host.d.ts
CHANGED
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
* - each tool call has a time limit.
|
|
9
9
|
*
|
|
10
10
|
* `server.ts` (the file in the MCP configuration of Claude Code) and `mark mcp` both start the
|
|
11
|
-
* server with `startDevToolsServer()`.
|
|
11
|
+
* server with `startDevToolsServer()`. The host comes from `createMcpHost()` of
|
|
12
|
+
* `@procedures/mcp-server` (CLI-10): the same factory as `mcp.serve` and the hosts of the apps.
|
|
12
13
|
*
|
|
13
14
|
* `MCP_FS_ROOT` confines the procedures to one folder (`confineToRoot()` of `@procedures/fs`):
|
|
14
15
|
* each tool keeps its paths in it, or the root refuses the tool. The host serves no remote
|
|
15
16
|
* events: its transport carries only MCP, and `events.subscribe` is not a tool.
|
|
16
17
|
*/
|
|
17
18
|
import { ProcedureServer, type HostPolicy, type ProcedureModule, type ProcedureRegistry, type ToolSurface } from "@procedures/client";
|
|
18
|
-
import { type BundleSurfaceModule } from "@procedures/mcp-server";
|
|
19
|
+
import { type BundleSurfaceModule, type McpHost } from "@procedures/mcp-server";
|
|
19
20
|
import { type McpServerConfig } from "./config.js";
|
|
20
21
|
/** The modules and the tool lists of some bundles. */
|
|
21
22
|
export interface LoadedBundles {
|
|
@@ -39,13 +40,16 @@ export interface DevToolsHost {
|
|
|
39
40
|
fsRoot?: string | undefined;
|
|
40
41
|
/** With a root: the keys of the procedures that the root refuses. Some of them are tools. */
|
|
41
42
|
refusedUnderRoot?: string[] | undefined;
|
|
43
|
+
/** The MCP host: `mcp.start()` starts its face (stdio, or Streamable HTTP with `config.http`). */
|
|
44
|
+
mcp: McpHost;
|
|
42
45
|
}
|
|
43
46
|
/** This function builds the host. It starts no transport. */
|
|
44
47
|
export declare function createDevToolsHost(config?: McpServerConfig): Promise<DevToolsHost>;
|
|
45
48
|
/**
|
|
46
49
|
* This function starts the dev-tools MCP server over stdio, or over Streamable HTTP with
|
|
47
50
|
* `config.http` (roadmap R26). Over stdio, stdout carries the protocol, so `console.log` goes to
|
|
48
|
-
* stderr from here on (BUGS-2026-07 Bug5).
|
|
51
|
+
* stderr from here on (BUGS-2026-07 Bug5). The stdio server stops when the client closes its
|
|
52
|
+
* input: `host.mcp.closed` then resolves.
|
|
49
53
|
*/
|
|
50
54
|
export declare function startDevToolsServer(config?: McpServerConfig): Promise<DevToolsHost>;
|
|
51
55
|
//# sourceMappingURL=host.d.ts.map
|
package/dist/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAEL,eAAe,EAGf,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,OAAO,EAEb,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAQ/D,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,kFAAkF;AAClF,wBAAsB,WAAW,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBpF;AAaD,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACxC,kGAAkG;IAClG,GAAG,EAAE,OAAO,CAAC;CACd;AAcD,6DAA6D;AAC7D,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,eAA8B,GAAG,OAAO,CAAC,YAAY,CAAC,CAmCtG;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,GAAE,eAA8B,GAAG,OAAO,CAAC,YAAY,CAAC,CAoBvG"}
|
package/dist/host.js
CHANGED
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
* - each tool call has a time limit.
|
|
9
9
|
*
|
|
10
10
|
* `server.ts` (the file in the MCP configuration of Claude Code) and `mark mcp` both start the
|
|
11
|
-
* server with `startDevToolsServer()`.
|
|
11
|
+
* server with `startDevToolsServer()`. The host comes from `createMcpHost()` of
|
|
12
|
+
* `@procedures/mcp-server` (CLI-10): the same factory as `mcp.serve` and the hosts of the apps.
|
|
12
13
|
*
|
|
13
14
|
* `MCP_FS_ROOT` confines the procedures to one folder (`confineToRoot()` of `@procedures/fs`):
|
|
14
15
|
* each tool keeps its paths in it, or the root refuses the tool. The host serves no remote
|
|
15
16
|
* events: its transport carries only MCP, and `events.subscribe` is not a tool.
|
|
16
17
|
*/
|
|
17
|
-
import { PROCEDURE_REGISTRY, ProcedureServer, createRegistry, registerClientProcedures,
|
|
18
|
-
import {
|
|
18
|
+
import { PROCEDURE_REGISTRY, ProcedureServer, createRegistry, registerClientProcedures, } from "@procedures/client";
|
|
19
|
+
import { createMcpHost, mergeSurfaces, redirectConsoleToStderr, } from "@procedures/mcp-server";
|
|
19
20
|
import { programCheckInterceptor } from "@procedures/compiler";
|
|
20
21
|
import { loadConfig } from "./config.js";
|
|
21
22
|
import { ms } from "@procedures/client";
|
|
@@ -49,6 +50,18 @@ async function loadBundlesGlobally(bundles) {
|
|
|
49
50
|
}
|
|
50
51
|
return { modules: [], surfaces, global: true };
|
|
51
52
|
}
|
|
53
|
+
/** The face of the configuration: Streamable HTTP with `config.http`, else stdio. */
|
|
54
|
+
function facesOf(config) {
|
|
55
|
+
if (!config.http)
|
|
56
|
+
return { stdio: true };
|
|
57
|
+
return {
|
|
58
|
+
http: {
|
|
59
|
+
port: config.http.port,
|
|
60
|
+
...(config.http.host ? { host: config.http.host } : {}),
|
|
61
|
+
...(config.http.token ? { token: config.http.token } : {}),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
52
65
|
/** This function builds the host. It starts no transport. */
|
|
53
66
|
export async function createDevToolsHost(config = loadConfig()) {
|
|
54
67
|
const loaded = await loadBundles(config.bundles);
|
|
@@ -64,75 +77,51 @@ export async function createDevToolsHost(config = loadConfig()) {
|
|
|
64
77
|
// Bundles without mcpNamespaces say nothing about their tools: then every procedure is a tool
|
|
65
78
|
const surface = mergeSurfaces(loaded.surfaces);
|
|
66
79
|
// Read only: the tools are the procedures that the capability permits, so the list shows only
|
|
67
|
-
// what a call can start (CAPABILITIES-2026-10)
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
:
|
|
79
|
-
// The check before the run (roadmap R22): a program with an error does not start, so a refusal
|
|
80
|
-
// in step 3 comes before the write of step 1
|
|
81
|
-
const exposeRule = typeof expose === "function" ? expose : expose ? surfaceRule(expose) : undefined;
|
|
82
|
-
const programCheck = config.programCheck === false ? [] : [programCheckInterceptor({ registry, expose: exposeRule })];
|
|
83
|
-
const policy = hostPolicy({
|
|
84
|
-
...(expose ? { expose } : {}),
|
|
85
|
-
strictCalls: true,
|
|
86
|
-
timeout: ms(config.toolTimeoutMs),
|
|
87
|
-
...(readOnly ? { readOnly: true } : {}),
|
|
88
|
-
...(programCheck.length > 0 ? { interceptors: programCheck } : {}),
|
|
80
|
+
// what a call can start (CAPABILITIES-2026-10). The check before the run (roadmap R22): a
|
|
81
|
+
// program with an error does not start, so a refusal in step 3 comes before the write of step 1.
|
|
82
|
+
const mcp = createMcpHost({
|
|
83
|
+
registry,
|
|
84
|
+
...(surface ? { surface } : {}),
|
|
85
|
+
readOnly: config.readOnly === true,
|
|
86
|
+
policy: { strictCalls: true, timeout: ms(config.toolTimeoutMs) },
|
|
87
|
+
...(config.programCheck === false ? {} : { interceptors: ({ expose }) => [programCheckInterceptor({ registry, expose })] }),
|
|
88
|
+
name: config.serverName,
|
|
89
|
+
version: config.serverVersion,
|
|
90
|
+
debug: config.debug,
|
|
91
|
+
faces: facesOf(config),
|
|
89
92
|
});
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
return {
|
|
94
|
+
registry,
|
|
95
|
+
surface,
|
|
96
|
+
policy: mcp.policy,
|
|
97
|
+
server: mcp.server,
|
|
98
|
+
mcp,
|
|
99
|
+
...(fsRoot !== undefined ? { fsRoot, refusedUnderRoot } : {}),
|
|
100
|
+
};
|
|
92
101
|
}
|
|
93
102
|
/**
|
|
94
103
|
* This function starts the dev-tools MCP server over stdio, or over Streamable HTTP with
|
|
95
104
|
* `config.http` (roadmap R26). Over stdio, stdout carries the protocol, so `console.log` goes to
|
|
96
|
-
* stderr from here on (BUGS-2026-07 Bug5).
|
|
105
|
+
* stderr from here on (BUGS-2026-07 Bug5). The stdio server stops when the client closes its
|
|
106
|
+
* input: `host.mcp.closed` then resolves.
|
|
97
107
|
*/
|
|
98
108
|
export async function startDevToolsServer(config = loadConfig()) {
|
|
99
|
-
// Defense-in-depth for the stdio transport: a stray console.log (from a procedure handler
|
|
100
|
-
// dependency) would corrupt the protocol. The MCP SDK writes its frames
|
|
101
|
-
// process.stdout.write, so it is not affected.
|
|
102
|
-
|
|
103
|
-
console.error(...args);
|
|
104
|
-
};
|
|
109
|
+
// Defense-in-depth for the stdio transport: a stray console.log (from a procedure handler, a
|
|
110
|
+
// dependency or a bundle that loads) would corrupt the protocol. The MCP SDK writes its frames
|
|
111
|
+
// with process.stdout.write, so it is not affected.
|
|
112
|
+
redirectConsoleToStderr();
|
|
105
113
|
if (config.debug) {
|
|
106
114
|
console.error("[mcp-server] Starting with config:", JSON.stringify(config, null, 2));
|
|
107
115
|
}
|
|
108
116
|
const host = await createDevToolsHost(config);
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
...(config.http
|
|
112
|
-
? {
|
|
113
|
-
transport: "http",
|
|
114
|
-
httpOptions: {
|
|
115
|
-
port: config.http.port,
|
|
116
|
-
...(config.http.host ? { host: config.http.host } : {}),
|
|
117
|
-
...(config.http.token ? { token: config.http.token } : {}),
|
|
118
|
-
},
|
|
119
|
-
}
|
|
120
|
-
: { transport: "stdio" }),
|
|
121
|
-
serverInfo: {
|
|
122
|
-
name: config.serverName,
|
|
123
|
-
version: config.serverVersion,
|
|
124
|
-
},
|
|
125
|
-
debug: config.debug,
|
|
126
|
-
...(expose ? { toolFilter: { include: expose } } : {}),
|
|
127
|
-
});
|
|
128
|
-
host.server.addTransport(transport);
|
|
129
|
-
await host.server.start();
|
|
117
|
+
await host.mcp.start();
|
|
118
|
+
const face = host.mcp.state().faces[0];
|
|
130
119
|
if (config.debug) {
|
|
131
|
-
console.error(`[mcp-server] Started with ${
|
|
120
|
+
console.error(`[mcp-server] Started with ${face?.toolCount ?? 0} tools`);
|
|
132
121
|
}
|
|
133
122
|
if (host.fsRoot !== undefined)
|
|
134
123
|
console.error(`[mcp-server] Each tool refuses a path outside ${host.fsRoot}. Refused under the root: ${String(host.refusedUnderRoot)}`);
|
|
135
|
-
const url =
|
|
124
|
+
const url = face?.url;
|
|
136
125
|
if (url)
|
|
137
126
|
console.error(`[mcp-server] Streamable HTTP at ${url}${config.http?.token ? " (send Authorization: Bearer <token>)" : ""}`);
|
|
138
127
|
return host;
|
package/dist/host.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* Starts an MCP server that exposes procedures as tools to Claude Code and Claude Desktop. The
|
|
5
5
|
* MCP configuration of a client runs this file (`node packages/impl-mcp-dev/dist/server.js`).
|
|
6
6
|
* Configurable via environment variables (see `config.ts`). `mark mcp` starts the same server.
|
|
7
|
+
*
|
|
8
|
+
* When the client closes the input of stdio, the host stops (the calls in flight get their grace
|
|
9
|
+
* time), and this process ends (CLI-10).
|
|
7
10
|
*/
|
|
8
11
|
export {};
|
|
9
12
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
package/dist/server.js
CHANGED
|
@@ -4,9 +4,17 @@
|
|
|
4
4
|
* Starts an MCP server that exposes procedures as tools to Claude Code and Claude Desktop. The
|
|
5
5
|
* MCP configuration of a client runs this file (`node packages/impl-mcp-dev/dist/server.js`).
|
|
6
6
|
* Configurable via environment variables (see `config.ts`). `mark mcp` starts the same server.
|
|
7
|
+
*
|
|
8
|
+
* When the client closes the input of stdio, the host stops (the calls in flight get their grace
|
|
9
|
+
* time), and this process ends (CLI-10).
|
|
7
10
|
*/
|
|
8
11
|
import { startDevToolsServer } from "./host.js";
|
|
9
|
-
startDevToolsServer()
|
|
12
|
+
startDevToolsServer()
|
|
13
|
+
.then(async (host) => {
|
|
14
|
+
await host.mcp.closed;
|
|
15
|
+
process.exit(0);
|
|
16
|
+
})
|
|
17
|
+
.catch((error) => {
|
|
10
18
|
console.error("[mcp-server] Fatal error:", error);
|
|
11
19
|
process.exit(1);
|
|
12
20
|
});
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,mBAAmB,EAAE;KAClB,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACnB,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;IACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;KACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/mcp-dev-tools",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"description": "A ready-to-use MCP server for Claude Code and Claude Desktop: 91 developer tools (docker, mongo, sqlite, cue, vitest, workspace) with a strict call policy.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
@@ -53,11 +53,11 @@
|
|
|
53
53
|
"provenance": true
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@procedures/bundle-mcp": "0.
|
|
57
|
-
"@procedures/client": "0.
|
|
58
|
-
"@procedures/compiler": "0.
|
|
59
|
-
"@procedures/fs": "0.
|
|
60
|
-
"@procedures/mcp-server": "0.
|
|
56
|
+
"@procedures/bundle-mcp": "0.9.0",
|
|
57
|
+
"@procedures/client": "0.9.0",
|
|
58
|
+
"@procedures/compiler": "0.9.0",
|
|
59
|
+
"@procedures/fs": "0.9.0",
|
|
60
|
+
"@procedures/mcp-server": "0.9.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@mark1russell7/cue": "^1.0.0",
|
package/src/host.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* - each tool call has a time limit.
|
|
9
9
|
*
|
|
10
10
|
* `server.ts` (the file in the MCP configuration of Claude Code) and `mark mcp` both start the
|
|
11
|
-
* server with `startDevToolsServer()`.
|
|
11
|
+
* server with `startDevToolsServer()`. The host comes from `createMcpHost()` of
|
|
12
|
+
* `@procedures/mcp-server` (CLI-10): the same factory as `mcp.serve` and the hosts of the apps.
|
|
12
13
|
*
|
|
13
14
|
* `MCP_FS_ROOT` confines the procedures to one folder (`confineToRoot()` of `@procedures/fs`):
|
|
14
15
|
* each tool keeps its paths in it, or the root refuses the tool. The host serves no remote
|
|
@@ -20,17 +21,19 @@ import {
|
|
|
20
21
|
ProcedureServer,
|
|
21
22
|
createRegistry,
|
|
22
23
|
registerClientProcedures,
|
|
23
|
-
capabilityRefusal,
|
|
24
|
-
narrowCapability,
|
|
25
|
-
surfaceRule,
|
|
26
|
-
hostPolicy,
|
|
27
|
-
procedureServerOptions,
|
|
28
24
|
type HostPolicy,
|
|
29
25
|
type ProcedureModule,
|
|
30
26
|
type ProcedureRegistry,
|
|
31
27
|
type ToolSurface,
|
|
32
28
|
} from "@procedures/client";
|
|
33
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
createMcpHost,
|
|
31
|
+
mergeSurfaces,
|
|
32
|
+
redirectConsoleToStderr,
|
|
33
|
+
type BundleSurfaceModule,
|
|
34
|
+
type McpHost,
|
|
35
|
+
type McpHostFaces,
|
|
36
|
+
} from "@procedures/mcp-server";
|
|
34
37
|
import { programCheckInterceptor } from "@procedures/compiler";
|
|
35
38
|
import { loadConfig, type McpServerConfig } from "./config.js";
|
|
36
39
|
import { ms } from "@procedures/client";
|
|
@@ -91,6 +94,20 @@ export interface DevToolsHost {
|
|
|
91
94
|
fsRoot?: string | undefined;
|
|
92
95
|
/** With a root: the keys of the procedures that the root refuses. Some of them are tools. */
|
|
93
96
|
refusedUnderRoot?: string[] | undefined;
|
|
97
|
+
/** The MCP host: `mcp.start()` starts its face (stdio, or Streamable HTTP with `config.http`). */
|
|
98
|
+
mcp: McpHost;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The face of the configuration: Streamable HTTP with `config.http`, else stdio. */
|
|
102
|
+
function facesOf(config: McpServerConfig): McpHostFaces {
|
|
103
|
+
if (!config.http) return { stdio: true };
|
|
104
|
+
return {
|
|
105
|
+
http: {
|
|
106
|
+
port: config.http.port,
|
|
107
|
+
...(config.http.host ? { host: config.http.host } : {}),
|
|
108
|
+
...(config.http.token ? { token: config.http.token } : {}),
|
|
109
|
+
},
|
|
110
|
+
};
|
|
94
111
|
}
|
|
95
112
|
|
|
96
113
|
/** This function builds the host. It starts no transport. */
|
|
@@ -108,76 +125,53 @@ export async function createDevToolsHost(config: McpServerConfig = loadConfig())
|
|
|
108
125
|
// Bundles without mcpNamespaces say nothing about their tools: then every procedure is a tool
|
|
109
126
|
const surface = mergeSurfaces(loaded.surfaces);
|
|
110
127
|
// Read only: the tools are the procedures that the capability permits, so the list shows only
|
|
111
|
-
// what a call can start (CAPABILITIES-2026-10)
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
:
|
|
122
|
-
|
|
123
|
-
// in step 3 comes before the write of step 1
|
|
124
|
-
const exposeRule = typeof expose === "function" ? expose : expose ? surfaceRule(expose) : undefined;
|
|
125
|
-
const programCheck = config.programCheck === false ? [] : [programCheckInterceptor({ registry, expose: exposeRule })];
|
|
126
|
-
const policy = hostPolicy({
|
|
127
|
-
...(expose ? { expose } : {}),
|
|
128
|
-
strictCalls: true,
|
|
129
|
-
timeout: ms(config.toolTimeoutMs),
|
|
130
|
-
...(readOnly ? { readOnly: true } : {}),
|
|
131
|
-
...(programCheck.length > 0 ? { interceptors: programCheck } : {}),
|
|
128
|
+
// what a call can start (CAPABILITIES-2026-10). The check before the run (roadmap R22): a
|
|
129
|
+
// program with an error does not start, so a refusal in step 3 comes before the write of step 1.
|
|
130
|
+
const mcp = createMcpHost({
|
|
131
|
+
registry,
|
|
132
|
+
...(surface ? { surface } : {}),
|
|
133
|
+
readOnly: config.readOnly === true,
|
|
134
|
+
policy: { strictCalls: true, timeout: ms(config.toolTimeoutMs) },
|
|
135
|
+
...(config.programCheck === false ? {} : { interceptors: ({ expose }) => [programCheckInterceptor({ registry, expose })] }),
|
|
136
|
+
name: config.serverName,
|
|
137
|
+
version: config.serverVersion,
|
|
138
|
+
debug: config.debug,
|
|
139
|
+
faces: facesOf(config),
|
|
132
140
|
});
|
|
133
|
-
|
|
134
|
-
|
|
141
|
+
return {
|
|
142
|
+
registry,
|
|
143
|
+
surface,
|
|
144
|
+
policy: mcp.policy,
|
|
145
|
+
server: mcp.server,
|
|
146
|
+
mcp,
|
|
147
|
+
...(fsRoot !== undefined ? { fsRoot, refusedUnderRoot } : {}),
|
|
148
|
+
};
|
|
135
149
|
}
|
|
136
150
|
|
|
137
151
|
/**
|
|
138
152
|
* This function starts the dev-tools MCP server over stdio, or over Streamable HTTP with
|
|
139
153
|
* `config.http` (roadmap R26). Over stdio, stdout carries the protocol, so `console.log` goes to
|
|
140
|
-
* stderr from here on (BUGS-2026-07 Bug5).
|
|
154
|
+
* stderr from here on (BUGS-2026-07 Bug5). The stdio server stops when the client closes its
|
|
155
|
+
* input: `host.mcp.closed` then resolves.
|
|
141
156
|
*/
|
|
142
157
|
export async function startDevToolsServer(config: McpServerConfig = loadConfig()): Promise<DevToolsHost> {
|
|
143
|
-
// Defense-in-depth for the stdio transport: a stray console.log (from a procedure handler
|
|
144
|
-
// dependency) would corrupt the protocol. The MCP SDK writes its frames
|
|
145
|
-
// process.stdout.write, so it is not affected.
|
|
146
|
-
|
|
147
|
-
console.error(...args);
|
|
148
|
-
};
|
|
158
|
+
// Defense-in-depth for the stdio transport: a stray console.log (from a procedure handler, a
|
|
159
|
+
// dependency or a bundle that loads) would corrupt the protocol. The MCP SDK writes its frames
|
|
160
|
+
// with process.stdout.write, so it is not affected.
|
|
161
|
+
redirectConsoleToStderr();
|
|
149
162
|
if (config.debug) {
|
|
150
163
|
console.error("[mcp-server] Starting with config:", JSON.stringify(config, null, 2));
|
|
151
164
|
}
|
|
152
165
|
|
|
153
166
|
const host = await createDevToolsHost(config);
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
...(config.http
|
|
157
|
-
? {
|
|
158
|
-
transport: "http" as const,
|
|
159
|
-
httpOptions: {
|
|
160
|
-
port: config.http.port,
|
|
161
|
-
...(config.http.host ? { host: config.http.host } : {}),
|
|
162
|
-
...(config.http.token ? { token: config.http.token } : {}),
|
|
163
|
-
},
|
|
164
|
-
}
|
|
165
|
-
: { transport: "stdio" as const }),
|
|
166
|
-
serverInfo: {
|
|
167
|
-
name: config.serverName,
|
|
168
|
-
version: config.serverVersion,
|
|
169
|
-
},
|
|
170
|
-
debug: config.debug,
|
|
171
|
-
...(expose ? { toolFilter: { include: expose } } : {}),
|
|
172
|
-
});
|
|
173
|
-
host.server.addTransport(transport);
|
|
174
|
-
await host.server.start();
|
|
167
|
+
await host.mcp.start();
|
|
168
|
+
const face = host.mcp.state().faces[0];
|
|
175
169
|
|
|
176
170
|
if (config.debug) {
|
|
177
|
-
console.error(`[mcp-server] Started with ${
|
|
171
|
+
console.error(`[mcp-server] Started with ${face?.toolCount ?? 0} tools`);
|
|
178
172
|
}
|
|
179
173
|
if (host.fsRoot !== undefined) console.error(`[mcp-server] Each tool refuses a path outside ${host.fsRoot}. Refused under the root: ${String(host.refusedUnderRoot)}`);
|
|
180
|
-
const url =
|
|
174
|
+
const url = face?.url;
|
|
181
175
|
if (url) console.error(`[mcp-server] Streamable HTTP at ${url}${config.http?.token ? " (send Authorization: Bearer <token>)" : ""}`);
|
|
182
176
|
return host;
|
|
183
177
|
}
|
package/src/server.ts
CHANGED
|
@@ -4,11 +4,19 @@
|
|
|
4
4
|
* Starts an MCP server that exposes procedures as tools to Claude Code and Claude Desktop. The
|
|
5
5
|
* MCP configuration of a client runs this file (`node packages/impl-mcp-dev/dist/server.js`).
|
|
6
6
|
* Configurable via environment variables (see `config.ts`). `mark mcp` starts the same server.
|
|
7
|
+
*
|
|
8
|
+
* When the client closes the input of stdio, the host stops (the calls in flight get their grace
|
|
9
|
+
* time), and this process ends (CLI-10).
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import { startDevToolsServer } from "./host.js";
|
|
10
13
|
|
|
11
|
-
startDevToolsServer()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
startDevToolsServer()
|
|
15
|
+
.then(async (host) => {
|
|
16
|
+
await host.mcp.closed;
|
|
17
|
+
process.exit(0);
|
|
18
|
+
})
|
|
19
|
+
.catch((error) => {
|
|
20
|
+
console.error("[mcp-server] Fatal error:", error);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
});
|