argsbarg 7.1.1 → 7.1.3
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 +38 -1
- package/README.md +7 -7
- package/docs/README.md +1 -1
- package/docs/cli-program.md +1 -1
- package/docs/configure.md +2 -2
- package/docs/mcp.md +53 -4
- package/docs/output-schema.md +6 -0
- package/examples/full-example/AGENTS.md +1 -1
- package/examples/full-example/bun.lock +83 -1
- package/examples/full-example/justfile +5 -3
- package/examples/full-example-json/AGENTS.md +1 -1
- package/examples/full-example-json/README.md +1 -0
- package/examples/full-example-json/bun.lock +83 -1
- package/examples/full-example-json/docs/cli-schema.json +284 -9
- package/examples/full-example-json/docs/cli.md +236 -18
- package/examples/full-example-json/docs/http.md +1 -0
- package/examples/full-example-json/docs/mcp.md +18 -0
- package/examples/full-example-json/docs/openapi.json +155 -0
- package/examples/full-example-json/justfile +5 -3
- package/examples/full-example-json/src/commands/shape-area/__generated__/ShapeAreaInputSchema.json +59 -0
- package/examples/full-example-json/src/commands/shape-area/__generated__/index.ts +5 -0
- package/examples/full-example-json/src/commands/shape-area/command.test.ts +34 -0
- package/examples/full-example-json/src/commands/shape-area/command.ts +31 -0
- package/examples/full-example-json/src/commands/shape-area/types.ts +28 -0
- package/examples/full-example-json/src/program.ts +2 -1
- package/examples/mcp-plugin/.claude-plugin/plugin.json +7 -1
- package/examples/mcp-plugin/.cursor-plugin/plugin.json +7 -1
- package/examples/mcp-plugin/AGENTS.md +14 -1
- package/examples/mcp-plugin/README.md +19 -10
- package/examples/mcp-plugin/bun.lock +83 -1
- package/examples/mcp-plugin/bunfig.toml +4 -0
- package/examples/mcp-plugin/docs/node-distro.md +97 -0
- package/examples/mcp-plugin/justfile +12 -11
- package/examples/mcp-plugin/package.json +2 -1
- package/examples/mcp-plugin/scripts/release.ts +10 -11
- package/index.d.ts +62 -0
- package/package.json +1 -1
- package/src/cli-tool/create.test.ts +14 -0
- package/src/cli-tool/create.ts +9 -0
- package/src/cli-tool/main.ts +1 -1
- package/src/cli-tool/schemagen/run.ts +41 -2
- package/src/cli-tool/schemagen/schemagen.test.ts +87 -2
- package/src/config/validate.test.ts +157 -0
- package/src/config/validate.ts +353 -26
- package/src/core/document-leaf.test.ts +53 -0
- package/src/core/json-pointer.ts +46 -0
- package/src/core/types.ts +33 -0
- package/src/core/validate.ts +68 -1
- package/src/docs/docs.test.ts +7 -0
- package/src/docs/mcp-guide.ts +43 -1
- package/src/headless/tool-call.test.ts +74 -2
- package/src/headless/tool-call.ts +44 -22
- package/src/http/schema-deref.ts +1 -23
- package/src/index.ts +3 -0
- package/src/mcp/server.ts +28 -4
- package/src/mcp/tools.test.ts +292 -0
- package/src/mcp/tools.ts +144 -6
- package/src/runtime/cli.ts +6 -1
- package/src/server/context.ts +6 -0
- package/src/test/integration/mcp.test.ts +73 -0
- package/src/test/mcp-integration-fixture.ts +1 -0
- package/src/test/mcp-size-fixture.ts +31 -0
- package/examples/mcp-plugin/.mcp.json +0 -6
- package/examples/mcp-plugin/mcp.json +0 -8
- package/examples/mcp-plugin/scripts/mcp.mjs +0 -11106
- package/examples/mcp-plugin/src/commands/render-json/__generated__/RenderJsonInputSchema.json +0 -15
- package/examples/mcp-plugin/src/commands/render-json/__generated__/index.ts +0 -5
- package/examples/mcp-plugin/src/commands/status/__generated__/StatusJsonOutputSchema.json +0 -15
- package/examples/mcp-plugin/src/commands/status/__generated__/index.ts +0 -5
- package/examples/mcp-plugin/src/commands/workspaces/__generated__/WorkspaceNameInputSchema.json +0 -15
- package/examples/mcp-plugin/src/commands/workspaces/__generated__/index.ts +0 -5
package/src/mcp/tools.ts
CHANGED
|
@@ -6,6 +6,7 @@ flat JSON tool arguments into argv for Cli.invoke.
|
|
|
6
6
|
import { cliSchemaJson } from "../core/schema.ts";
|
|
7
7
|
import {
|
|
8
8
|
type CliLeaf,
|
|
9
|
+
type CliMcpSizeLimits,
|
|
9
10
|
type CliNode,
|
|
10
11
|
type CliOption,
|
|
11
12
|
CliOptionKind,
|
|
@@ -48,10 +49,51 @@ export interface McpToolDef {
|
|
|
48
49
|
path: string[];
|
|
49
50
|
/** Leaf command node. */
|
|
50
51
|
leaf: CliLeaf;
|
|
51
|
-
/** JSON Schema for tools/call arguments. */
|
|
52
|
+
/** JSON Schema for tools/call arguments (wrapped under {@link MCP_INPUT_WRAPPER_KEY} when not object-rooted). */
|
|
52
53
|
inputSchema: Record<string, unknown>;
|
|
53
|
-
/**
|
|
54
|
+
/** True when {@link inputSchema} wraps the leaf schema; tools/call arguments are unwrapped before invoke. */
|
|
55
|
+
inputWrapped: boolean;
|
|
56
|
+
/** JSON Schema for structured tool results (wrapped under {@link MCP_OUTPUT_WRAPPER_KEY} when not object-rooted). */
|
|
54
57
|
outputSchema?: Record<string, unknown>;
|
|
58
|
+
/** True when {@link outputSchema} wraps the leaf schema; `structuredContent` is wrapped to match. */
|
|
59
|
+
outputWrapped: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Property holding the leaf input when an MCP `inputSchema` is wrapped to get an object root. */
|
|
63
|
+
export const MCP_INPUT_WRAPPER_KEY = "input";
|
|
64
|
+
|
|
65
|
+
/** Property holding the leaf result when an MCP `outputSchema` is wrapped to get an object root. */
|
|
66
|
+
export const MCP_OUTPUT_WRAPPER_KEY = "result";
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* MCP requires `type: "object"` at the root of tool input and output schemas. Returns object-rooted
|
|
70
|
+
* schemas unchanged; wraps anything else (e.g. a discriminated-union `anyOf` root) as a single
|
|
71
|
+
* required property, moving `$schema`, `$id`, `definitions`, and `$defs` up so `#/definitions/…`
|
|
72
|
+
* references still resolve.
|
|
73
|
+
*/
|
|
74
|
+
export function wrapMcpRootSchema(
|
|
75
|
+
/** Leaf input or output schema. */
|
|
76
|
+
schema: Record<string, unknown>,
|
|
77
|
+
/** Wrapper property name ({@link MCP_INPUT_WRAPPER_KEY} or {@link MCP_OUTPUT_WRAPPER_KEY}). */
|
|
78
|
+
key: string,
|
|
79
|
+
): { schema: Record<string, unknown>; wrapped: boolean } {
|
|
80
|
+
if (schema.type === "object") {
|
|
81
|
+
return { schema, wrapped: false };
|
|
82
|
+
}
|
|
83
|
+
const { $schema, $id, definitions, $defs, ...inner } = schema;
|
|
84
|
+
return {
|
|
85
|
+
schema: {
|
|
86
|
+
...($schema === undefined ? {} : { $schema }),
|
|
87
|
+
...($id === undefined ? {} : { $id }),
|
|
88
|
+
type: "object",
|
|
89
|
+
properties: { [key]: inner },
|
|
90
|
+
required: [key],
|
|
91
|
+
additionalProperties: false,
|
|
92
|
+
...(definitions === undefined ? {} : { definitions }),
|
|
93
|
+
...($defs === undefined ? {} : { $defs }),
|
|
94
|
+
},
|
|
95
|
+
wrapped: true,
|
|
96
|
+
};
|
|
55
97
|
}
|
|
56
98
|
|
|
57
99
|
/** Builds MCP tool description: "{cli path} — {description}". */
|
|
@@ -107,7 +149,13 @@ function resolveToolDescription(root: CliProgram, path: string[], leaf: CliLeaf)
|
|
|
107
149
|
} else {
|
|
108
150
|
desc = mcpToolDescription(path, root.key, leaf.description);
|
|
109
151
|
}
|
|
110
|
-
|
|
152
|
+
// `mcpTool.notes` overrides what CLI help shows (leaf.notes) for the MCP description only:
|
|
153
|
+
// `false` omits notes entirely; a string replaces them; omitted falls through to leaf.notes.
|
|
154
|
+
const notesOverride = leaf.mcpTool?.notes;
|
|
155
|
+
if (notesOverride === false) {
|
|
156
|
+
return desc;
|
|
157
|
+
}
|
|
158
|
+
const notes = (typeof notesOverride === "string" ? notesOverride : (leaf.notes ?? "")).trim();
|
|
111
159
|
if (notes.length > 0) {
|
|
112
160
|
desc += `\n\n${cliResolveNotes(notes, root.key)}`;
|
|
113
161
|
}
|
|
@@ -156,14 +204,18 @@ export function collectMcpTools(root: CliProgram): McpToolDef[] {
|
|
|
156
204
|
if (isMcpHidden(cmd)) {
|
|
157
205
|
return;
|
|
158
206
|
}
|
|
159
|
-
const
|
|
207
|
+
const input = wrapMcpRootSchema(buildLeafInputSchema(cmd), MCP_INPUT_WRAPPER_KEY);
|
|
208
|
+
const leafOutput = leafOutputSchema(cmd);
|
|
209
|
+
const output = leafOutput === undefined ? undefined : wrapMcpRootSchema(leafOutput, MCP_OUTPUT_WRAPPER_KEY);
|
|
160
210
|
out.push({
|
|
161
211
|
name: mcpToolName(root, path),
|
|
162
212
|
description: resolveToolDescription(root, path, cmd),
|
|
163
213
|
path,
|
|
164
214
|
leaf: cmd,
|
|
165
|
-
inputSchema:
|
|
166
|
-
|
|
215
|
+
inputSchema: input.schema,
|
|
216
|
+
inputWrapped: input.wrapped,
|
|
217
|
+
...(output === undefined ? {} : { outputSchema: output.schema }),
|
|
218
|
+
outputWrapped: output?.wrapped ?? false,
|
|
167
219
|
});
|
|
168
220
|
return;
|
|
169
221
|
}
|
|
@@ -272,3 +324,89 @@ export function mcpToolCallToArgv(
|
|
|
272
324
|
|
|
273
325
|
return argv;
|
|
274
326
|
}
|
|
327
|
+
|
|
328
|
+
/** Default {@link CliMcpSizeLimits}; see that type for what each limit approximates and why. */
|
|
329
|
+
export const DEFAULT_MCP_SIZE_LIMITS: Required<CliMcpSizeLimits> = {
|
|
330
|
+
definitionBytes: 51_200,
|
|
331
|
+
definitionLines: 2_000,
|
|
332
|
+
descriptionChars: 2_048,
|
|
333
|
+
instructionsChars: 2_048,
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/** Measured size of one MCP tool's description and pretty-printed definition. */
|
|
337
|
+
export interface McpToolSize {
|
|
338
|
+
/** Pretty-printed `{name, description, inputSchema, outputSchema}`, in UTF-8 bytes. */
|
|
339
|
+
definitionBytes: number;
|
|
340
|
+
/** Line count of the same pretty-printed definition. */
|
|
341
|
+
definitionLines: number;
|
|
342
|
+
/** Character length of `description` alone. */
|
|
343
|
+
descriptionChars: number;
|
|
344
|
+
/** MCP tool name. */
|
|
345
|
+
name: string;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** Per-tool sizes plus any warnings past {@link CliMcpSizeLimits} (defaults or `mcpServer.sizeLimits`). */
|
|
349
|
+
export interface McpSizeReport {
|
|
350
|
+
/** Character length of `mcpServer.instructions`, or 0 when unset. */
|
|
351
|
+
instructionsChars: number;
|
|
352
|
+
/** One entry per MCP tool, in `tools/list` order. */
|
|
353
|
+
tools: McpToolSize[];
|
|
354
|
+
/** Human-readable warnings for anything past its limit; empty when everything fits. */
|
|
355
|
+
warnings: string[];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Formats a definition's pretty-printed JSON exactly as Cursor's synced tool file would show it. */
|
|
359
|
+
function mcpToolDefinitionJson(tool: McpToolDef): string {
|
|
360
|
+
return JSON.stringify(
|
|
361
|
+
{
|
|
362
|
+
name: tool.name,
|
|
363
|
+
description: tool.description,
|
|
364
|
+
inputSchema: tool.inputSchema,
|
|
365
|
+
...(tool.outputSchema === undefined ? {} : { outputSchema: tool.outputSchema }),
|
|
366
|
+
},
|
|
367
|
+
null,
|
|
368
|
+
2,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Measures every MCP tool's description and definition size against {@link CliMcpSizeLimits}. */
|
|
373
|
+
export function mcpSizeReport(root: CliProgram): McpSizeReport {
|
|
374
|
+
const limits = { ...DEFAULT_MCP_SIZE_LIMITS, ...root.mcpServer?.sizeLimits };
|
|
375
|
+
const warnings: string[] = [];
|
|
376
|
+
|
|
377
|
+
const tools = collectMcpTools(root).map((tool): McpToolSize => {
|
|
378
|
+
const definitionJson = mcpToolDefinitionJson(tool);
|
|
379
|
+
const definitionBytes = Buffer.byteLength(definitionJson, "utf8");
|
|
380
|
+
const definitionLines = definitionJson.split("\n").length;
|
|
381
|
+
const descriptionChars = tool.description.length;
|
|
382
|
+
|
|
383
|
+
if (limits.descriptionChars !== false && descriptionChars > limits.descriptionChars) {
|
|
384
|
+
warnings.push(
|
|
385
|
+
`MCP tool "${tool.name}" description is ${descriptionChars.toLocaleString()} chars ` +
|
|
386
|
+
`(limit ${limits.descriptionChars.toLocaleString()}; Claude Code truncates longer descriptions)`,
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
const overBytes = limits.definitionBytes !== false && definitionBytes > limits.definitionBytes;
|
|
390
|
+
const overLines = limits.definitionLines !== false && definitionLines > limits.definitionLines;
|
|
391
|
+
if (overBytes || overLines) {
|
|
392
|
+
const byteLimit = limits.definitionBytes === false ? "∞" : limits.definitionBytes.toLocaleString();
|
|
393
|
+
const lineLimit = limits.definitionLines === false ? "∞" : limits.definitionLines.toLocaleString();
|
|
394
|
+
warnings.push(
|
|
395
|
+
`MCP tool "${tool.name}" definition is ${definitionBytes.toLocaleString()} bytes / ` +
|
|
396
|
+
`${definitionLines.toLocaleString()} lines pretty-printed (limit ${byteLimit} bytes / ${lineLimit} lines; ` +
|
|
397
|
+
`Cursor reads tool definitions in chunks of at most that size)`,
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return { definitionBytes, definitionLines, descriptionChars, name: tool.name };
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
const instructionsChars = (root.mcpServer?.instructions ?? "").length;
|
|
405
|
+
if (limits.instructionsChars !== false && instructionsChars > limits.instructionsChars) {
|
|
406
|
+
warnings.push(
|
|
407
|
+
`MCP instructions are ${instructionsChars.toLocaleString()} chars (limit ${limits.instructionsChars.toLocaleString()})`,
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return { instructionsChars, tools, warnings };
|
|
412
|
+
}
|
package/src/runtime/cli.ts
CHANGED
|
@@ -33,7 +33,8 @@ import { buildInvokeHookContext, classifyFailureKind, runErrorPipeline, runHook
|
|
|
33
33
|
import { httpServeHttp } from "../http/server.ts";
|
|
34
34
|
import { LogEmitter } from "../log/emitter.ts";
|
|
35
35
|
import { bootstrapMcpEnv } from "../mcp/env.ts";
|
|
36
|
-
import { mcpServeStdioLoop } from "../mcp/server.ts";
|
|
36
|
+
import { MCP_PROTOCOL_VERSIONS, mcpServeStdioLoop } from "../mcp/server.ts";
|
|
37
|
+
import { mcpSizeReport } from "../mcp/tools.ts";
|
|
37
38
|
import { createServerRuntime, type ServerHandleContext } from "../server/context.ts";
|
|
38
39
|
import { resolveHttpServeConfig, resolveMcpServeConfig, type ServeOverrides } from "../server/overrides.ts";
|
|
39
40
|
import {
|
|
@@ -414,6 +415,7 @@ export class Cli {
|
|
|
414
415
|
emitter,
|
|
415
416
|
mcp: resolved,
|
|
416
417
|
mcpHooks: this.program.mcpServer?.hooks,
|
|
418
|
+
mcpProtocolVersion: MCP_PROTOCOL_VERSIONS[0],
|
|
417
419
|
};
|
|
418
420
|
bootstrapAppConfig(this.program, { validateFile: "soft", runtime, emitter });
|
|
419
421
|
const shutdown = () => {
|
|
@@ -422,6 +424,9 @@ export class Cli {
|
|
|
422
424
|
};
|
|
423
425
|
process.once("SIGINT", shutdown);
|
|
424
426
|
process.once("SIGTERM", shutdown);
|
|
427
|
+
for (const message of mcpSizeReport(this.program).warnings) {
|
|
428
|
+
emitter.emit({ level: "warn", message, action: "mcp.size" });
|
|
429
|
+
}
|
|
425
430
|
emitter.emitLifecycle(`${this.program.key} ${this.program.version} — MCP ready (stdio)`, "mcp.server.ready");
|
|
426
431
|
await mcpServeStdioLoop(this);
|
|
427
432
|
process.exit(0);
|
package/src/server/context.ts
CHANGED
|
@@ -14,6 +14,12 @@ export interface ServerHandleContext {
|
|
|
14
14
|
mcp?: ResolvedMcpServeConfig;
|
|
15
15
|
httpHooks?: CliHttpWireHooks;
|
|
16
16
|
mcpHooks?: CliMcpWireHooks;
|
|
17
|
+
/**
|
|
18
|
+
* The MCP protocol version negotiated with `initialize`, or the newest supported version before
|
|
19
|
+
* `initialize` has been handled. Later requests (`tools/list`, `tools/call`) gate version-specific
|
|
20
|
+
* response fields (e.g. `outputSchema`, `structuredContent`) on this.
|
|
21
|
+
*/
|
|
22
|
+
mcpProtocolVersion?: string;
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
/** Creates a fresh {@link ServerRuntime} for HTTP or MCP. */
|
|
@@ -353,6 +353,79 @@ test("MCP initialize returns tools and resources capabilities", async () => {
|
|
|
353
353
|
expect(res.result.capabilities.resources).toBeDefined();
|
|
354
354
|
});
|
|
355
355
|
|
|
356
|
+
test("MCP initialize echoes a supported protocol version", async () => {
|
|
357
|
+
for (const version of ["2024-11-05", "2025-06-18"]) {
|
|
358
|
+
const responses = await mcpRequest([
|
|
359
|
+
{ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: version } },
|
|
360
|
+
]);
|
|
361
|
+
const res = responses.get(1) as { result: { protocolVersion: string } };
|
|
362
|
+
expect(res.result.protocolVersion).toBe(version);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
test("MCP initialize answers unsupported or missing versions with the newest", async () => {
|
|
367
|
+
for (const params of [{ protocolVersion: "2099-01-01" }, {}]) {
|
|
368
|
+
const responses = await mcpRequest([{ jsonrpc: "2.0", id: 1, method: "initialize", params }]);
|
|
369
|
+
const res = responses.get(1) as { result: { protocolVersion: string } };
|
|
370
|
+
expect(res.result.protocolVersion).toBe("2025-06-18");
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test("2024-11-05 sessions omit outputSchema and structuredContent", async () => {
|
|
375
|
+
const readme = join(import.meta.dir, "..", "..", "..", "README.md");
|
|
376
|
+
const responses = await mcpRequest([
|
|
377
|
+
{ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2024-11-05" } },
|
|
378
|
+
{ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} },
|
|
379
|
+
{
|
|
380
|
+
jsonrpc: "2.0",
|
|
381
|
+
id: 3,
|
|
382
|
+
method: "tools/call",
|
|
383
|
+
params: { name: "stat_owner_lookup", arguments: { path: readme, "user-name": "test" } },
|
|
384
|
+
},
|
|
385
|
+
]);
|
|
386
|
+
const listRes = responses.get(2) as { result: { tools: { name: string; outputSchema?: unknown }[] } };
|
|
387
|
+
const lookup = listRes.result.tools.find((t) => t.name === "stat_owner_lookup");
|
|
388
|
+
expect(lookup).toBeDefined();
|
|
389
|
+
expect(lookup?.outputSchema).toBeUndefined();
|
|
390
|
+
|
|
391
|
+
const callRes = responses.get(3) as { result: { structuredContent?: unknown; isError: boolean } };
|
|
392
|
+
expect(callRes.result.isError).toBe(false);
|
|
393
|
+
expect(callRes.result.structuredContent).toBeUndefined();
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
test("MCP initialize includes configured instructions", async () => {
|
|
397
|
+
const responses = await mcpRequest([{ jsonrpc: "2.0", id: 1, method: "initialize", params: {} }], {
|
|
398
|
+
script: "src/test/mcp-integration-fixture.ts",
|
|
399
|
+
});
|
|
400
|
+
const res = responses.get(1) as { result: { instructions?: string } };
|
|
401
|
+
expect(res.result.instructions).toBe("Read the fixture skill.");
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
test("MCP startup warns about oversized tools on stderr", async () => {
|
|
405
|
+
const proc = Bun.spawn(["bun", "run", "src/test/mcp-size-fixture.ts", "mcp"], {
|
|
406
|
+
stdin: "pipe",
|
|
407
|
+
stdout: "pipe",
|
|
408
|
+
stderr: "pipe",
|
|
409
|
+
});
|
|
410
|
+
proc.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: {} })}\n`);
|
|
411
|
+
proc.stdin.end();
|
|
412
|
+
const timeout = setTimeout(() => proc.kill(), 10_000);
|
|
413
|
+
const [stdout, stderr] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text()]);
|
|
414
|
+
await proc.exited;
|
|
415
|
+
clearTimeout(timeout);
|
|
416
|
+
|
|
417
|
+
expect(stderr).toContain("description is 3,");
|
|
418
|
+
|
|
419
|
+
const lines = stdout
|
|
420
|
+
.split("\n")
|
|
421
|
+
.map((l) => l.trim())
|
|
422
|
+
.filter(Boolean);
|
|
423
|
+
expect(lines.length).toBeGreaterThan(0);
|
|
424
|
+
for (const line of lines) {
|
|
425
|
+
expect(() => JSON.parse(line)).not.toThrow();
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
|
|
356
429
|
test("MCP tools/list includes stat_owner_lookup", async () => {
|
|
357
430
|
const responses = await mcpRequest([{ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} }]);
|
|
358
431
|
const res = responses.get(2) as {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/*
|
|
3
|
+
MCP size-warning integration test fixture (not a public example). One leaf with oversized notes,
|
|
4
|
+
triggering the "description" startup size warning on stderr.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Cli, type CliProgram } from "../index.ts";
|
|
8
|
+
|
|
9
|
+
const program = {
|
|
10
|
+
commands: [
|
|
11
|
+
{
|
|
12
|
+
key: "run",
|
|
13
|
+
description: "Run it.",
|
|
14
|
+
notes: "x".repeat(3_000),
|
|
15
|
+
handler: (ctx) => {
|
|
16
|
+
if (ctx.invocation === "cli") {
|
|
17
|
+
console.log("ran");
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
return "ran";
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
description: "MCP size-warning test fixture.",
|
|
25
|
+
key: "mcp-size-test",
|
|
26
|
+
mcpServer: { enabled: true },
|
|
27
|
+
version: "0.0.0-test",
|
|
28
|
+
} satisfies CliProgram;
|
|
29
|
+
|
|
30
|
+
const cli = new Cli(program);
|
|
31
|
+
await cli.run();
|