@evantahler/mcpx 0.15.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 (106) hide show
  1. package/.claude/settings.local.json +18 -0
  2. package/.claude/skills/mcpx.md +165 -0
  3. package/.claude/worktrees/elastic-jennings/.claude/settings.local.json +18 -0
  4. package/.claude/worktrees/elastic-jennings/.claude/skills/mcpcli.md +93 -0
  5. package/.claude/worktrees/elastic-jennings/.github/workflows/auto-release.yml +117 -0
  6. package/.claude/worktrees/elastic-jennings/.github/workflows/ci.yml +18 -0
  7. package/.claude/worktrees/elastic-jennings/.prettierignore +4 -0
  8. package/.claude/worktrees/elastic-jennings/.prettierrc +7 -0
  9. package/.claude/worktrees/elastic-jennings/CLAUDE.md +19 -0
  10. package/.claude/worktrees/elastic-jennings/LICENSE +21 -0
  11. package/.claude/worktrees/elastic-jennings/README.md +487 -0
  12. package/.claude/worktrees/elastic-jennings/bun.lock +381 -0
  13. package/.claude/worktrees/elastic-jennings/install.sh +55 -0
  14. package/.claude/worktrees/elastic-jennings/package.json +56 -0
  15. package/.claude/worktrees/elastic-jennings/src/cli.ts +39 -0
  16. package/.claude/worktrees/elastic-jennings/src/client/http.ts +100 -0
  17. package/.claude/worktrees/elastic-jennings/src/client/manager.ts +266 -0
  18. package/.claude/worktrees/elastic-jennings/src/client/oauth.ts +299 -0
  19. package/.claude/worktrees/elastic-jennings/src/client/stdio.ts +12 -0
  20. package/.claude/worktrees/elastic-jennings/src/commands/add.ts +155 -0
  21. package/.claude/worktrees/elastic-jennings/src/commands/auth.ts +114 -0
  22. package/.claude/worktrees/elastic-jennings/src/commands/exec.ts +91 -0
  23. package/.claude/worktrees/elastic-jennings/src/commands/index.ts +62 -0
  24. package/.claude/worktrees/elastic-jennings/src/commands/info.ts +38 -0
  25. package/.claude/worktrees/elastic-jennings/src/commands/list.ts +30 -0
  26. package/.claude/worktrees/elastic-jennings/src/commands/remove.ts +67 -0
  27. package/.claude/worktrees/elastic-jennings/src/commands/search.ts +45 -0
  28. package/.claude/worktrees/elastic-jennings/src/commands/skill.ts +70 -0
  29. package/.claude/worktrees/elastic-jennings/src/config/env.ts +41 -0
  30. package/.claude/worktrees/elastic-jennings/src/config/loader.ts +156 -0
  31. package/.claude/worktrees/elastic-jennings/src/config/schemas.ts +137 -0
  32. package/.claude/worktrees/elastic-jennings/src/context.ts +53 -0
  33. package/.claude/worktrees/elastic-jennings/src/output/formatter.ts +316 -0
  34. package/.claude/worktrees/elastic-jennings/src/output/logger.ts +114 -0
  35. package/.claude/worktrees/elastic-jennings/src/search/index.ts +69 -0
  36. package/.claude/worktrees/elastic-jennings/src/search/indexer.ts +92 -0
  37. package/.claude/worktrees/elastic-jennings/src/search/keyword.ts +86 -0
  38. package/.claude/worktrees/elastic-jennings/src/search/semantic.ts +75 -0
  39. package/.claude/worktrees/elastic-jennings/src/search/staleness.ts +8 -0
  40. package/.claude/worktrees/elastic-jennings/src/validation/schema.ts +77 -0
  41. package/.claude/worktrees/elastic-jennings/test/cli.test.ts +51 -0
  42. package/.claude/worktrees/elastic-jennings/test/client/manager.test.ts +249 -0
  43. package/.claude/worktrees/elastic-jennings/test/client/oauth.test.ts +328 -0
  44. package/.claude/worktrees/elastic-jennings/test/commands/add-remove.test.ts +253 -0
  45. package/.claude/worktrees/elastic-jennings/test/commands/exec.test.ts +105 -0
  46. package/.claude/worktrees/elastic-jennings/test/commands/info.test.ts +48 -0
  47. package/.claude/worktrees/elastic-jennings/test/commands/list.test.ts +39 -0
  48. package/.claude/worktrees/elastic-jennings/test/commands/skill.test.ts +98 -0
  49. package/.claude/worktrees/elastic-jennings/test/config/env.test.ts +61 -0
  50. package/.claude/worktrees/elastic-jennings/test/config/loader.test.ts +139 -0
  51. package/.claude/worktrees/elastic-jennings/test/fixtures/.keep +0 -0
  52. package/.claude/worktrees/elastic-jennings/test/fixtures/auth.json +10 -0
  53. package/.claude/worktrees/elastic-jennings/test/fixtures/mock-config/.keep +0 -0
  54. package/.claude/worktrees/elastic-jennings/test/fixtures/mock-config/servers.json +8 -0
  55. package/.claude/worktrees/elastic-jennings/test/fixtures/mock-server.ts +113 -0
  56. package/.claude/worktrees/elastic-jennings/test/fixtures/search.json +15 -0
  57. package/.claude/worktrees/elastic-jennings/test/fixtures/servers.json +18 -0
  58. package/.claude/worktrees/elastic-jennings/test/integration/stdio-server.test.ts +149 -0
  59. package/.claude/worktrees/elastic-jennings/test/output/formatter.test.ts +54 -0
  60. package/.claude/worktrees/elastic-jennings/test/output/logger.test.ts +89 -0
  61. package/.claude/worktrees/elastic-jennings/test/search/indexer.test.ts +32 -0
  62. package/.claude/worktrees/elastic-jennings/test/search/keyword.test.ts +80 -0
  63. package/.claude/worktrees/elastic-jennings/test/search/semantic.test.ts +32 -0
  64. package/.claude/worktrees/elastic-jennings/test/validation/schema.test.ts +113 -0
  65. package/.claude/worktrees/elastic-jennings/tsconfig.json +29 -0
  66. package/.cursor/rules/mcpx.mdc +165 -0
  67. package/LICENSE +21 -0
  68. package/README.md +627 -0
  69. package/package.json +58 -0
  70. package/src/cli.ts +72 -0
  71. package/src/client/browser.ts +24 -0
  72. package/src/client/debug-fetch.ts +81 -0
  73. package/src/client/elicitation.ts +368 -0
  74. package/src/client/http.ts +25 -0
  75. package/src/client/manager.ts +566 -0
  76. package/src/client/oauth.ts +314 -0
  77. package/src/client/sse.ts +17 -0
  78. package/src/client/stdio.ts +12 -0
  79. package/src/client/trace.ts +184 -0
  80. package/src/commands/add.ts +179 -0
  81. package/src/commands/auth.ts +114 -0
  82. package/src/commands/exec.ts +156 -0
  83. package/src/commands/index.ts +62 -0
  84. package/src/commands/info.ts +63 -0
  85. package/src/commands/list.ts +64 -0
  86. package/src/commands/ping.ts +69 -0
  87. package/src/commands/prompt.ts +60 -0
  88. package/src/commands/remove.ts +67 -0
  89. package/src/commands/resource.ts +46 -0
  90. package/src/commands/search.ts +49 -0
  91. package/src/commands/servers.ts +66 -0
  92. package/src/commands/skill.ts +112 -0
  93. package/src/commands/task.ts +82 -0
  94. package/src/config/env.ts +41 -0
  95. package/src/config/loader.ts +156 -0
  96. package/src/config/schemas.ts +152 -0
  97. package/src/context.ts +62 -0
  98. package/src/lib/input.ts +36 -0
  99. package/src/output/formatter.ts +884 -0
  100. package/src/output/logger.ts +173 -0
  101. package/src/search/index.ts +69 -0
  102. package/src/search/indexer.ts +92 -0
  103. package/src/search/keyword.ts +86 -0
  104. package/src/search/semantic.ts +75 -0
  105. package/src/search/staleness.ts +8 -0
  106. package/src/validation/schema.ts +103 -0
