@tronsfey/ucli 0.5.0 → 0.5.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 CHANGED
@@ -172,6 +172,8 @@ ucli run --service <name> --operation <operationId> [options]
172
172
  | `--params` | No | JSON string of parameters (path, query, body merged) |
173
173
  | `--format` | No | Output format: `json` (default), `table`, `yaml` |
174
174
  | `--query` | No | JMESPath expression to filter the response |
175
+ | `--machine` | No | Structured JSON envelope output (agent-friendly) |
176
+ | `--dry-run` | No | Preview the HTTP request without executing (implies `--machine`) |
175
177
 
176
178
  **Examples:**
177
179
 
@@ -193,6 +195,13 @@ ucli run --service inventory --operation listProducts \
193
195
  # POST with data from file
194
196
  ucli run --service crm --operation createContact \
195
197
  --params "@./contact.json"
198
+
199
+ # Agent-friendly structured output
200
+ ucli run --service payments --operation listTransactions --machine
201
+
202
+ # Preview request without executing
203
+ ucli run --service payments --operation createPayment --dry-run \
204
+ --data '{"amount": 5000, "currency": "USD"}'
196
205
  ```
197
206
 
198
207
  ---
@@ -226,6 +235,32 @@ ucli mcp tools <server-name> [--format table|json]
226
235
 
227
236
  ---
228
237
 
238
+ ### `mcp describe <server> <tool>`
239
+
240
+ Show detailed parameter schema for a tool on a MCP server.
241
+
242
+ ```bash
243
+ ucli mcp describe <server-name> <tool-name> [--json]
244
+ ```
245
+
246
+ | Argument/Flag | Description |
247
+ |---------------|-------------|
248
+ | `<server-name>` | MCP server name from `mcp list` |
249
+ | `<tool-name>` | Tool name from `mcp tools` |
250
+ | `--json` | Output full schema as JSON (for agent consumption) |
251
+
252
+ **Examples:**
253
+
254
+ ```bash
255
+ # Human-readable tool description
256
+ ucli mcp describe weather get_forecast
257
+
258
+ # JSON schema (for agent introspection)
259
+ ucli mcp describe weather get_forecast --json
260
+ ```
261
+
262
+ ---
263
+
229
264
  ### `mcp run <server> <tool> [args...]`
230
265
 
231
266
  Execute a tool on an MCP server.
@@ -234,16 +269,27 @@ Execute a tool on an MCP server.
234
269
  ucli mcp run <server-name> <tool-name> [args...]
235
270
  ```
236
271
 
237
- Args are passed as `key=value` pairs and converted to a JSON object.
272
+ Args are passed as `key=value` pairs and converted to a JSON object, or use `--input-json` for direct JSON input.
273
+
274
+ | Flag | Description |
275
+ |------|-------------|
276
+ | `--json` | Machine-readable JSON output |
277
+ | `--input-json` | Pass tool arguments as a JSON object (preferred for agents) |
238
278
 
239
279
  **Examples:**
240
280
 
241
281
  ```bash
242
- # Call a weather tool
282
+ # Call a weather tool with key=value args
243
283
  ucli mcp run weather get_forecast location="New York" units=metric
244
284
 
245
285
  # Call a search tool
246
286
  ucli mcp run search-server web_search query="ucli MCP" limit=5
287
+
288
+ # Call with JSON input (preferred for agents)
289
+ ucli mcp run weather get_forecast --input-json '{"location": "New York", "units": "metric"}'
290
+
291
+ # Get structured JSON output
292
+ ucli mcp run weather get_forecast --json location="New York"
247
293
  ```
248
294
 
249
295
  ---
@@ -314,23 +360,35 @@ ucli services list --format json
314
360
  # Step 2: Inspect a service to see available operations
315
361
  ucli services info <service-name> --format json
316
362
 
317
- # Step 3: Execute an operation
363
+ # Step 3: Preview a request (dry-run — no execution)
364
+ ucli run --service <name> --operation <operationId> --dry-run \
365
+ --params '{ ... }'
366
+
367
+ # Step 4: Execute an operation with structured output
318
368
  ucli run --service <name> --operation <operationId> \
319
- --params '{ ... }' --format json
369
+ --params '{ ... }' --machine
320
370
 
