@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/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
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAEL,eAAe,EAQf,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAqC,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAErG,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;CACzC;AAED,6DAA6D;AAC7D,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,eAA8B,GAAG,OAAO,CAAC,YAAY,CAAC,CAsCtG;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,GAAE,eAA8B,GAAG,OAAO,CAAC,YAAY,CAAC,CAyCvG"}
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, capabilityRefusal, narrowCapability, surfaceRule, hostPolicy, procedureServerOptions, } from "@procedures/client";
18
- import { McpServerTransport, mergeSurfaces } from "@procedures/mcp-server";
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
- const readOnly = config.readOnly === true;
69
- const capability = readOnly ? narrowCapability(undefined, { effects: { writes: [] } }) : undefined;
70
- const surfaceExpose = surface ? surfaceRule(surface) : undefined;
71
- const expose = capability
72
- ? (path) => {
73
- if (surfaceExpose && !surfaceExpose(path))
74
- return false;
75
- const procedure = registry.get(path);
76
- return procedure !== undefined && capabilityRefusal(procedure, capability) === undefined;
77
- }
78
- : surface;
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
- const server = new ProcedureServer(procedureServerOptions(policy, registry));
91
- return { registry, surface, policy, server, ...(fsRoot !== undefined ? { fsRoot, refusedUnderRoot } : {}) };
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 or a
100
- // dependency) would corrupt the protocol. The MCP SDK writes its frames with
101
- // process.stdout.write, so it is not affected.
102
- console.log = (...args) => {
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
- const expose = host.policy.expose;
110
- const transport = new McpServerTransport(host.server, {
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 ${transport.getState().toolCount} tools`);
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 = transport.getState().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":"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"}
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,wBAAwB,GAKzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,aAAa,EACb,aAAa,EACb,uBAAuB,GAIxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAkBxC,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA0B;IAC1D,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,MAAM,QAAQ,GAA0B,EAAE,CAAC;IAC3C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,OAA4B,CAAC;QACjC,IAAI,CAAC;YACH,sEAAsE;YACtE,OAAO,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,SAAS,CAAC,CAAwB,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAC9C,CAAC;AAED,mFAAmF;AACnF,KAAK,UAAU,mBAAmB,CAAC,OAA0B;IAC3D,qGAAqG;IACrG,wBAAwB,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAA0B,EAAE,CAAC;IAC3C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,CAAwB,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACjD,CAAC;AAgBD,qFAAqF;AACrF,SAAS,OAAO,CAAC,MAAuB;IACtC,IAAI,CAAC,MAAM,CAAC,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzC,OAAO;QACL,IAAI,EAAE;YACJ,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI;YACtB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3D;KACF,CAAC;AACJ,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAM,GAAoB,UAAU,EAAE;IAC7E,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACxF,8FAA8F;IAC9F,8FAA8F;IAC9F,IAAI,MAA0B,CAAC;IAC/B,IAAI,gBAAsC,CAAC;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;QAChE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACzF,CAAC;IACD,8FAA8F;IAC9F,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/C,8FAA8F;IAC9F,0FAA0F;IAC1F,iGAAiG;IACjG,MAAM,GAAG,GAAG,aAAa,CAAC;QACxB,QAAQ;QACR,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,IAAI;QAClC,MAAM,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE;QAChE,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,uBAAuB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC;QAC3H,IAAI,EAAE,MAAM,CAAC,UAAU;QACvB,OAAO,EAAE,MAAM,CAAC,aAAa;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC;KACvB,CAAC,CAAC;IACH,OAAO;QACL,QAAQ;QACR,OAAO;QACP,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG;QACH,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAM,GAAoB,UAAU,EAAE;IAC9E,6FAA6F;IAC7F,+FAA+F;IAC/F,oDAAoD;IACpD,uBAAuB,EAAE,CAAC;IAC1B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEvC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CAAC,6BAA6B,IAAI,EAAE,SAAS,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,KAAK,CAAC,iDAAiD,IAAI,CAAC,MAAM,6BAA6B,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACvK,MAAM,GAAG,GAAG,IAAI,EAAE,GAAG,CAAC;IACtB,IAAI,GAAG;QAAE,OAAO,CAAC,KAAK,CAAC,mCAAmC,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrI,OAAO,IAAI,CAAC;AACd,CAAC"}
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
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
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().catch((error) => {
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
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,mBAAmB,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACpC,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
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.8.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.8.0",
57
- "@procedures/client": "0.8.0",
58
- "@procedures/compiler": "0.8.0",
59
- "@procedures/fs": "0.8.0",
60
- "@procedures/mcp-server": "0.8.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 { McpServerTransport, mergeSurfaces, type BundleSurfaceModule } from "@procedures/mcp-server";
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
- const readOnly = config.readOnly === true;
113
- const capability = readOnly ? narrowCapability(undefined, { effects: { writes: [] } }) : undefined;
114
- const surfaceExpose = surface ? surfaceRule(surface) : undefined;
115
- const expose = capability
116
- ? (path: string[]): boolean => {
117
- if (surfaceExpose && !surfaceExpose(path)) return false;
118
- const procedure = registry.get(path);
119
- return procedure !== undefined && capabilityRefusal(procedure, capability) === undefined;
120
- }
121
- : surface;
122
- // The check before the run (roadmap R22): a program with an error does not start, so a refusal
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
- const server = new ProcedureServer(procedureServerOptions(policy, registry));
134
- return { registry, surface, policy, server, ...(fsRoot !== undefined ? { fsRoot, refusedUnderRoot } : {}) };
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 or a
144
- // dependency) would corrupt the protocol. The MCP SDK writes its frames with
145
- // process.stdout.write, so it is not affected.
146
- console.log = (...args: unknown[]): void => {
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
- const expose = host.policy.expose;
155
- const transport = new McpServerTransport(host.server, {
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 ${transport.getState().toolCount} tools`);
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 = transport.getState().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().catch((error) => {
12
- console.error("[mcp-server] Fatal error:", error);
13
- process.exit(1);
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
+ });