@@ -0,0 +1,487 @@
1
+ # mcpcli
2
+
3
+ A command-line interface for MCP servers. **curl for MCP.**
4
+
5
+ Two audiences:
6
+
7
+ 1. **AI/LLM agents** that prefer shelling out over maintaining persistent MCP connections — better for token management, progressive tool discovery, and sharing a single pool of MCP servers across multiple agents on one machine
8
+ 2. **MCP developers** who need a fast way to discover, debug, and test their servers from the terminal
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ # Via bun
14
+ bun install -g @evantahler/mcpcli
15
+
16
+ # Via curl
17
+ curl -fsSL https://raw.githubusercontent.com/evantahler/mcpcli/main/install.sh | bash
18
+ ```
19
+
20
+ The curl installer downloads a pre-built binary — no runtime needed. The bun install method requires [Bun](https://bun.sh).
21
+
22
+ ## Quick Start
23
+
24
+ ```bash
25
+ # List all servers and their tools
26
+ mcpcli
27
+
28
+ # List with descriptions
29
+ mcpcli -d
30
+
31
+ # Inspect a server
32
+ mcpcli info github
33
+
34
+ # Inspect a specific tool
35
+ mcpcli info github search_repositories
36
+
37
+ # Execute a tool
38
+ mcpcli exec github search_repositories '{"query": "mcp server"}'
39
+
40
+ # Search tools — combines keyword and semantic matching
41
+ mcpcli search "post a ticket to linear"
42
+
43
+ # Search with only keyword/glob matching (fast, no embeddings)
44
+ mcpcli search -k "*file*"
45
+
46
+ # Search with only semantic matching
47
+ mcpcli search -q "manage pull requests"
48
+ ```
49
+
50
+ ## Commands
51
+
52
+ | Command | Description |
53
+ | ------------------------------------ | -------------------------------------------- |
54
+ | `mcpcli` | List all configured servers and tools |
55
+ | `mcpcli info <server>` | Show tools for a server |
56
+ | `mcpcli info <server> <tool>` | Show tool schema |
57
+ | `mcpcli search <query>` | Search tools (keyword + semantic) |
58
+ | `mcpcli search -k <pattern>` | Keyword/glob search only |
59
+ | `mcpcli search -q <query>` | Semantic search only |
60
+ | `mcpcli index` | Build/rebuild the search index |
61
+ | `mcpcli index -i` | Show index status |
62
+ | `mcpcli exec <server> <tool> [json]` | Validate inputs locally, then execute tool |
63
+ | `mcpcli exec <server>` | List available tools for a server |
64
+ | `mcpcli auth <server>` | Authenticate with an HTTP MCP server (OAuth) |
65
+ | `mcpcli auth <server> -s` | Check auth status and token TTL |
66
+ | `mcpcli auth <server> -r` | Force token refresh |
67
+ | `mcpcli deauth <server>` | Remove stored authentication for a server |
68
+ | `mcpcli add <name> --command <cmd>` | Add a stdio MCP server to your config |
69
+ | `mcpcli add <name> --url <url>` | Add an HTTP MCP server to your config |
70
+ | `mcpcli remove <name>` | Remove an MCP server from your config |
71
+ | `mcpcli skill install --claude` | Install the mcpcli skill for Claude Code |
72
+
73
+ ## Options
74
+
75
+ | Flag | Purpose |
76
+ | ------------------------- | -------------------------------------------------- |
77
+ | `-h, --help` | Show help |
78
+ | `-V, --version` | Show version |
79
+ | `-d, --with-descriptions` | Include tool descriptions in list output |
80
+ | `-c, --config <path>` | Specify config file location |
81
+ | `-v, --verbose` | Show HTTP request/response headers and timing |
82
+ | `-S, --show-secrets` | Show full auth tokens in verbose output (unmasked) |
83
+ | `-j, --json` | Force JSON output (default when piped) |
84
+
85
+ ## Managing Servers
86
+
87
+ Add and remove servers from the CLI — no manual JSON editing required.
88
+
89
+ ```bash
90
+ # Add a stdio server
91
+ mcpcli add filesystem --command npx --args "-y,@modelcontextprotocol/server-filesystem,/tmp"
92
+
93
+ # Add an HTTP server with headers
94
+ mcpcli add my-api --url https://api.example.com/mcp --header "Authorization:Bearer tok123"
95
+
96
+ # Add with tool filtering
97
+ mcpcli add github --url https://mcp.github.com --allowed-tools "search_*,get_*"
98
+
99
+ # Add with environment variables
100
+ mcpcli add my-server --command node --args "server.js" --env "API_KEY=sk-123,DEBUG=true"
101
+
102
+ # Overwrite an existing server
103
+ mcpcli add filesystem --command echo --force
104
+
105
+ # Remove a server (also cleans up auth.json)
106
+ mcpcli remove filesystem
107
+
108
+ # Remove but keep stored auth credentials
109
+ mcpcli remove my-api --keep-auth
110
+
111
+ # Preview what would be removed
112
+ mcpcli remove my-api --dry-run
113
+ ```
114
+
115
+ **`add` options:**
116
+
117
+ | Flag | Purpose |
118
+ | -------------------------- | -------------------------------------- |
119
+ | `--command <cmd>` | Command to run (stdio server) |
120
+ | `--args <a1,a2,...>` | Comma-separated arguments |
121
+ | `--env <KEY=VAL,...>` | Comma-separated environment variables |
122
+ | `--cwd <dir>` | Working directory for the command |
123
+ | `--url <url>` | Server URL (HTTP server) |
124
+ | `--header <Key:Value>` | HTTP header (repeatable) |
125
+ | `--allowed-tools <t1,t2>` | Comma-separated allowed tool patterns |
126
+ | `--disabled-tools <t1,t2>` | Comma-separated disabled tool patterns |
127
+ | `-f, --force` | Overwrite if server already exists |
128
+
129
+ **`remove` options:**
130
+
131
+ | Flag | Purpose |
132
+ | ------------- | ------------------------------------------------- |
133
+ | `--keep-auth` | Don't remove stored auth credentials |
134
+ | `--dry-run` | Show what would be removed without changing files |
135
+
136
+ ## Configuration
137
+
138
+ Config lives in `~/.mcpcli/` (or the current directory). Three files:
139
+
140
+ ### `servers.json` — MCP Server Definitions
141
+
142
+ Standard MCP server config format. Supports both stdio and HTTP servers.
143
+
144
+ ```json
145
+ {
146
+ "mcpServers": {
147
+ "filesystem": {
148
+ "command": "npx",
149
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
150
+ "env": { "API_KEY": "${API_KEY}" },
151
+ "allowedTools": ["read_file", "list_directory"],
152
+ "disabledTools": ["delete_file"]
153
+ },
154
+ "github": {
155
+ "url": "https://mcp.github.com"
156
+ },
157
+ "internal-api": {
158
+ "url": "https://mcp.internal.example.com",
159
+ "headers": { "Authorization": "Bearer ${TOKEN}" }
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ **Stdio servers** — `command` + `args`, spawned as child processes
166
+ **HTTP servers** — `url`, with optional static `headers` for pre-shared tokens. OAuth is auto-discovered at connection time via `.well-known/oauth-authorization-server` — no config needed.
167
+
168
+ Environment variables are interpolated via `${VAR_NAME}` syntax. Set `MCP_STRICT_ENV=false` to warn instead of error on missing variables.
169
+
170
+ **Tool filtering:**
171
+
172
+ - `allowedTools` — glob patterns for tools to expose (whitelist)
173
+ - `disabledTools` — glob patterns for tools to hide (blacklist, takes precedence)
174
+
175
+ ### `auth.json` — OAuth Token Storage (managed automatically)
176
+
177
+ Stores OAuth tokens for HTTP MCP servers. You don't edit this directly — managed automatically.
178
+
179
+ ```json
180
+ {
181
+ "github": {
182
+ "access_token": "gho_xxxx",
183
+ "refresh_token": "ghr_xxxx",
184
+ "expires_at": "2026-03-03T12:00:00Z",
185
+ "token_type": "bearer",
186
+ "scope": "repo,read:org"
187
+ },
188
+ "linear": {
189
+ "access_token": "lin_xxxx",
190
+ "refresh_token": "lin_ref_xxxx",
191
+ "expires_at": "2026-03-04T08:30:00Z",
192
+ "token_type": "bearer"
193
+ }
194
+ }
195
+ ```
196
+
197
+ Tokens are automatically refreshed when expired (if a refresh token is available). Any command that connects to a server (`exec`, `info`, `search`, listing) will refresh tokens transparently. `mcpcli auth <server> --status` shows current token state and TTL.
198
+
199
+ ### `search.json` — Semantic Search Index (managed automatically)
200
+
201
+ Contains every discovered tool with metadata for semantic search. Built and updated automatically — any command that connects to a server will detect new/changed tools and re-index them in the background.
202
+
203
+ ```json
204
+ {
205
+ "version": 1,
206
+ "indexed_at": "2026-03-03T10:00:00Z",
207
+ "embedding_model": "Xenova/all-MiniLM-L6-v2",
208
+ "tools": [
209
+ {
210
+ "server": "linear",
211
+ "tool": "createIssue",
212
+ "description": "Create a new issue in Linear",
213
+ "input_schema": { "...": "..." },
214
+ "scenarios": ["Create a new issue in Linear", "create issue"],
215
+ "keywords": ["create", "issue"],
216
+ "embedding": [0.012, -0.034, "..."]
217
+ }
218
+ ]
219
+ }
220
+ ```
221
+
222
+ Each tool gets:
223
+
224
+ - **scenarios** — the tool description plus a keyword phrase derived from the tool name
225
+ - **keywords** — terms extracted by splitting the tool name on `_`, `-`, and camelCase boundaries
226
+ - **embedding** — 384-dim vector for cosine similarity search
227
+
228
+ Scenarios and keywords are extracted heuristically from tool names and descriptions. Embeddings are generated in-process using `Xenova/all-MiniLM-L6-v2` (~23MB ONNX model, downloaded on first run). No API keys needed.
229
+
230
+ ## Config Resolution Order
231
+
232
+ 1. `MCP_CONFIG_PATH` environment variable
233
+ 2. `-c / --config` flag
234
+ 3. `./servers.json` (current directory)
235
+ 4. `~/.mcpcli/servers.json`
236
+
237
+ ## Environment Variables
238
+
239
+ | Variable | Purpose | Default |
240
+ | ----------------- | --------------------------- | ------------ |
241
+ | `MCP_CONFIG_PATH` | Config directory path | `~/.mcpcli/` |
242
+ | `MCP_DEBUG` | Enable debug output | `false` |
243
+ | `MCP_TIMEOUT` | Request timeout (seconds) | `1800` |
244
+ | `MCP_CONCURRENCY` | Parallel server connections | `5` |
245
+ | `MCP_MAX_RETRIES` | Retry attempts | `3` |
246
+ | `MCP_STRICT_ENV` | Error on missing `${VAR}` | `true` |
247
+
248
+ ## OAuth Flow
249
+
250
+ For HTTP MCP servers that require OAuth:
251
+
252
+ ```bash
253
+ # Start the OAuth flow — opens browser for authorization
254
+ mcpcli auth github
255
+
256
+ # Check token status
257
+ mcpcli auth github -s
258
+ # => github: authenticated (expires in 47m)
259
+
260
+ # Force re-authentication
261
+ mcpcli auth github -r
262
+ ```
263
+
264
+ The OAuth flow:
265
+
266
+ 1. Discovers the server's OAuth metadata via `/.well-known/oauth-authorization-server`
267
+ 2. Starts a local callback server on a random port
268
+ 3. Opens the browser for user authorization
269
+ 4. Exchanges the authorization code for tokens
270
+ 5. Stores tokens in `auth.json`
271
+ 6. Automatically refreshes tokens before they expire on any subsequent command
272
+
273
+ ## Search
274
+
275
+ `mcpcli search` is a single command that combines keyword matching and semantic vector search. By default, both strategies run and results are merged.
276
+
277
+ ```bash
278
+ # Combined search (default) — keyword hits + semantic matches, merged and ranked
279
+ mcpcli search "send a message to slack"
280
+ # => slack/postMessage (0.94) Post a message to a channel
281
+ # => slack/sendDirectMessage (0.87) Send a DM to a user
282
+ # => teams/sendMessage (0.72) Send a Teams message
283
+
284
+ # Keyword only — fast glob match against tool names, descriptions, and keywords
285
+ mcpcli search -k "*pull*request*"
286
+ # => github/createPullRequest
287
+ # => github/getPullRequest
288
+ # => github/mergePullRequest
289
+
290
+ # Semantic only — vector similarity against intent
291
+ mcpcli search -q "review someone's code changes"
292
+ # => github/submitPullRequestReview (0.91) Submit a PR review
293
+ # => github/getPullRequest (0.85) Get PR details
294
+ # => github/listPullRequestCommits (0.78) List commits in a PR
295
+ ```
296
+
297
+ The combined search pipeline:
298
+
299
+ 1. **Keyword match** — glob/substring against tool names, descriptions, and indexed keywords
300
+ 2. **Semantic match** — embed the query, cosine similarity against tool embeddings
301
+ 3. **Merge & rank** — combine both result sets, deduplicate, sort by score
302
+ 4. **Return** — top results with similarity scores
303
+
304
+ The index updates incrementally — only new or changed tools are re-indexed. The first run indexes everything; subsequent runs are fast.
305
+
306
+ ## Debugging with Verbose Mode
307
+
308
+ `-v` shows HTTP request/response details, like `curl -v`. Debug output goes to stderr so piping to `jq` still works.
309
+
310
+ ```bash
311
+ # See full HTTP traffic
312
+ mcpcli -v exec arcade Gmail_WhoAmI
313
+
314
+ # > POST https://api.arcade.dev/mcp/evan-coding
315
+ # > authorization: Bearer eyJhbGci...
316
+ # > content-type: application/json
317
+ # > accept: application/json, text/event-stream
318
+ # >
319
+ # {
320
+ # "method": "tools/call",
321
+ # "params": {
322
+ # "name": "Gmail_WhoAmI",
323
+ # "arguments": {}
324
+ # }
325
+ # }
326
+ # < 200 OK (142ms)
327
+ # < content-type: application/json
328
+ # < x-request-id: abc123
329
+ # <
330
+ # { "content": [ ... ] }
331
+
332
+ # Debug on stderr, clean JSON on stdout
333
+ mcpcli -v exec arcade Gmail_WhoAmI | jq .
334
+
335
+ # Show full auth tokens (unmasked)
336
+ mcpcli -v -S call arcade Gmail_WhoAmI
337
+ ```
338
+
339
+ The `>` / `<` convention matches curl — `>` for request, `<` for response. The JSON-RPC body is shown between the request headers and response, without a prefix. Timing is displayed on the response status line.
340
+
341
+ ## Input Validation
342
+
343
+ `mcpcli exec` validates tool arguments locally before sending them to the server. MCP tools advertise a JSON Schema for their inputs — mcpcli uses this to catch errors fast, without a round-trip.
344
+
345
+ ```bash
346
+ # Missing required field — caught locally
347
+ mcpcli exec github create_issue '{"title": "bug"}'
348
+ # => error: missing required field "repo" (github/create_issue)
349
+
350
+ # Wrong type — caught locally
351
+ mcpcli exec github create_issue '{"repo": "foo", "title": 123}'
352
+ # => error: "title" must be a string, got number (github/create_issue)
353
+
354
+ # Valid — sent to server
355
+ mcpcli exec github create_issue '{"repo": "foo", "title": "bug"}'
356
+ # => { ... }
357
+ ```
358
+
359
+ Validation covers:
360
+
361
+ - **Required fields** — errors before sending if any are missing
362
+ - **Type checking** — string, number, boolean, array, object
363
+ - **Enum values** — rejects values not in the allowed set
364
+ - **Nested objects** — validates recursively
365
+
366
+ If a tool's `inputSchema` is unavailable (some servers don't provide one), execution proceeds without local validation.
367
+
368
+ ## Shell Output & Piping
369
+
370
+ Output is human-friendly by default, JSON when piped:
371
+
372
+ ```bash
373
+ # Human-readable
374
+ mcpcli info github
375
+
376
+ # JSON (piped)
377
+ mcpcli info github | jq '.tools[].name'
378
+
379
+ # Force JSON
380
+ mcpcli info github --json
381
+ ```
382
+
383
+ Tool results are always JSON, designed for chaining:
384
+
385
+ ```bash
386
+ # Search repos and read the first result
387
+ mcpcli exec github search_repositories '{"query":"mcp"}' \
388
+ | jq -r '.content[0].text | fromjson | .items[0].full_name' \
389
+ | xargs -I {} mcpcli exec github get_file_contents '{"owner":"{}","path":"README.md"}'
390
+
391
+ # Conditional execution
392
+ mcpcli exec filesystem list_directory '{"path":"."}' \
393
+ | jq -e '.content[0].text | contains("package.json")' \
394
+ && mcpcli exec filesystem read_file '{"path":"./package.json"}'
395
+ ```
396
+
397
+ Stdin works for tool arguments:
398
+
399
+ ```bash
400
+ echo '{"path":"./README.md"}' | mcpcli exec filesystem read_file
401
+
402
+ cat params.json | mcpcli exec server tool
403
+ ```
404
+
405
+ ## Agent Integration
406
+
407
+ ### Claude Code Skill
408
+
409
+ mcpcli ships a Claude Code skill at `.claude/skills/mcpcli.md` that teaches Claude Code how to discover and use MCP tools. Install it:
410
+
411
+ ```bash
412
+ # Install to the current project (.claude/skills/mcpcli.md)
413
+ mcpcli skill install --claude
414
+
415
+ # Install globally (~/.claude/skills/mcpcli.md)
416
+ mcpcli skill install --claude --global
417
+
418
+ # Install to both locations
419
+ mcpcli skill install --claude --global --project
420
+
421
+ # Overwrite an existing skill file
422
+ mcpcli skill install --claude --force
423
+ ```
424
+
425
+ Then in any Claude Code session, the agent can use `/mcpcli` or the skill triggers automatically when the agent needs to interact with external services. The skill instructs the agent to:
426
+
427
+ 1. **Search first** — `mcpcli search "<intent>"` to find relevant tools
428
+ 2. **Inspect** — `mcpcli info <server> <tool>` to get the schema before calling
429
+ 3. **Execute** — `mcpcli exec <server> <tool> '<json>'` to execute
430
+
431
+ This keeps tool schemas out of the system prompt entirely. The agent discovers what it needs on-demand, saving tokens and context window space.
432
+
433
+ ### Raw System Prompt (other agents)
434
+
435
+ For non-Claude-Code agents, add this to the system prompt:
436
+
437
+ ```
438
+ You have access to MCP tools via the `mcpcli` CLI.
439
+
440
+ To discover tools:
441
+ mcpcli search "<what you want to do>" # combined keyword + semantic
442
+ mcpcli search -k "<pattern>" # keyword/glob only
443
+ mcpcli info <server> <tool> # tool schema
444
+
445
+ To execute tools:
446
+ mcpcli exec <server> <tool> '<json args>'
447
+
448
+ Always search before executing — don't assume tool names.
449
+ ```
450
+
451
+ ## Development
452
+
453
+ ```bash
454
+ # Install dependencies
455
+ bun install
456
+
457
+ # Run in development
458
+ bun run dev
459
+
460
+ # Run tests
461
+ bun test
462
+
463
+ # Build single binary
464
+ bun run build
465
+
466
+ # Lint
467
+ bun lint
468
+ ```
469
+
470
+ ## Tech Stack
471
+
472
+ | Layer | Choice |
473
+ | ----------- | ----------------------------------------------------- |
474
+ | Runtime | Bun |
475
+ | Language | TypeScript |
476
+ | MCP Client | `@modelcontextprotocol/sdk` |
477
+ | CLI Parsing | `commander` |
478
+ | Validation | `ajv` (JSON Schema) |
479
+ | Embeddings | `@huggingface/transformers` (Xenova/all-MiniLM-L6-v2) |
480
+
481
+ ## Inspiration
482
+
483
+ Inspired by [mcp-cli](https://github.com/philschmid/mcp-cli) by Phil Schmid, which nails the core DX of a shell-friendly MCP client. mcpcli extends that foundation with OAuth support for HTTP servers and semantic tool search.
484
+
485
+ ## License
486
+
487
+ MIT