321
- # Step 4: Filter results with JMESPath
371
+ # Step 5: Filter results with JMESPath
322
372
  ucli run --service inventory --operation listProducts \
323
373
  --query 'items[?inStock == `true`] | [0:5]'
324
374
 
325
- # Step 5: Chain operations (use output from one as input to another)
375
+ # Step 6: Chain operations (use output from one as input to another)
326
376
  PRODUCT_ID=$(ucli run --service inventory --operation listProducts \
327
377
  --query 'items[0].id' | tr -d '"')
328
378
  ucli run --service orders --operation createOrder \
329
379
  --params "{\"productId\": \"$PRODUCT_ID\", \"quantity\": 1}"
380
+
381
+ # Step 7: MCP — describe a tool, then call it with JSON input
382
+ ucli mcp describe weather get_forecast --json
383
+ ucli mcp run weather get_forecast --input-json '{"location": "New York", "units": "metric"}'
330
384
  ```
331
385
 
332
386
  **Tips for agents:**
333
387
  - Always run `services list` first to discover what's available
388
+ - Use `--machine` for structured envelope output from API operations
389
+ - Use `--dry-run` to preview requests before executing destructive operations
390
+ - Use `mcp describe <server> <tool> --json` to discover tool parameters
391
+ - Use `--input-json` for MCP tool calls (more reliable than `key=value` for complex args)
334
392
  - Use `--format json` for programmatic parsing
335
393
  - Use `--query` with JMESPath to extract specific fields
336
394
  - Check pagination fields (`nextPage`, `totalCount`) for list operations
package/README.zh.md CHANGED
@@ -172,6 +172,8 @@ ucli run --service <name> --operation <operationId> [选项]
172
172
  | `--params` | 否 | JSON 字符串(路径参数、查询参数、请求体合并传入) |
173
173
  | `--format` | 否 | 输出格式:`json`(默认)、`table`、`yaml` |
174
174
  | `--query` | 否 | JMESPath 表达式,用于过滤响应 |
175
+ | `--machine` | 否 | 结构化 JSON 信封输出(Agent 友好模式) |
176
+ | `--dry-run` | 否 | 预览 HTTP 请求但不执行(隐含 `--machine`) |
175
177
 
176
178
  **示例:**
177
179
 
@@ -193,6 +195,13 @@ ucli run --service inventory --operation listProducts \
193
195
  # 从文件读取参数
194
196
  ucli run --service crm --operation createContact \
195
197
  --params "@./contact.json"
198
+
199
+ # Agent 友好结构化输出
200
+ ucli run --service payments --operation listTransactions --machine
201
+
202
+ # 预览请求但不执行
203
+ ucli run --service payments --operation createPayment --dry-run \
204
+ --data '{"amount": 5000, "currency": "CNY"}'
196
205
  ```
197
206
 
198
207
  ---
@@ -217,6 +226,32 @@ ucli mcp tools <server-name> [--format table|json]
217
226
 
218
227
  ---
219
228
 
229
+ ### `mcp describe <server> <tool>`
230
+
231
+ 查看 MCP 服务器上指定工具的详细参数模式。
232
+
233
+ ```bash
234
+ ucli mcp describe <server-name> <tool-name> [--json]
235
+ ```
236
+
237
+ | 参数 | 说明 |
238
+ |------|------|
239
+ | `<server-name>` | MCP 服务器名称(来自 `mcp list`) |
240
+ | `<tool-name>` | 工具名称(来自 `mcp tools`) |
241
+ | `--json` | 以 JSON 格式输出完整模式(适合 Agent 消费) |
242
+
243
+ **示例:**
244
+
245
+ ```bash
246
+ # 人类可读的工具描述
247
+ ucli mcp describe weather get_forecast
248
+
249
+ # JSON 模式(适合 Agent 内省)
250
+ ucli mcp describe weather get_forecast --json
251
+ ```
252
+
253
+ ---
254
+
220
255
  ### `mcp run <server> <tool> [args...]`
221
256
 
222
257
  在 MCP 服务器上执行指定工具。
@@ -225,7 +260,12 @@ ucli mcp tools <server-name> [--format table|json]
225
260
  ucli mcp run <server-name> <tool-name> [args...]
