@modeltoolsprotocol/mtpcli 1.1.0 → 1.2.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.
Files changed (3) hide show
  1. package/README.md +8 -12
  2. package/dist/index.js +328 -335
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # mtpcli
2
2
 
3
- The command-line interface for the [Model Tools Protocol](https://github.com/modeltoolsprotocol/modeltoolsprotocol) (MTP). Discover, authenticate, and bridge tools that implement the `--describe` convention.
3
+ The command-line interface for the [Model Tools Protocol](https://github.com/modeltoolsprotocol/modeltoolsprotocol) (MTP). Discover, authenticate, and bridge tools that implement the `--mtp-describe` convention.
4
4
 
5
- CLI tools are composable but not LLM-discoverable. MCP tools are discoverable but not composable. MTP bridges the gap with a single `--describe` flag. See the [protocol README](https://github.com/modeltoolsprotocol/modeltoolsprotocol) for the full rationale.
5
+ CLI tools are composable but not LLM-discoverable. MCP tools are discoverable but not composable. MTP bridges the gap with a single `--mtp-describe` flag. **mtpcli** turns any `--mtp-describe` CLI into an MCP server, turns any MCP server into a composable CLI, and handles discovery, auth, and validation along the way. See the [protocol README](https://github.com/modeltoolsprotocol/modeltoolsprotocol) for the full rationale.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,15 +10,11 @@ CLI tools are composable but not LLM-discoverable. MCP tools are discoverable bu
10
10
  npm install -g @modeltoolsprotocol/mtpcli
11
11
  ```
12
12
 
13
- ## What it does
14
-
15
- **mtpcli** bridges the gap between CLI tools and MCP servers. It turns any `--describe` CLI into an MCP server, turns any MCP server into a composable CLI, and handles discovery, auth, and validation along the way.
16
-
17
13
  ## Usage
18
14
 
19
15
  ### Serve CLI tools over MCP
20
16
 
21
- Any CLI that supports `--describe` becomes an MCP server:
17
+ Any CLI that supports `--mtp-describe` becomes an MCP server:
22
18
 
23
19
  ```bash
24
20
  $ mtpcli serve --tool atlasctl --tool mytool
@@ -31,7 +27,7 @@ mtpcli serve: serving 6 tool(s) from 2 CLI tool(s)
31
27
  ...
32
28
  ```
33
29
 
34
- Drop it into your Claude Desktop config and it works like any other MCP server. The bridge reads `--describe`, translates commands to MCP tools, and shells out to the real CLI when the host calls a tool.
30
+ Drop it into your Claude Desktop config and it works like any other MCP server. The bridge reads `--mtp-describe`, translates commands to MCP tools, and shells out to the real CLI when the host calls a tool.
35
31
 
36
32
  ### Wrap an MCP server as a CLI
37
33
 
@@ -39,7 +35,7 @@ Atlassian ships an MCP server at `mcp.atlassian.com`. With `mtpcli wrap`, it's a
39
35
 
40
36
  ```bash
41
37
  # Discover what tools the server offers
42
- $ mtpcli wrap --url "https://mcp.atlassian.com/v1/mcp" --describe
38
+ $ mtpcli wrap --url "https://mcp.atlassian.com/v1/mcp" --mtp-describe
43
39
 
44
40
  # Fetch a Confluence page
45
41
  $ mtpcli wrap --url "https://mcp.atlassian.com/v1/mcp" \
@@ -51,7 +47,7 @@ $ mtpcli wrap --url "https://mcp.atlassian.com/v1/mcp" \
51
47
  | jq -r '.body'
52
48
 
53
49
  # Works with stdio servers too
54
- $ mtpcli wrap --server "npx @mcp/server-github" --describe
50
+ $ mtpcli wrap --server "npx @mcp/server-github" --mtp-describe
55
51
  ```
56
52
 
57
53
  The 2,500+ MCP servers people have built? They're all CLI tools now. Pipe their output, use them in scripts, compose them with other tools.
@@ -90,7 +86,7 @@ mtpcli auth logout mytool
90
86
 
91
87
  See [AUTH.md](AUTH.md) for details on token storage, usage patterns, and bridge integration.
92
88
 
93
- ### Validate a tool's --describe output
89
+ ### Validate a tool's --mtp-describe output
94
90
 
95
91
  ```bash
96
92
  # Validate a tool against the MTP spec
@@ -120,7 +116,7 @@ mtpcli completions fish mytool | source
120
116
 
121
117
  ```bash
122
118
  # mtpcli is itself an MTP-compliant tool
123
- mtpcli --describe
119
+ mtpcli --mtp-describe
124
120
  ```
125
121
 
126
122
  ## Development
package/dist/index.js CHANGED
@@ -27,7 +27,6 @@ var __export = (target, all) => {
27
27
  });
28
28
  };
29
29
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
30
- var __promiseAll = (args) => Promise.all(args);
31
30
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
32
31
 
33
32
  // node_modules/commander/lib/error.js
@@ -2123,25 +2122,6 @@ var require_commander = __commonJS((exports) => {
2123
2122
  exports.InvalidOptionArgumentError = InvalidArgumentError;
2124
2123
  });
2125
2124
 
2126
- // node_modules/commander/esm.mjs
2127
- var import__, program, createCommand, createArgument, createOption, CommanderError, InvalidArgumentError, InvalidOptionArgumentError, Command, Argument, Option, Help;
2128
- var init_esm = __esm(() => {
2129
- import__ = __toESM(require_commander(), 1);
2130
- ({
2131
- program,
2132
- createCommand,
2133
- createArgument,
2134
- createOption,
2135
- CommanderError,
2136
- InvalidArgumentError,
2137
- InvalidOptionArgumentError,
2138
- Command,
2139
- Argument,
2140
- Option,
2141
- Help
2142
- } = import__.default);
2143
- });
2144
-
2145
2125
  // node_modules/zod/v3/helpers/util.js
2146
2126
  var util, objectUtil, ZodParsedType, getParsedType = (data) => {
2147
2127
  const t = typeof data;
@@ -6108,119 +6088,6 @@ var init_zod = __esm(() => {
6108
6088
  init_external();
6109
6089
  });
6110
6090
 
6111
- // src/models.ts
6112
- function cleanJson(obj) {
6113
- if (obj === null || obj === undefined)
6114
- return;
6115
- if (Array.isArray(obj)) {
6116
- return obj.map(cleanJson);
6117
- }
6118
- if (typeof obj === "object") {
6119
- const out = {};
6120
- for (const [k, v] of Object.entries(obj)) {
6121
- if (v === undefined)
6122
- continue;
6123
- if (Array.isArray(v) && v.length === 0)
6124
- continue;
6125
- const cleaned = cleanJson(v);
6126
- if (cleaned !== undefined) {
6127
- out[k] = cleaned;
6128
- }
6129
- }
6130
- return out;
6131
- }
6132
- return obj;
6133
- }
6134
- var ExampleSchema, ArgSchema, IoDescriptorSchema, CommandAuthSchema, CommandSchema, AuthProviderSchema, AuthConfigSchema, ToolSchemaSchema, StoredTokenSchema, JsonRpcErrorSchema, JsonRpcRequestSchema, JsonRpcResponseSchema, McpToolDefSchema;
6135
- var init_models = __esm(() => {
6136
- init_zod();
6137
- ExampleSchema = exports_external.object({
6138
- description: exports_external.string().optional(),
6139
- command: exports_external.string(),
6140
- output: exports_external.string().optional()
6141
- });
6142
- ArgSchema = exports_external.object({
6143
- name: exports_external.string(),
6144
- type: exports_external.string(),
6145
- description: exports_external.string().optional(),
6146
- required: exports_external.boolean().default(false),
6147
- default: exports_external.any().optional(),
6148
- values: exports_external.array(exports_external.string()).optional()
6149
- });
6150
- IoDescriptorSchema = exports_external.object({
6151
- contentType: exports_external.string().optional(),
6152
- description: exports_external.string().optional(),
6153
- schema: exports_external.any().optional()
6154
- });
6155
- CommandAuthSchema = exports_external.object({
6156
- required: exports_external.boolean().default(false),
6157
- scopes: exports_external.array(exports_external.string()).optional()
6158
- });
6159
- CommandSchema = exports_external.object({
6160
- name: exports_external.string(),
6161
- description: exports_external.string(),
6162
- args: exports_external.array(ArgSchema).default([]),
6163
- stdin: IoDescriptorSchema.optional(),
6164
- stdout: IoDescriptorSchema.optional(),
6165
- examples: exports_external.array(ExampleSchema).default([]),
6166
- auth: CommandAuthSchema.optional()
6167
- });
6168
- AuthProviderSchema = exports_external.object({
6169
- id: exports_external.string(),
6170
- type: exports_external.string(),
6171
- displayName: exports_external.string().optional(),
6172
- authorizationUrl: exports_external.string().optional(),
6173
- tokenUrl: exports_external.string().optional(),
6174
- scopes: exports_external.array(exports_external.string()).optional(),
6175
- clientId: exports_external.string().optional(),
6176
- registrationUrl: exports_external.string().optional(),
6177
- instructions: exports_external.string().optional()
6178
- });
6179
- AuthConfigSchema = exports_external.object({
6180
- required: exports_external.boolean().default(false),
6181
- envVar: exports_external.string(),
6182
- providers: exports_external.array(AuthProviderSchema)
6183
- });
6184
- ToolSchemaSchema = exports_external.object({
6185
- name: exports_external.string(),
6186
- version: exports_external.string(),
6187
- description: exports_external.string(),
6188
- auth: AuthConfigSchema.optional(),
6189
- commands: exports_external.array(CommandSchema)
6190
- });
6191
- StoredTokenSchema = exports_external.object({
6192
- access_token: exports_external.string(),
6193
- token_type: exports_external.string().optional(),
6194
- refresh_token: exports_external.string().optional(),
6195
- expires_at: exports_external.string().optional(),
6196
- scopes: exports_external.array(exports_external.string()).optional(),
6197
- provider_id: exports_external.string(),
6198
- created_at: exports_external.string()
6199
- });
6200
- JsonRpcErrorSchema = exports_external.object({
6201
- code: exports_external.number(),
6202
- message: exports_external.string(),
6203
- data: exports_external.any().optional()
6204
- });
6205
- JsonRpcRequestSchema = exports_external.object({
6206
- jsonrpc: exports_external.string(),
6207
- id: exports_external.any().optional(),
6208
- method: exports_external.string(),
6209
- params: exports_external.any().default({})
6210
- });
6211
- JsonRpcResponseSchema = exports_external.object({
6212
- jsonrpc: exports_external.string(),
6213
- id: exports_external.any().optional(),
6214
- result: exports_external.any().optional(),
6215
- error: JsonRpcErrorSchema.optional()
6216
- });
6217
- McpToolDefSchema = exports_external.object({
6218
- name: exports_external.string(),
6219
- description: exports_external.string(),
6220
- inputSchema: exports_external.any()
6221
- });
6222
- });
6223
-
6224
6091
  // node_modules/jaro-winkler/index.js
6225
6092
  var require_jaro_winkler = __commonJS((exports, module) => {
6226
6093
  (function(root) {
@@ -6561,8 +6428,8 @@ function jsonRpcSuccess(id, result) {
6561
6428
  function jsonRpcError(id, code, message) {
6562
6429
  return { jsonrpc: "2.0", id, error: { code, message } };
6563
6430
  }
6564
- var ExampleSchema2, ArgSchema2, IoDescriptorSchema2, CommandAuthSchema2, CommandSchema2, AuthProviderSchema2, AuthConfigSchema2, ToolSchemaSchema2, StoredTokenSchema2, JsonRpcErrorSchema2, JsonRpcRequestSchema2, JsonRpcResponseSchema2, McpToolDefSchema2;
6565
- var init_models2 = __esm(() => {
6431
+ var ExampleSchema2, ArgSchema2, IoDescriptorSchema2, CommandAuthSchema2, CommandSchema2, AuthProviderSchema2, AuthConfigSchema2, MTP_SPEC_VERSION2 = "2026-02-07", ToolSchemaSchema2, StoredTokenSchema2, JsonRpcErrorSchema2, JsonRpcRequestSchema2, JsonRpcResponseSchema2, McpToolDefSchema2;
6432
+ var init_models = __esm(() => {
6566
6433
  init_zod();
6567
6434
  ExampleSchema2 = exports_external.object({
6568
6435
  description: exports_external.string().optional(),
@@ -6612,6 +6479,7 @@ var init_models2 = __esm(() => {
6612
6479
  providers: exports_external.array(AuthProviderSchema2)
6613
6480
  });
6614
6481
  ToolSchemaSchema2 = exports_external.object({
6482
+ specVersion: exports_external.string(),
6615
6483
  name: exports_external.string(),
6616
6484
  version: exports_external.string(),
6617
6485
  description: exports_external.string(),
@@ -6705,7 +6573,7 @@ async function getToolSchema(toolName) {
6705
6573
  return null;
6706
6574
  }
6707
6575
  try {
6708
- const { stdout } = await execFileAsync(toolPath, ["--describe"], {
6576
+ const { stdout } = await execFileAsync(toolPath, ["--mtp-describe"], {
6709
6577
  timeout: 5000
6710
6578
  });
6711
6579
  return ToolSchemaSchema2.parse(JSON.parse(stdout.trim()));
@@ -6803,7 +6671,7 @@ async function loadSchemas(toolNames) {
6803
6671
  writeCache(schema.name, schema);
6804
6672
  schemas.push(schema);
6805
6673
  } else {
6806
- process.stderr.write(`warning: could not get --describe from '${name}'
6674
+ process.stderr.write(`warning: could not get --mtp-describe from '${name}'
6807
6675
  `);
6808
6676
  }
6809
6677
  }
@@ -6811,7 +6679,7 @@ async function loadSchemas(toolNames) {
6811
6679
  }
6812
6680
  var import_jaro_winkler, import_which, execFileAsync;
6813
6681
  var init_search = __esm(() => {
6814
- init_models2();
6682
+ init_models();
6815
6683
  import_jaro_winkler = __toESM(require_jaro_winkler(), 1);
6816
6684
  import_which = __toESM(require_lib(), 1);
6817
6685
  execFileAsync = promisify(execFile);
@@ -7457,7 +7325,7 @@ async function getToolSchema2(toolName) {
7457
7325
  return null;
7458
7326
  }
7459
7327
  try {
7460
- const { stdout } = await execFileAsync6(toolPath, ["--describe"], {
7328
+ const { stdout } = await execFileAsync6(toolPath, ["--mtp-describe"], {
7461
7329
  timeout: 5000
7462
7330
  });
7463
7331
  return ToolSchemaSchema2.parse(JSON.parse(stdout.trim()));
@@ -7467,7 +7335,7 @@ async function getToolSchema2(toolName) {
7467
7335
  }
7468
7336
  var import_jaro_winkler2, import_which2, execFileAsync6;
7469
7337
  var init_search2 = __esm(() => {
7470
- init_models2();
7338
+ init_models();
7471
7339
  import_jaro_winkler2 = __toESM(require_jaro_winkler(), 1);
7472
7340
  import_which2 = __toESM(require_lib(), 1);
7473
7341
  execFileAsync6 = promisify8(execFile8);
@@ -8825,9 +8693,12 @@ function readResponse(rl) {
8825
8693
  });
8826
8694
  }
8827
8695
  var init_mcp = __esm(() => {
8828
- init_models2();
8696
+ init_models();
8829
8697
  });
8830
8698
 
8699
+ // src/version.ts
8700
+ var VERSION2 = "1.2.0";
8701
+
8831
8702
  // src/serve.ts
8832
8703
  var exports_serve = {};
8833
8704
  __export(exports_serve, {
@@ -8886,12 +8757,12 @@ function commandToMcpTool(toolName, cmd) {
8886
8757
  if (cmd.stdin.description && typeof prop === "object" && prop !== null) {
8887
8758
  prop.description = cmd.stdin.description;
8888
8759
  }
8889
- properties._stdin = prop;
8760
+ properties["mtp:stdin"] = prop;
8890
8761
  } else {
8891
8762
  const prop = { type: "string" };
8892
8763
  if (cmd.stdin.description)
8893
8764
  prop.description = cmd.stdin.description;
8894
- properties._stdin = prop;
8765
+ properties["mtp:stdin"] = prop;
8895
8766
  }
8896
8767
  }
8897
8768
  const inputSchema = {
@@ -8950,8 +8821,8 @@ function buildCliCommand(toolName, commandName, arguments_, commandSchema) {
8950
8821
  }
8951
8822
  function invokeCliTool(toolName, commandName, arguments_, commandSchema, authEnv) {
8952
8823
  const argsForCli = { ...arguments_ };
8953
- const stdinData = argsForCli._stdin;
8954
- delete argsForCli._stdin;
8824
+ const stdinData = argsForCli["mtp:stdin"];
8825
+ delete argsForCli["mtp:stdin"];
8955
8826
  const stdinStr = stdinData !== undefined ? typeof stdinData === "string" ? stdinData : JSON.stringify(stdinData) : undefined;
8956
8827
  const cmd = buildCliCommand(toolName, commandName, argsForCli, commandSchema);
8957
8828
  return new Promise((resolve) => {
@@ -9020,7 +8891,7 @@ async function handleRequest(state, req) {
9020
8891
  return jsonRpcSuccess(id, {
9021
8892
  protocolVersion: "2024-11-05",
9022
8893
  capabilities: { tools: {} },
9023
- serverInfo: { name: "mtpcli-serve", version: VERSION }
8894
+ serverInfo: { name: "mtpcli-serve", version: VERSION2 }
9024
8895
  });
9025
8896
  case "notifications/initialized":
9026
8897
  return null;
@@ -9062,7 +8933,7 @@ async function run(toolNames) {
9062
8933
  for (const name of toolNames) {
9063
8934
  const schema = await getToolSchema2(name);
9064
8935
  if (!schema)
9065
- throw new Error(`could not get --describe from '${name}'`);
8936
+ throw new Error(`could not get --mtp-describe from '${name}'`);
9066
8937
  if (schema.auth)
9067
8938
  allAuth.set(name, schema.auth);
9068
8939
  for (const cmd of schema.commands) {
@@ -9110,12 +8981,11 @@ async function run(toolNames) {
9110
8981
  }
9111
8982
  }
9112
8983
  var execFileAsync7, TOOL_TIMEOUT_MS = 60000, MAX_OUTPUT_BYTES;
9113
- var init_serve = __esm(async () => {
8984
+ var init_serve = __esm(() => {
9114
8985
  init_auth();
9115
8986
  init_mcp();
9116
- init_models2();
8987
+ init_models();
9117
8988
  init_search2();
9118
- await init_src();
9119
8989
  execFileAsync7 = promisify9(execFile9);
9120
8990
  MAX_OUTPUT_BYTES = 1024 * 1024 * 1024;
9121
8991
  });
@@ -9567,8 +9437,8 @@ function mcpToolToCommand(tool) {
9567
9437
  ...inputSchema.properties ?? {}
9568
9438
  };
9569
9439
  const requiredFields = (inputSchema.required ?? []).filter((v) => typeof v === "string");
9570
- const stdinProp = allProperties._stdin;
9571
- delete allProperties._stdin;
9440
+ const stdinProp = allProperties["mtp:stdin"];
9441
+ delete allProperties["mtp:stdin"];
9572
9442
  let stdin;
9573
9443
  if (stdinProp) {
9574
9444
  const propType = stdinProp.type;
@@ -9684,7 +9554,7 @@ class McpClient {
9684
9554
  client.sendRequest("initialize", {
9685
9555
  protocolVersion: "2024-11-05",
9686
9556
  capabilities: {},
9687
- clientInfo: { name: "mtpcli-wrap", version: VERSION }
9557
+ clientInfo: { name: "mtpcli-wrap", version: VERSION2 }
9688
9558
  });
9689
9559
  await client.readResponse();
9690
9560
  client.sendNotification("notifications/initialized", {});
@@ -9745,7 +9615,7 @@ class HttpMcpClient {
9745
9615
  const initResult = await client.sendRequest("initialize", {
9746
9616
  protocolVersion: "2025-11-25",
9747
9617
  capabilities: {},
9748
- clientInfo: { name: "mtpcli-wrap", version: VERSION }
9618
+ clientInfo: { name: "mtpcli-wrap", version: VERSION2 }
9749
9619
  });
9750
9620
  client.protocolVersion = initResult.protocolVersion ?? "2025-11-25";
9751
9621
  await client.sendNotification("notifications/initialized", {});
@@ -9943,6 +9813,7 @@ async function run2(serverCmd, serverUrl, describeMode, toolName, toolArgs = [],
9943
9813
  const mcpTools = await client.listTools();
9944
9814
  const commands = mcpTools.map(mcpToolToCommand);
9945
9815
  const schema = {
9816
+ specVersion: MTP_SPEC_VERSION2,
9946
9817
  name: serverName,
9947
9818
  version: "0.1.0",
9948
9819
  description: `CLI wrapper for MCP server: ${serverName}`,
@@ -9966,9 +9837,9 @@ async function run2(serverCmd, serverUrl, describeMode, toolName, toolArgs = [],
9966
9837
  const stdinData = Buffer.concat(chunks).toString("utf-8");
9967
9838
  if (stdinData) {
9968
9839
  try {
9969
- parsed._stdin = JSON.parse(stdinData);
9840
+ parsed["mtp:stdin"] = JSON.parse(stdinData);
9970
9841
  } catch {
9971
- parsed._stdin = stdinData;
9842
+ parsed["mtp:stdin"] = stdinData;
9972
9843
  }
9973
9844
  }
9974
9845
  }
@@ -9987,9 +9858,9 @@ async function run2(serverCmd, serverUrl, describeMode, toolName, toolArgs = [],
9987
9858
  client.stop();
9988
9859
  }
9989
9860
  }
9990
- var init_wrap = __esm(async () => {
9861
+ var init_wrap = __esm(() => {
9991
9862
  init_mcp();
9992
- await init_src();
9863
+ init_models();
9993
9864
  });
9994
9865
 
9995
9866
  // src/validate.ts
@@ -10080,7 +9951,7 @@ function crossReferenceHelp(schema, helpText) {
10080
9951
  }
10081
9952
  helpFlags.delete("--help");
10082
9953
  helpFlags.delete("--version");
10083
- helpFlags.delete("--describe");
9954
+ helpFlags.delete("--mtp-describe");
10084
9955
  const declaredFlags = new Set;
10085
9956
  for (const cmd of schema.commands) {
10086
9957
  for (const arg of cmd.args) {
@@ -10094,7 +9965,7 @@ function crossReferenceHelp(schema, helpText) {
10094
9965
  diags.push({
10095
9966
  level: "info",
10096
9967
  code: "HELP_ARG_MISMATCH",
10097
- message: `Flag "${flag}" in --describe but not found in --help`
9968
+ message: `Flag "${flag}" in --mtp-describe but not found in --help`
10098
9969
  });
10099
9970
  }
10100
9971
  }
@@ -10103,7 +9974,7 @@ function crossReferenceHelp(schema, helpText) {
10103
9974
  diags.push({
10104
9975
  level: "info",
10105
9976
  code: "HELP_ARG_MISMATCH",
10106
- message: `Flag "${flag}" in --help but not found in --describe`
9977
+ message: `Flag "${flag}" in --help but not found in --mtp-describe`
10107
9978
  });
10108
9979
  }
10109
9980
  }
@@ -10124,7 +9995,7 @@ async function validateTool(toolName, opts) {
10124
9995
  }
10125
9996
  let describeOutput;
10126
9997
  try {
10127
- const { stdout } = await execFileAsync8(toolPath, ["--describe"], {
9998
+ const { stdout } = await execFileAsync8(toolPath, ["--mtp-describe"], {
10128
9999
  timeout: 1e4
10129
10000
  });
10130
10001
  describeOutput = stdout.trim();
@@ -10132,7 +10003,7 @@ async function validateTool(toolName, opts) {
10132
10003
  diags.push({
10133
10004
  level: "error",
10134
10005
  code: "DESCRIBE_FAILED",
10135
- message: `"${toolName} --describe" produced empty output`
10006
+ message: `"${toolName} --mtp-describe" produced empty output`
10136
10007
  });
10137
10008
  return buildResult(toolName, diags);
10138
10009
  }
@@ -10140,7 +10011,7 @@ async function validateTool(toolName, opts) {
10140
10011
  diags.push({
10141
10012
  level: "error",
10142
10013
  code: "DESCRIBE_FAILED",
10143
- message: `"${toolName} --describe" failed: ${e instanceof Error ? e.message : e}`
10014
+ message: `"${toolName} --mtp-describe" failed: ${e instanceof Error ? e.message : e}`
10144
10015
  });
10145
10016
  return buildResult(toolName, diags);
10146
10017
  }
@@ -10213,7 +10084,7 @@ function printHuman(result) {
10213
10084
  }
10214
10085
  var import_which3, execFileAsync8, VALID_ARG_TYPES;
10215
10086
  var init_validate = __esm(() => {
10216
- init_models2();
10087
+ init_models();
10217
10088
  import_which3 = __toESM(require_lib(), 1);
10218
10089
  execFileAsync8 = promisify10(execFile10);
10219
10090
  VALID_ARG_TYPES = new Set([
@@ -10590,7 +10461,7 @@ async function run4(shell, toolName) {
10590
10461
  }
10591
10462
  const schema = await getToolSchema2(toolName);
10592
10463
  if (!schema) {
10593
- process.stderr.write(`error: could not get --describe from "${toolName}"
10464
+ process.stderr.write(`error: could not get --mtp-describe from "${toolName}"
10594
10465
  `);
10595
10466
  process.exit(1);
10596
10467
  }
@@ -10600,16 +10471,148 @@ var init_completions = __esm(() => {
10600
10471
  init_search2();
10601
10472
  });
10602
10473
 
10474
+ // node_modules/commander/esm.mjs
10475
+ var import__ = __toESM(require_commander(), 1);
10476
+ var {
10477
+ program,
10478
+ createCommand,
10479
+ createArgument,
10480
+ createOption,
10481
+ CommanderError,
10482
+ InvalidArgumentError,
10483
+ InvalidOptionArgumentError,
10484
+ Command,
10485
+ Argument,
10486
+ Option,
10487
+ Help
10488
+ } = import__.default;
10489
+
10490
+ // src/models.ts
10491
+ init_zod();
10492
+ var ExampleSchema = exports_external.object({
10493
+ description: exports_external.string().optional(),
10494
+ command: exports_external.string(),
10495
+ output: exports_external.string().optional()
10496
+ });
10497
+ var ArgSchema = exports_external.object({
10498
+ name: exports_external.string(),
10499
+ type: exports_external.string(),
10500
+ description: exports_external.string().optional(),
10501
+ required: exports_external.boolean().default(false),
10502
+ default: exports_external.any().optional(),
10503
+ values: exports_external.array(exports_external.string()).optional()
10504
+ });
10505
+ var IoDescriptorSchema = exports_external.object({
10506
+ contentType: exports_external.string().optional(),
10507
+ description: exports_external.string().optional(),
10508
+ schema: exports_external.any().optional()
10509
+ });
10510
+ var CommandAuthSchema = exports_external.object({
10511
+ required: exports_external.boolean().default(false),
10512
+ scopes: exports_external.array(exports_external.string()).optional()
10513
+ });
10514
+ var CommandSchema = exports_external.object({
10515
+ name: exports_external.string(),
10516
+ description: exports_external.string(),
10517
+ args: exports_external.array(ArgSchema).default([]),
10518
+ stdin: IoDescriptorSchema.optional(),
10519
+ stdout: IoDescriptorSchema.optional(),
10520
+ examples: exports_external.array(ExampleSchema).default([]),
10521
+ auth: CommandAuthSchema.optional()
10522
+ });
10523
+ var AuthProviderSchema = exports_external.object({
10524
+ id: exports_external.string(),
10525
+ type: exports_external.string(),
10526
+ displayName: exports_external.string().optional(),
10527
+ authorizationUrl: exports_external.string().optional(),
10528
+ tokenUrl: exports_external.string().optional(),
10529
+ scopes: exports_external.array(exports_external.string()).optional(),
10530
+ clientId: exports_external.string().optional(),
10531
+ registrationUrl: exports_external.string().optional(),
10532
+ instructions: exports_external.string().optional()
10533
+ });
10534
+ var AuthConfigSchema = exports_external.object({
10535
+ required: exports_external.boolean().default(false),
10536
+ envVar: exports_external.string(),
10537
+ providers: exports_external.array(AuthProviderSchema)
10538
+ });
10539
+ var MTP_SPEC_VERSION = "2026-02-07";
10540
+ var ToolSchemaSchema = exports_external.object({
10541
+ specVersion: exports_external.string(),
10542
+ name: exports_external.string(),
10543
+ version: exports_external.string(),
10544
+ description: exports_external.string(),
10545
+ auth: AuthConfigSchema.optional(),
10546
+ commands: exports_external.array(CommandSchema)
10547
+ });
10548
+ var StoredTokenSchema = exports_external.object({
10549
+ access_token: exports_external.string(),
10550
+ token_type: exports_external.string().optional(),
10551
+ refresh_token: exports_external.string().optional(),
10552
+ expires_at: exports_external.string().optional(),
10553
+ scopes: exports_external.array(exports_external.string()).optional(),
10554
+ provider_id: exports_external.string(),
10555
+ created_at: exports_external.string()
10556
+ });
10557
+ var JsonRpcErrorSchema = exports_external.object({
10558
+ code: exports_external.number(),
10559
+ message: exports_external.string(),
10560
+ data: exports_external.any().optional()
10561
+ });
10562
+ var JsonRpcRequestSchema = exports_external.object({
10563
+ jsonrpc: exports_external.string(),
10564
+ id: exports_external.any().optional(),
10565
+ method: exports_external.string(),
10566
+ params: exports_external.any().default({})
10567
+ });
10568
+ var JsonRpcResponseSchema = exports_external.object({
10569
+ jsonrpc: exports_external.string(),
10570
+ id: exports_external.any().optional(),
10571
+ result: exports_external.any().optional(),
10572
+ error: JsonRpcErrorSchema.optional()
10573
+ });
10574
+ var McpToolDefSchema = exports_external.object({
10575
+ name: exports_external.string(),
10576
+ description: exports_external.string(),
10577
+ inputSchema: exports_external.any()
10578
+ });
10579
+ function cleanJson(obj) {
10580
+ if (obj === null || obj === undefined)
10581
+ return;
10582
+ if (Array.isArray(obj)) {
10583
+ return obj.map(cleanJson);
10584
+ }
10585
+ if (typeof obj === "object") {
10586
+ const out = {};
10587
+ for (const [k, v] of Object.entries(obj)) {
10588
+ if (v === undefined)
10589
+ continue;
10590
+ if (Array.isArray(v) && v.length === 0)
10591
+ continue;
10592
+ const cleaned = cleanJson(v);
10593
+ if (cleaned !== undefined) {
10594
+ out[k] = cleaned;
10595
+ }
10596
+ }
10597
+ return out;
10598
+ }
10599
+ return obj;
10600
+ }
10601
+
10602
+ // src/version.ts
10603
+ var VERSION = "1.2.0";
10604
+
10603
10605
  // src/index.ts
10604
10606
  function selfDescribe() {
10605
10607
  const schema = {
10608
+ specVersion: MTP_SPEC_VERSION,
10606
10609
  name: "mtpcli",
10607
10610
  version: VERSION,
10608
- description: "Unified CLI for discovering, authenticating, and bridging --describe-compatible tools",
10611
+ description: "Unified CLI for discovering, authenticating, and bridging --mtp-describe-compatible tools",
10609
10612
  commands: [
10610
10613
  {
10611
10614
  name: "search",
10612
- description: "Search across --describe-compatible tools for commands matching a query",
10615
+ description: "Search across --mtp-describe-compatible tools for commands matching a query",
10613
10616
  args: [
10614
10617
  {
10615
10618
  name: "query",
@@ -10806,7 +10809,7 @@ function selfDescribe() {
10806
10809
  name: "--tool",
10807
10810
  type: "array",
10808
10811
  required: true,
10809
- description: "Tool name(s) to serve (must support --describe)"
10812
+ description: "Tool name(s) to serve (must support --mtp-describe)"
10810
10813
  }
10811
10814
  ],
10812
10815
  examples: [
@@ -10822,7 +10825,7 @@ function selfDescribe() {
10822
10825
  },
10823
10826
  {
10824
10827
  name: "wrap",
10825
- description: "Wrap an MCP server as a --describe-compatible CLI",
10828
+ description: "Wrap an MCP server as a --mtp-describe-compatible CLI",
10826
10829
  args: [
10827
10830
  {
10828
10831
  name: "--server",
@@ -10845,9 +10848,9 @@ function selfDescribe() {
10845
10848
  description: "Pre-registered OAuth client ID (for servers without dynamic registration)"
10846
10849
  },
10847
10850
  {
10848
- name: "--describe",
10851
+ name: "--mtp-describe",
10849
10852
  type: "boolean",
10850
- description: "Output --describe JSON"
10853
+ description: "Output --mtp-describe JSON"
10851
10854
  },
10852
10855
  {
10853
10856
  name: "tool_name",
@@ -10858,7 +10861,7 @@ function selfDescribe() {
10858
10861
  examples: [
10859
10862
  {
10860
10863
  description: "Describe a stdio MCP server",
10861
- command: 'mtpcli wrap --server "npx @mcp/server-github" --describe'
10864
+ command: 'mtpcli wrap --server "npx @mcp/server-github" --mtp-describe'
10862
10865
  },
10863
10866
  {
10864
10867
  description: "Call a tool on a stdio server",
@@ -10866,7 +10869,7 @@ function selfDescribe() {
10866
10869
  },
10867
10870
  {
10868
10871
  description: "Describe an HTTP MCP server",
10869
- command: "mtpcli wrap --url http://localhost:3000/mcp --describe"
10872
+ command: "mtpcli wrap --url http://localhost:3000/mcp --mtp-describe"
10870
10873
  },
10871
10874
  {
10872
10875
  description: "Call a tool on an HTTP server",
@@ -10876,7 +10879,7 @@ function selfDescribe() {
10876
10879
  },
10877
10880
  {
10878
10881
  name: "validate",
10879
- description: "Validate a tool's --describe output against the MTP spec",
10882
+ description: "Validate a tool's --mtp-describe output against the MTP spec",
10880
10883
  args: [
10881
10884
  {
10882
10885
  name: "tool",
@@ -10919,7 +10922,7 @@ function selfDescribe() {
10919
10922
  },
10920
10923
  {
10921
10924
  name: "completions",
10922
- description: "Generate shell completions for a --describe-compatible tool",
10925
+ description: "Generate shell completions for a --mtp-describe-compatible tool",
10923
10926
  args: [
10924
10927
  {
10925
10928
  name: "shell",
@@ -10954,126 +10957,122 @@ function selfDescribe() {
10954
10957
  };
10955
10958
  console.log(JSON.stringify(cleanJson(schema), null, 2));
10956
10959
  }
10957
- var VERSION = "1.1.0", program2, authCmd;
10958
- var init_src = __esm(async () => {
10959
- init_esm();
10960
- init_models();
10961
- program2 = new Command().name("mtpcli").version(VERSION).description("Unified CLI for discovering, authenticating, and bridging --describe-compatible tools").option("--describe", "Print self-describing JSON (mtpcli spec)").action(async (opts) => {
10962
- if (opts.describe) {
10963
- selfDescribe();
10964
- return;
10965
- }
10966
- program2.help();
10967
- });
10968
- program2.command("search").description("Search across --describe-compatible tools").argument("<query>", "Search query").option("--json", "Output as JSON", false).option("--scan-path", "Scan PATH for --describe-compatible tools", false).option("--jobs <n>", "Number of parallel jobs for --scan-path", "16").argument("[tools...]", "Tool names to search (after --)").action(async (query, tools, opts) => {
10969
- const { search: search2, loadSchemas: loadSchemas2, scanPath: scanPath2 } = await Promise.resolve().then(() => (init_search(), exports_search));
10970
- const schemas = opts.scanPath ? await scanPath2(parseInt(opts.jobs, 10)) : await loadSchemas2(tools);
10971
- if (schemas.length === 0) {
10972
- process.stderr.write(`no tools found. Try: mtpcli search --scan-path "query"
10960
+ var program2 = new Command().name("mtpcli").version(VERSION).description("Unified CLI for discovering, authenticating, and bridging --mtp-describe-compatible tools").option("--mtp-describe", "Print self-describing JSON (MTP spec)").action(async (opts) => {
10961
+ if (opts.mtpDescribe) {
10962
+ selfDescribe();
10963
+ return;
10964
+ }
10965
+ program2.help();
10966
+ });
10967
+ program2.command("search").description("Search across --mtp-describe-compatible tools").argument("<query>", "Search query").option("--json", "Output as JSON", false).option("--scan-path", "Scan PATH for --mtp-describe-compatible tools", false).option("--jobs <n>", "Number of parallel jobs for --scan-path", "16").argument("[tools...]", "Tool names to search (after --)").action(async (query, tools, opts) => {
10968
+ const { search: search2, loadSchemas: loadSchemas2, scanPath: scanPath2 } = await Promise.resolve().then(() => (init_search(), exports_search));
10969
+ const schemas = opts.scanPath ? await scanPath2(parseInt(opts.jobs, 10)) : await loadSchemas2(tools);
10970
+ if (schemas.length === 0) {
10971
+ process.stderr.write(`no tools found. Try: mtpcli search --scan-path "query"
10973
10972
  `);
10974
- return;
10975
- }
10976
- const results = search2(query, schemas);
10977
- if (results.length === 0) {
10978
- process.stderr.write(`no results for "${query}"
10973
+ return;
10974
+ }
10975
+ const results = search2(query, schemas);
10976
+ if (results.length === 0) {
10977
+ process.stderr.write(`no results for "${query}"
10979
10978
  `);
10980
- return;
10981
- }
10982
- if (opts.json) {
10983
- console.log(JSON.stringify(results, null, 2));
10984
- } else {
10985
- for (const r of results) {
10986
- console.log(`${r.score.toFixed(1).padStart(6)} ${r.tool} ${r.command} ${r.description}`);
10987
- }
10988
- }
10989
- });
10990
- authCmd = program2.command("auth").description("Manage authentication for tools");
10991
- authCmd.command("login").description("Log in to a tool").argument("[tool]", "Tool name").option("--provider <id>", "Specific provider ID").option("--token <value>", "API key / bearer token (skip OAuth flow)").option("--url <url>", "HTTP MCP server URL (triggers OAuth discovery)").option("--client-id <id>", "Pre-registered OAuth client ID (for --url)").action(async (tool, opts) => {
10992
- if (opts.url) {
10993
- const { mcpOAuthFlow: mcpOAuthFlow3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
10994
- await mcpOAuthFlow3(opts.url, "", opts.clientId);
10995
- return;
10979
+ return;
10980
+ }
10981
+ if (opts.json) {
10982
+ console.log(JSON.stringify(results, null, 2));
10983
+ } else {
10984
+ for (const r of results) {
10985
+ console.log(`${r.score.toFixed(1).padStart(6)} ${r.tool} ${r.command} ${r.description}`);
10996
10986
  }
10997
- if (!tool) {
10998
- process.stderr.write(`error: tool name is required (or use --url)
10987
+ }
10988
+ });
10989
+ var authCmd = program2.command("auth").description("Manage authentication for tools");
10990
+ authCmd.command("login").description("Log in to a tool").argument("[tool]", "Tool name").option("--provider <id>", "Specific provider ID").option("--token <value>", "API key / bearer token (skip OAuth flow)").option("--url <url>", "HTTP MCP server URL (triggers OAuth discovery)").option("--client-id <id>", "Pre-registered OAuth client ID (for --url)").action(async (tool, opts) => {
10991
+ if (opts.url) {
10992
+ const { mcpOAuthFlow: mcpOAuthFlow3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
10993
+ await mcpOAuthFlow3(opts.url, "", opts.clientId);
10994
+ return;
10995
+ }
10996
+ if (!tool) {
10997
+ process.stderr.write(`error: tool name is required (or use --url)
10999
10998
  `);
11000
- process.exit(1);
11001
- }
11002
- const { runLogin: runLogin3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11003
- await runLogin3(tool, opts.provider, opts.token);
11004
- });
11005
- authCmd.command("logout").description("Log out from a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11006
- if (opts.url) {
11007
- const { mcpAuthLogout: mcpAuthLogout3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11008
- const deleted = mcpAuthLogout3(opts.url);
11009
- if (deleted) {
11010
- process.stderr.write(`Logged out from ${opts.url}
10999
+ process.exit(1);
11000
+ }
11001
+ const { runLogin: runLogin3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11002
+ await runLogin3(tool, opts.provider, opts.token);
11003
+ });
11004
+ authCmd.command("logout").description("Log out from a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11005
+ if (opts.url) {
11006
+ const { mcpAuthLogout: mcpAuthLogout3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11007
+ const deleted = mcpAuthLogout3(opts.url);
11008
+ if (deleted) {
11009
+ process.stderr.write(`Logged out from ${opts.url}
11011
11010
  `);
11012
- } else {
11013
- process.stderr.write(`No tokens found for ${opts.url}
11011
+ } else {
11012
+ process.stderr.write(`No tokens found for ${opts.url}
11014
11013
  `);
11015
- }
11016
- return;
11017
11014
  }
11018
- if (!tool) {
11019
- process.stderr.write(`error: tool name is required (or use --url)
11015
+ return;
11016
+ }
11017
+ if (!tool) {
11018
+ process.stderr.write(`error: tool name is required (or use --url)
11020
11019
  `);
11021
- process.exit(1);
11022
- }
11023
- const { runLogout: runLogout3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11024
- await runLogout3(tool);
11025
- });
11026
- authCmd.command("status").description("Show auth status for a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11027
- if (opts.url) {
11028
- const { mcpAuthStatus: mcpAuthStatus3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11029
- console.log(JSON.stringify(mcpAuthStatus3(opts.url), null, 2));
11030
- return;
11031
- }
11032
- if (!tool) {
11033
- process.stderr.write(`error: tool name is required (or use --url)
11020
+ process.exit(1);
11021
+ }
11022
+ const { runLogout: runLogout3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11023
+ await runLogout3(tool);
11024
+ });
11025
+ authCmd.command("status").description("Show auth status for a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11026
+ if (opts.url) {
11027
+ const { mcpAuthStatus: mcpAuthStatus3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11028
+ console.log(JSON.stringify(mcpAuthStatus3(opts.url), null, 2));
11029
+ return;
11030
+ }
11031
+ if (!tool) {
11032
+ process.stderr.write(`error: tool name is required (or use --url)
11034
11033
  `);
11035
- process.exit(1);
11036
- }
11037
- const { runStatus: runStatus3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11038
- await runStatus3(tool);
11039
- });
11040
- authCmd.command("token").description("Print the access token for a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11041
- if (opts.url) {
11042
- const { mcpAuthToken: mcpAuthToken3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11043
- const t = await mcpAuthToken3(opts.url);
11044
- if (!t) {
11045
- throw new Error(`no valid token for '${opts.url}'. Run: mtpcli auth login --url ${opts.url}`);
11046
- }
11047
- console.log(t);
11048
- return;
11049
- }
11050
- if (!tool) {
11051
- process.stderr.write(`error: tool name is required (or use --url)
11034
+ process.exit(1);
11035
+ }
11036
+ const { runStatus: runStatus3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11037
+ await runStatus3(tool);
11038
+ });
11039
+ authCmd.command("token").description("Print the access token for a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11040
+ if (opts.url) {
11041
+ const { mcpAuthToken: mcpAuthToken3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11042
+ const t = await mcpAuthToken3(opts.url);
11043
+ if (!t) {
11044
+ throw new Error(`no valid token for '${opts.url}'. Run: mtpcli auth login --url ${opts.url}`);
11045
+ }
11046
+ console.log(t);
11047
+ return;
11048
+ }
11049
+ if (!tool) {
11050
+ process.stderr.write(`error: tool name is required (or use --url)
11052
11051
  `);
11053
- process.exit(1);
11054
- }
11055
- const { runToken: runToken3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11056
- await runToken3(tool);
11057
- });
11058
- authCmd.command("env").description("Print shell export statement for eval").argument("<tool>", "Tool name").action(async (tool) => {
11059
- const { runEnv: runEnv3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11060
- await runEnv3(tool);
11061
- });
11062
- authCmd.command("refresh").description("Force-refresh the stored OAuth token for a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11063
- if (opts.url) {
11064
- const { mcpAuthRefresh: mcpAuthRefresh3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11065
- await mcpAuthRefresh3(opts.url);
11066
- return;
11067
- }
11068
- if (!tool) {
11069
- process.stderr.write(`error: tool name is required (or use --url)
11052
+ process.exit(1);
11053
+ }
11054
+ const { runToken: runToken3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11055
+ await runToken3(tool);
11056
+ });
11057
+ authCmd.command("env").description("Print shell export statement for eval").argument("<tool>", "Tool name").action(async (tool) => {
11058
+ const { runEnv: runEnv3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11059
+ await runEnv3(tool);
11060
+ });
11061
+ authCmd.command("refresh").description("Force-refresh the stored OAuth token for a tool").argument("[tool]", "Tool name").option("--url <url>", "HTTP MCP server URL").action(async (tool, opts) => {
11062
+ if (opts.url) {
11063
+ const { mcpAuthRefresh: mcpAuthRefresh3 } = await Promise.resolve().then(() => (init_mcp_oauth(), exports_mcp_oauth));
11064
+ await mcpAuthRefresh3(opts.url);
11065
+ return;
11066
+ }
11067
+ if (!tool) {
11068
+ process.stderr.write(`error: tool name is required (or use --url)
11070
11069
  `);
11071
- process.exit(1);
11072
- }
11073
- const { runRefresh: runRefresh3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11074
- await runRefresh3(tool);
11075
- });
11076
- program2.command("serve").description("Serve CLI tools as an MCP server (cli2mcp bridge)").requiredOption("--tool <names...>", "Tool(s) to serve").addHelpText("after", `
11070
+ process.exit(1);
11071
+ }
11072
+ const { runRefresh: runRefresh3 } = await Promise.resolve().then(() => (init_auth2(), exports_auth2));
11073
+ await runRefresh3(tool);
11074
+ });
11075
+ program2.command("serve").description("Serve CLI tools as an MCP server (cli2mcp bridge)").requiredOption("--tool <names...>", "Tool(s) to serve").addHelpText("after", `
11077
11076
  This command is meant to be used as an MCP server, not run directly.
11078
11077
  Add it to your MCP client config (e.g. ~/.claude.json):
11079
11078
 
@@ -11087,12 +11086,12 @@ Add it to your MCP client config (e.g. ~/.claude.json):
11087
11086
  }
11088
11087
  }
11089
11088
 
11090
- Any CLI tool on your PATH that supports --describe can be served.
11089
+ Any CLI tool on your PATH that supports --mtp-describe can be served.
11091
11090
  Multiple tools can be combined into a single MCP server:
11092
11091
 
11093
11092
  mtpcli serve --tool tool1 --tool tool2`).action(async (opts) => {
11094
- if (process.stdin.isTTY) {
11095
- process.stderr.write(`Error: 'mtpcli serve' is an MCP server and should not be run directly.
11093
+ if (process.stdin.isTTY) {
11094
+ process.stderr.write(`Error: 'mtpcli serve' is an MCP server and should not be run directly.
11096
11095
  ` + `Add it to your MCP client config instead. For example, in ~/.claude.json:
11097
11096
 
11098
11097
  ` + ` {
@@ -11107,57 +11106,51 @@ Multiple tools can be combined into a single MCP server:
11107
11106
 
11108
11107
  ` + `Run 'mtpcli serve --help' for more details.
11109
11108
  `);
11110
- process.exit(1);
11111
- }
11112
- const { run: run5 } = await init_serve().then(() => exports_serve);
11113
- await run5(opts.tool);
11114
- });
11115
- program2.command("wrap").description("Wrap an MCP server as a CLI tool (mcp2cli bridge)").option("--server <cmd>", "MCP server command to run (stdio transport)").option("--url <url>", "MCP server URL (Streamable HTTP / SSE transport)").option("-H, --header <header...>", "HTTP header(s) for --url (e.g. 'Authorization: Bearer tok')").option("--client-id <id>", "Pre-registered OAuth client ID (for --url)").option("--describe", "Output --describe JSON instead of invoking", false).argument("[tool_name]", "Tool name to invoke").argument("[args...]", "Arguments for the tool (after --)").action(async (toolName, args, opts) => {
11116
- if (opts.server && opts.url) {
11117
- process.stderr.write(`error: --server and --url are mutually exclusive
11118
- `);
11119
- process.exit(1);
11120
- }
11121
- if (!opts.server && !opts.url) {
11122
- process.stderr.write(`error: one of --server or --url is required
11109
+ process.exit(1);
11110
+ }
11111
+ const { run: run5 } = await Promise.resolve().then(() => (init_serve(), exports_serve));
11112
+ await run5(opts.tool);
11113
+ });
11114
+ program2.command("wrap").description("Wrap an MCP server as a CLI tool (mcp2cli bridge)").option("--server <cmd>", "MCP server command to run (stdio transport)").option("--url <url>", "MCP server URL (Streamable HTTP / SSE transport)").option("-H, --header <header...>", "HTTP header(s) for --url (e.g. 'Authorization: Bearer tok')").option("--client-id <id>", "Pre-registered OAuth client ID (for --url)").option("--mtp-describe", "Output --mtp-describe JSON instead of invoking", false).argument("[tool_name]", "Tool name to invoke").argument("[args...]", "Arguments for the tool (after --)").action(async (toolName, args, opts) => {
11115
+ if (opts.server && opts.url) {
11116
+ process.stderr.write(`error: --server and --url are mutually exclusive
11123
11117
  `);
11124
- process.exit(1);
11125
- }
11126
- if (opts.header && !opts.url) {
11127
- process.stderr.write(`error: --header requires --url
11118
+ process.exit(1);
11119
+ }
11120
+ if (!opts.server && !opts.url) {
11121
+ process.stderr.write(`error: one of --server or --url is required
11128
11122
  `);
11129
- process.exit(1);
11130
- }
11131
- if (opts.clientId && !opts.url) {
11132
- process.stderr.write(`error: --client-id requires --url
11123
+ process.exit(1);
11124
+ }
11125
+ if (opts.header && !opts.url) {
11126
+ process.stderr.write(`error: --header requires --url
11133
11127
  `);
11134
- process.exit(1);
11135
- }
11136
- const { run: run5 } = await init_wrap().then(() => exports_wrap);
11137
- await run5(opts.server, opts.url, opts.describe, toolName, args, opts.header ?? [], opts.clientId);
11138
- });
11139
- program2.command("validate").description("Validate a tool's --describe output against the MTP spec").argument("[tool]", "Tool name to validate").option("--json", "Output as JSON", false).option("--stdin", "Read JSON from stdin", false).option("--skip-help", "Skip --help cross-reference", false).action(async (tool, opts) => {
11140
- const { run: run5 } = await Promise.resolve().then(() => (init_validate(), exports_validate));
11141
- await run5(tool, {
11142
- json: opts.json,
11143
- stdin: opts.stdin,
11144
- skipHelp: opts.skipHelp
11145
- });
11146
- });
11147
- program2.command("completions").description("Generate shell completions from --describe output").argument("<shell>", "Shell type (bash, zsh, fish)").argument("<tool>", "Tool name").action(async (shell, tool) => {
11148
- const { run: run5 } = await Promise.resolve().then(() => (init_completions(), exports_completions));
11149
- await run5(shell, tool);
11150
- });
11151
- try {
11152
- await program2.parseAsync(process.argv);
11153
- } catch (e) {
11154
- process.stderr.write(`error: ${e instanceof Error ? e.message : e}
11128
+ process.exit(1);
11129
+ }
11130
+ if (opts.clientId && !opts.url) {
11131
+ process.stderr.write(`error: --client-id requires --url
11155
11132
  `);
11156
11133
  process.exit(1);
11157
11134
  }
11135
+ const { run: run5 } = await Promise.resolve().then(() => (init_wrap(), exports_wrap));
11136
+ await run5(opts.server, opts.url, opts.mtpDescribe, toolName, args, opts.header ?? [], opts.clientId);
11158
11137
  });
11159
- await init_src();
11160
-
11161
- export {
11162
- VERSION
11163
- };
11138
+ program2.command("validate").description("Validate a tool's --mtp-describe output against the MTP spec").argument("[tool]", "Tool name to validate").option("--json", "Output as JSON", false).option("--stdin", "Read JSON from stdin", false).option("--skip-help", "Skip --help cross-reference", false).action(async (tool, opts) => {
11139
+ const { run: run5 } = await Promise.resolve().then(() => (init_validate(), exports_validate));
11140
+ await run5(tool, {
11141
+ json: opts.json,
11142
+ stdin: opts.stdin,
11143
+ skipHelp: opts.skipHelp
11144
+ });
11145
+ });
11146
+ program2.command("completions").description("Generate shell completions from --mtp-describe output").argument("<shell>", "Shell type (bash, zsh, fish)").argument("<tool>", "Tool name").action(async (shell, tool) => {
11147
+ const { run: run5 } = await Promise.resolve().then(() => (init_completions(), exports_completions));
11148
+ await run5(shell, tool);
11149
+ });
11150
+ try {
11151
+ await program2.parseAsync(process.argv);
11152
+ } catch (e) {
11153
+ process.stderr.write(`error: ${e instanceof Error ? e.message : e}
11154
+ `);
11155
+ process.exit(1);
11156
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modeltoolsprotocol/mtpcli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "bin": {