@goke/mcp 0.1.1 → 0.1.2
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/README.md +2 -1
- package/dist/__test__/add-cli-tools-to-mcp.test.js +1 -0
- package/dist/__test__/create-mcp-action.test.js +6 -2
- package/dist/__test__/http-multi-tenant.test.js +1 -0
- package/dist/cli-to-mcp.d.ts.map +1 -1
- package/dist/cli-to-mcp.js +3 -6
- package/package.json +2 -2
- package/src/__test__/add-cli-tools-to-mcp.test.ts +1 -0
- package/src/__test__/create-mcp-action.test.ts +6 -2
- package/src/__test__/http-multi-tenant.test.ts +1 -0
- package/src/cli-to-mcp.ts +3 -8
package/README.md
CHANGED
|
@@ -95,6 +95,7 @@ const cli = goke("my-cli")
|
|
|
95
95
|
cli
|
|
96
96
|
.command("search", "Search pages")
|
|
97
97
|
.option("--query <query>", z.string().describe("Search query"))
|
|
98
|
+
.required()
|
|
98
99
|
.option("--limit [limit]", z.number().default(10).describe("Max results"))
|
|
99
100
|
.action((options) => {
|
|
100
101
|
return { results: findPages(options.query, options.limit) }
|
|
@@ -129,7 +130,7 @@ my-cli mcp
|
|
|
129
130
|
|
|
130
131
|
When running as MCP, the server exposes `search` and `deploy` as tools. The `mcp` command itself is excluded. Options with Zod schemas (or any Standard Schema) become typed `inputSchema` properties in the MCP tool definition.
|
|
131
132
|
|
|
132
|
-
**`inputSchema.required` is not the CLI `<value>` syntax.** `--query <query>` means the flag needs a value if it is present. The flag is still optional unless
|
|
133
|
+
**`inputSchema.required` is not the CLI `<value>` syntax.** `--query <query>` means the flag needs a value if it is present. The flag itself is still optional unless you chain `.required()`. Required **positionals** like `<env>` always go in `required`. `.required()` flags go in `required` too.
|
|
133
134
|
|
|
134
135
|
### Installing the MCP server in clients
|
|
135
136
|
|
|
@@ -15,6 +15,7 @@ function createCli() {
|
|
|
15
15
|
cli
|
|
16
16
|
.command("say hi", "Say hello")
|
|
17
17
|
.option("--name <name>", z.string().describe("Person to greet"))
|
|
18
|
+
.required()
|
|
18
19
|
.option("--caps", z.boolean().default(false).describe("Uppercase output"))
|
|
19
20
|
.action((options) => {
|
|
20
21
|
const message = `Hello ${options.name}!`;
|
|
@@ -29,7 +29,9 @@ describe("createMcpAction", () => {
|
|
|
29
29
|
cli
|
|
30
30
|
.command("add", "Add numbers")
|
|
31
31
|
.option("--a <a>", z.number().describe("First"))
|
|
32
|
+
.required()
|
|
32
33
|
.option("--b <b>", z.number().describe("Second"))
|
|
34
|
+
.required()
|
|
33
35
|
.action((options) => ({ sum: options.a + options.b }));
|
|
34
36
|
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
35
37
|
cli.command("mcp", "Start MCP server").action(createMcpAction({
|
|
@@ -186,7 +188,7 @@ describe("createMcpAction", () => {
|
|
|
186
188
|
expect(searchTool.description).toBe("Search for items");
|
|
187
189
|
expect(searchTool.inputSchema.properties).toHaveProperty("query");
|
|
188
190
|
expect(searchTool.inputSchema.properties).toHaveProperty("limit");
|
|
189
|
-
expect(searchTool.inputSchema.required).
|
|
191
|
+
expect(searchTool.inputSchema.required).toBeUndefined();
|
|
190
192
|
const deployTool = tools.tools.find((t) => t.name === "deploy");
|
|
191
193
|
expect(deployTool.inputSchema.properties).toHaveProperty("env");
|
|
192
194
|
expect(deployTool.inputSchema.properties).toHaveProperty("dryRun");
|
|
@@ -271,12 +273,14 @@ describe("createMcpAction", () => {
|
|
|
271
273
|
await client.close();
|
|
272
274
|
}
|
|
273
275
|
});
|
|
274
|
-
it("puts
|
|
276
|
+
it("puts .required() --flag <value> in inputSchema.required", async () => {
|
|
275
277
|
const cli = goke("checks");
|
|
276
278
|
cli
|
|
277
279
|
.command("checks create", "Create a check")
|
|
278
280
|
.option("--url <url>", z.string().describe("URL to check"))
|
|
281
|
+
.required()
|
|
279
282
|
.option("--name <name>", z.string().describe("Check name"))
|
|
283
|
+
.required()
|
|
280
284
|
.option("--timeout [ms]", z.number().optional().describe("Timeout"))
|
|
281
285
|
.action((options) => options);
|
|
282
286
|
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
@@ -90,6 +90,7 @@ function buildBaseCli() {
|
|
|
90
90
|
cli
|
|
91
91
|
.command("save <filename>", "Save content to a file in the tenant workspace")
|
|
92
92
|
.option("--content <content>", z.string().describe("File content"))
|
|
93
|
+
.required()
|
|
93
94
|
.action(async (filename, options, ctx) => {
|
|
94
95
|
const full = path.posix.join(ctx.process.cwd, filename);
|
|
95
96
|
await ctx.fs.writeFile(full, options.content);
|
package/dist/cli-to-mcp.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-to-mcp.d.ts","sourceRoot":"","sources":["../src/cli-to-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAS/E,OAAO,
|
|
1
|
+
{"version":3,"file":"cli-to-mcp.d.ts","sourceRoot":"","sources":["../src/cli-to-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAS/E,OAAO,EAKL,KAAK,IAAI,EAIV,MAAM,MAAM,CAAC;AAyFd,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,IAAI,CAAC;IACV,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;CACpD;AAufD,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,GAAG,EAAE,IAAI,CAAC;IACV,iGAAiG;IACjG,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;IACjD,iCAAiC;IACjC,gBAAgB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC;IACnD,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;CACxD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAsClG;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAyCvE"}
|
package/dist/cli-to-mcp.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* or a high-level McpServer by mounting tools/list + tools/call handlers.
|
|
6
6
|
*/
|
|
7
7
|
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
-
import { coerceBySchema, extractJsonSchema, GokeProcessExit,
|
|
8
|
+
import { coerceBySchema, extractJsonSchema, GokeProcessExit, } from "goke";
|
|
9
9
|
const CLI_TO_MCP_STATE = Symbol.for("@goke/mcp/cli-to-mcp-state");
|
|
10
10
|
function createTextCaptureStream() {
|
|
11
11
|
const chunks = [];
|
|
@@ -360,14 +360,11 @@ function createBinding(cli, command, toolName) {
|
|
|
360
360
|
}
|
|
361
361
|
}
|
|
362
362
|
// `--days <days>` means "value required if the flag is present". The flag
|
|
363
|
-
// itself is required only when
|
|
363
|
+
// itself is required only when `.required()` set `flagRequired`.
|
|
364
364
|
for (const option of options) {
|
|
365
365
|
const normalized = normalizeOptionSchema(option);
|
|
366
366
|
properties[option.name] = normalized.schema;
|
|
367
|
-
if (option.
|
|
368
|
-
&& option.default === undefined
|
|
369
|
-
&& option.schema
|
|
370
|
-
&& !schemaAcceptsOmittedValue(option.schema)) {
|
|
367
|
+
if (option.flagRequired && option.default === undefined) {
|
|
371
368
|
requiredNames.push(option.name);
|
|
372
369
|
}
|
|
373
370
|
optionBindings.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goke/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Dynamically generate CLI commands from MCP server tools",
|
|
6
6
|
"repository": {
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@types/node": "^22.19.7",
|
|
52
52
|
"vitest": "^3.1.0",
|
|
53
53
|
"zod": "^4.3.6",
|
|
54
|
-
"goke": "^6.
|
|
54
|
+
"goke": "^6.17.0"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"clean": "rm -rf dist",
|
|
@@ -18,6 +18,7 @@ function createCli() {
|
|
|
18
18
|
cli
|
|
19
19
|
.command("say hi", "Say hello")
|
|
20
20
|
.option("--name <name>", z.string().describe("Person to greet"))
|
|
21
|
+
.required()
|
|
21
22
|
.option("--caps", z.boolean().default(false).describe("Uppercase output"))
|
|
22
23
|
.action((options) => {
|
|
23
24
|
const message = `Hello ${options.name}!`;
|
|
@@ -35,7 +35,9 @@ describe("createMcpAction", () => {
|
|
|
35
35
|
cli
|
|
36
36
|
.command("add", "Add numbers")
|
|
37
37
|
.option("--a <a>", z.number().describe("First"))
|
|
38
|
+
.required()
|
|
38
39
|
.option("--b <b>", z.number().describe("Second"))
|
|
40
|
+
.required()
|
|
39
41
|
.action((options) => ({ sum: options.a + options.b }));
|
|
40
42
|
|
|
41
43
|
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
@@ -238,7 +240,7 @@ describe("createMcpAction", () => {
|
|
|
238
240
|
expect(searchTool.description).toBe("Search for items");
|
|
239
241
|
expect(searchTool.inputSchema.properties).toHaveProperty("query");
|
|
240
242
|
expect(searchTool.inputSchema.properties).toHaveProperty("limit");
|
|
241
|
-
expect(searchTool.inputSchema.required).
|
|
243
|
+
expect(searchTool.inputSchema.required).toBeUndefined();
|
|
242
244
|
|
|
243
245
|
const deployTool = tools.tools.find((t) => t.name === "deploy")!;
|
|
244
246
|
expect(deployTool.inputSchema.properties).toHaveProperty("env");
|
|
@@ -346,13 +348,15 @@ describe("createMcpAction", () => {
|
|
|
346
348
|
}
|
|
347
349
|
});
|
|
348
350
|
|
|
349
|
-
it("puts
|
|
351
|
+
it("puts .required() --flag <value> in inputSchema.required", async () => {
|
|
350
352
|
const cli = goke("checks");
|
|
351
353
|
|
|
352
354
|
cli
|
|
353
355
|
.command("checks create", "Create a check")
|
|
354
356
|
.option("--url <url>", z.string().describe("URL to check"))
|
|
357
|
+
.required()
|
|
355
358
|
.option("--name <name>", z.string().describe("Check name"))
|
|
359
|
+
.required()
|
|
356
360
|
.option("--timeout [ms]", z.number().optional().describe("Timeout"))
|
|
357
361
|
.action((options) => options);
|
|
358
362
|
|
|
@@ -104,6 +104,7 @@ function buildBaseCli(): Goke {
|
|
|
104
104
|
cli
|
|
105
105
|
.command("save <filename>", "Save content to a file in the tenant workspace")
|
|
106
106
|
.option("--content <content>", z.string().describe("File content"))
|
|
107
|
+
.required()
|
|
107
108
|
.action(async (filename: string, options: { content: string }, ctx) => {
|
|
108
109
|
const full = path.posix.join(ctx.process.cwd, filename);
|
|
109
110
|
await ctx.fs.writeFile(full, options.content);
|
package/src/cli-to-mcp.ts
CHANGED
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
coerceBySchema,
|
|
21
21
|
extractJsonSchema,
|
|
22
22
|
GokeProcessExit,
|
|
23
|
-
schemaAcceptsOmittedValue,
|
|
24
23
|
type Command,
|
|
25
24
|
type Goke,
|
|
26
25
|
type GokeExecutionContext,
|
|
@@ -41,6 +40,7 @@ interface OptionLike {
|
|
|
41
40
|
description: string;
|
|
42
41
|
default?: unknown;
|
|
43
42
|
required?: boolean;
|
|
43
|
+
flagRequired?: boolean;
|
|
44
44
|
isBoolean?: boolean;
|
|
45
45
|
schema?: StandardJSONSchemaV1;
|
|
46
46
|
}
|
|
@@ -505,17 +505,12 @@ function createBinding(cli: Goke, command: Command, toolName: string): CliToolBi
|
|
|
505
505
|
}
|
|
506
506
|
|
|
507
507
|
// `--days <days>` means "value required if the flag is present". The flag
|
|
508
|
-
// itself is required only when
|
|
508
|
+
// itself is required only when `.required()` set `flagRequired`.
|
|
509
509
|
for (const option of options) {
|
|
510
510
|
const normalized = normalizeOptionSchema(option);
|
|
511
511
|
properties[option.name] = normalized.schema;
|
|
512
512
|
|
|
513
|
-
if (
|
|
514
|
-
option.required
|
|
515
|
-
&& option.default === undefined
|
|
516
|
-
&& option.schema
|
|
517
|
-
&& !schemaAcceptsOmittedValue(option.schema)
|
|
518
|
-
) {
|
|
513
|
+
if (option.flagRequired && option.default === undefined) {
|
|
519
514
|
requiredNames.push(option.name);
|
|
520
515
|
}
|
|
521
516
|
|