226
261
  ```
227
262
 
228
- 参数以 `key=value` 形式传入。
263
+ 参数以 `key=value` 形式传入,或使用 `--input-json` 直接传入 JSON 对象。
264
+
265
+ | 参数 | 说明 |
266
+ |------|------|
267
+ | `--json` | 结构化 JSON 输出 |
268
+ | `--input-json` | 以 JSON 对象形式传入工具参数(Agent 推荐) |
229
269
 
230
270
  **示例:**
231
271
 
@@ -235,6 +275,12 @@ ucli mcp run weather get_forecast location="北京" units=metric
235
275
 
236
276
  # 调用搜索工具
237
277
  ucli mcp run search-server web_search query="ucli MCP" limit=5
278
+
279
+ # 以 JSON 输入调用(Agent 推荐)
280
+ ucli mcp run weather get_forecast --input-json '{"location": "北京", "units": "metric"}'
281
+
282
+ # 获取结构化 JSON 输出
283
+ ucli mcp run weather get_forecast --json location="北京"
238
284
  ```
239
285
 
240
286
  ---
@@ -305,23 +351,35 @@ ucli services list --format json
305
351
  # 第二步:查看服务支持的操作
306
352
  ucli services info <service-name> --format json
307
353
 
308
- # 第三步:执行操作
354
+ # 第三步:预览请求(dry-run,不执行)
355
+ ucli run --service <name> --operation <operationId> --dry-run \
356
+ --params '{ ... }'
357
+
358
+ # 第四步:执行操作并获取结构化输出
309
359
  ucli run --service <name> --operation <operationId> \
310
- --params '{ ... }' --format json
360
+ --params '{ ... }' --machine
311
361
 
312
- # 第四步:用 JMESPath 过滤结果
362
+ # 第五步:用 JMESPath 过滤结果
313
363
  ucli run --service inventory --operation listProducts \
314
364
  --query 'items[?inStock == `true`] | [0:5]'
315
365
 
316
- # 第五步:链式操作(将前一个结果作为下一个的输入)
366
+ # 第六步:链式操作(将前一个结果作为下一个的输入)
317
367
  PRODUCT_ID=$(ucli run --service inventory --operation listProducts \
318
368
  --query 'items[0].id' | tr -d '"')
319
369
  ucli run --service orders --operation createOrder \
320
370
  --params "{\"productId\": \"$PRODUCT_ID\", \"quantity\": 1}"
371
+
372
+ # 第七步:MCP — 查看工具参数模式,然后以 JSON 输入调用
373
+ ucli mcp describe weather get_forecast --json
374
+ ucli mcp run weather get_forecast --input-json '{"location": "北京", "units": "metric"}'
321
375
  ```
322
376
 
323
377
  **智能体使用建议:**
324
378
  - 始终先运行 `services list` 发现可用服务
379
+ - 使用 `--machine` 获取结构化信封输出
380
+ - 使用 `--dry-run` 预览请求,避免误操作
381
+ - 使用 `mcp describe <server> <tool> --json` 发现工具参数模式
382
+ - 使用 `--input-json` 调用 MCP 工具(适合复杂或嵌套参数)
325
383
  - 使用 `--format json` 方便程序解析
326
384
  - 使用 `--query` 配合 JMESPath 提取特定字段
327
385
  - 注意列表操作的分页字段(`nextPage`、`totalCount`)
@@ -36662,9 +36662,97 @@ var require_streamableHttp = __commonJS({
36662
36662
  }
36663
36663
  });
36664
36664
 
36665
- // ../../node_modules/.pnpm/@tronsfey+mcp2cli@1.0.1_zod@4.3.6/node_modules/@tronsfey/mcp2cli/dist/client/index.js
36665
+ // ../../node_modules/.pnpm/@tronsfey+mcp2cli@1.3.0_zod@4.3.6/node_modules/@tronsfey/mcp2cli/package.json
36666
+ var require_package = __commonJS({
36667
+ "../../node_modules/.pnpm/@tronsfey+mcp2cli@1.3.0_zod@4.3.6/node_modules/@tronsfey/mcp2cli/package.json"(exports, module) {
36668
+ module.exports = {
36669
+ name: "@tronsfey/mcp2cli",
36670
+ version: "1.3.0",
36671
+ description: "Command-line proxy for any MCP server \u2014 call tools directly from the terminal",
36672
+ main: "dist/index.js",
36673
+ bin: {
36674
+ mcp2cli: "./bin/mcp2cli",
36675
+ ucli: "./bin/mcp2cli"
36676
+ },
36677
+ files: [
36678
+ "dist/",
36679
+ "bin/",
36680
+ "CLAUDE.md",
36681
+ "README.md",
36682
+ "LICENSE"
36683
+ ],
36684
+ keywords: [
36685
+ "mcp",
36686
+ "model-context-protocol",
36687
+ "cli",
36688
+ "proxy",
36689
+ "commander",
36690
+ "typescript",
36691
+ "ai",
36692
+ "tools"
36693
+ ],
36694
+ author: "",
36695
+ license: "MIT",
36696
+ repository: {
36697
+ type: "git",
36698
+ url: "https://github.com/tronsfey928/mcp2cli.git"
36699
+ },
36700
+ homepage: "https://github.com/tronsfey928/mcp2cli#readme",
36701
+ bugs: {
36702
+ url: "https://github.com/tronsfey928/mcp2cli/issues"
36703
+ },
36704
+ engines: {
36705
+ node: ">=18"
36706
+ },
36707
+ scripts: {
36708
+ build: "tsc",
36709
+ dev: "ts-node src/index.ts",
36710
+ start: "node dist/index.js",
36711
+ test: "jest --testPathIgnorePatterns=tests/integration",
36712
+ "test:coverage": "jest --coverage --testPathIgnorePatterns=tests/integration",
36713
+ "test:e2e": "npm run build && jest --testPathPattern=tests/integration --testTimeout=30000 --runInBand --forceExit",
36714
+ lint: "tsc --noEmit",
36715
+ clean: "rm -rf dist",
36716
+ prepublishOnly: "npm run lint && npm test && npm run build"
36717
+ },
36718
+ dependencies: {
36719
+ "@modelcontextprotocol/sdk": "^1.0.0",
36720
+ chalk: "^4.1.2",
36721
+ commander: "^12.1.0",
36722
+ "fs-extra": "^11.2.0",
36723
+ jmespath: "^0.16.0",
36724
+ ora: "^5.4.1"
36725
+ },
36726
+ devDependencies: {
36727
+ "@modelcontextprotocol/server-filesystem": "^2026.1.14",
36728
+ "@types/express": "^4.17.25",
36729
+ "@types/fs-extra": "^11.0.4",
36730
+ "@types/jest": "^29.5.14",
36731
+ "@types/jmespath": "^0.15.2",
36732
+ "@types/node": "^22.0.0",
36733
+ jest: "^29.7.0",
36734
+ "ts-jest": "^29.4.0",
36735
+ "ts-node": "^10.9.2",
36736
+ typescript: "^5.7.3",
36737
+ zod: "^3.25.76"
36738
+ },
36739
+ jest: {
36740
+ preset: "ts-jest",
36741
+ testEnvironment: "node",
36742
+ testMatch: [
36743
+ "**/tests/**/*.test.ts"
36744
+ ],
36745
+ collectCoverageFrom: [
36746
+ "src/**/*.ts"
36747
+ ]
36748
+ }
36749
+ };
36750
+ }
36751
+ });
36752
+
36753
+ // ../../node_modules/.pnpm/@tronsfey+mcp2cli@1.3.0_zod@4.3.6/node_modules/@tronsfey/mcp2cli/dist/client/index.js
36666
36754
  var require_client3 = __commonJS({
36667
- "../../node_modules/.pnpm/@tronsfey+mcp2cli@1.0.1_zod@4.3.6/node_modules/@tronsfey/mcp2cli/dist/client/index.js"(exports) {
36755
+ "../../node_modules/.pnpm/@tronsfey+mcp2cli@1.3.0_zod@4.3.6/node_modules/@tronsfey/mcp2cli/dist/client/index.js"(exports) {
36668
36756
  Object.defineProperty(exports, "__esModule", { value: true });
36669
36757
  exports.parseCommand = parseCommand;
36670
36758
  exports.isTransportUnsupported = isTransportUnsupported;
@@ -36673,6 +36761,7 @@ var require_client3 = __commonJS({
36673
36761
  var stdio_js_1 = require_stdio2();
36674
36762
  var sse_js_1 = require_sse();
36675
36763
  var streamableHttp_js_1 = require_streamableHttp();
36764
+ var pkg = require_package();
36676
36765
  function parseCommand(cmdString) {
36677
36766
  const parts = [];
36678
36767
  let current = "";
@@ -36698,13 +36787,16 @@ var require_client3 = __commonJS({
36698
36787
  if (inSingle || inDouble) {
36699
36788
  throw new Error(`Unclosed quote in command: ${cmdString}`);
36700
36789
  }
36790
+ if (parts.length === 0) {
36791
+ throw new Error("Empty command string");
36792
+ }
36701
36793
  const [command, ...args] = parts;
36702
36794
  return { command, args };
36703
36795
  }
36704
36796
  function makeClient() {
36705
36797
  return new index_js_1.Client({
36706
36798
  name: "mcp2cli",
36707
- version: "1.0.0"
36799
+ version: pkg.version
36708
36800
  });
36709
36801
  }
36710
36802
  function isTransportUnsupported(err) {
@@ -36724,11 +36816,14 @@ var require_client3 = __commonJS({
36724
36816
  ...Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== void 0)),
36725
36817
  ...config.env ?? {}
36726
36818
  };
36819
+ if (verbose) {
36820
+ console.error(`[debug] Connecting via stdio: ${command} ${args.join(" ")}`);
36821
+ }
36727
36822
  const client2 = makeClient();
36728
36823
  const transport = new stdio_js_1.StdioClientTransport({ command, args, env });
36729
36824
  await client2.connect(transport);
36730
36825
  if (verbose) {
36731
- console.error(`[mcp2cli] Connected via stdio: ${config.command}`);
36826
+ console.error(`[debug] Connected via stdio successfully`);
36732
36827
  }
36733
36828
  return client2;
36734
36829
  }
@@ -36737,6 +36832,9 @@ var require_client3 = __commonJS({
36737
36832
  }
36738
36833
  const serverUrl = new URL(config.url);
36739
36834
  const headers = config.headers ?? {};
36835
+ if (verbose) {
36836
+ console.error(`[debug] Attempting Streamable HTTP connection to ${config.url}`);
36837
+ }
36740
36838
  try {
36741
36839
  const client2 = makeClient();
36742
36840
  const transport = new streamableHttp_js_1.StreamableHTTPClientTransport(serverUrl, {
@@ -36744,28 +36842,34 @@ var require_client3 = __commonJS({
36744
36842
  });
36745
36843
  await client2.connect(transport);
36746
36844
  if (verbose) {
36747
- console.error(`[mcp2cli] Connected via Streamable HTTP: ${config.url}`);
36845
+ console.error(`[debug] Connected via Streamable HTTP successfully`);
36748
36846
  }
36749
36847
  return client2;
36750
36848
  } catch (err) {
36849
+ if (verbose) {
36850
+ console.error(`[debug] Streamable HTTP failed: ${err.message}`);
36851
+ }
36751
36852
  if (!isTransportUnsupported(err)) {
36752
36853
  throw err;
36753
36854
  }
36754
36855
  if (verbose) {
36755
- console.error(`[mcp2cli] Streamable HTTP not supported, falling back to SSE`);
36856
+ console.error(`[debug] Falling back to SSE transport\u2026`);
36756
36857
  }
36757
36858
  }
36859
+ if (verbose) {
36860
+ console.error(`[debug] Attempting SSE connection to ${config.url}`);
36861
+ }
36758
36862
  const client = makeClient();
36759
36863
  const sseTransport = new sse_js_1.SSEClientTransport(serverUrl, {
36760
36864
  requestInit: { headers }
36761
36865
  });
36762
36866
  await client.connect(sseTransport);
36763
36867
  if (verbose) {
36764
- console.error(`[mcp2cli] Connected via SSE: ${config.url}`);
36868
+ console.error(`[debug] Connected via SSE successfully`);
36765
36869
  }
36766
36870
  return client;
36767
36871
  }
36768
36872
  }
36769
36873
  });
36770
36874
  export default require_client3();
36771
- //# sourceMappingURL=client-3I7XBDJU.js.map
36875
+ //# sourceMappingURL=client-Y6NONDCI.js.map