@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.
- package/.claude/settings.local.json +18 -0
- package/.claude/skills/mcpx.md +165 -0
- package/.claude/worktrees/elastic-jennings/.claude/settings.local.json +18 -0
- package/.claude/worktrees/elastic-jennings/.claude/skills/mcpcli.md +93 -0
- package/.claude/worktrees/elastic-jennings/.github/workflows/auto-release.yml +117 -0
- package/.claude/worktrees/elastic-jennings/.github/workflows/ci.yml +18 -0
- package/.claude/worktrees/elastic-jennings/.prettierignore +4 -0
- package/.claude/worktrees/elastic-jennings/.prettierrc +7 -0
- package/.claude/worktrees/elastic-jennings/CLAUDE.md +19 -0
- package/.claude/worktrees/elastic-jennings/LICENSE +21 -0
- package/.claude/worktrees/elastic-jennings/README.md +487 -0
- package/.claude/worktrees/elastic-jennings/bun.lock +381 -0
- package/.claude/worktrees/elastic-jennings/install.sh +55 -0
- package/.claude/worktrees/elastic-jennings/package.json +56 -0
- package/.claude/worktrees/elastic-jennings/src/cli.ts +39 -0
- package/.claude/worktrees/elastic-jennings/src/client/http.ts +100 -0
- package/.claude/worktrees/elastic-jennings/src/client/manager.ts +266 -0
- package/.claude/worktrees/elastic-jennings/src/client/oauth.ts +299 -0
- package/.claude/worktrees/elastic-jennings/src/client/stdio.ts +12 -0
- package/.claude/worktrees/elastic-jennings/src/commands/add.ts +155 -0
- package/.claude/worktrees/elastic-jennings/src/commands/auth.ts +114 -0
- package/.claude/worktrees/elastic-jennings/src/commands/exec.ts +91 -0
- package/.claude/worktrees/elastic-jennings/src/commands/index.ts +62 -0
- package/.claude/worktrees/elastic-jennings/src/commands/info.ts +38 -0
- package/.claude/worktrees/elastic-jennings/src/commands/list.ts +30 -0
- package/.claude/worktrees/elastic-jennings/src/commands/remove.ts +67 -0
- package/.claude/worktrees/elastic-jennings/src/commands/search.ts +45 -0
- package/.claude/worktrees/elastic-jennings/src/commands/skill.ts +70 -0
- package/.claude/worktrees/elastic-jennings/src/config/env.ts +41 -0
- package/.claude/worktrees/elastic-jennings/src/config/loader.ts +156 -0
- package/.claude/worktrees/elastic-jennings/src/config/schemas.ts +137 -0
- package/.claude/worktrees/elastic-jennings/src/context.ts +53 -0
- package/.claude/worktrees/elastic-jennings/src/output/formatter.ts +316 -0
- package/.claude/worktrees/elastic-jennings/src/output/logger.ts +114 -0
- package/.claude/worktrees/elastic-jennings/src/search/index.ts +69 -0
- package/.claude/worktrees/elastic-jennings/src/search/indexer.ts +92 -0
- package/.claude/worktrees/elastic-jennings/src/search/keyword.ts +86 -0
- package/.claude/worktrees/elastic-jennings/src/search/semantic.ts +75 -0
- package/.claude/worktrees/elastic-jennings/src/search/staleness.ts +8 -0
- package/.claude/worktrees/elastic-jennings/src/validation/schema.ts +77 -0
- package/.claude/worktrees/elastic-jennings/test/cli.test.ts +51 -0
- package/.claude/worktrees/elastic-jennings/test/client/manager.test.ts +249 -0
- package/.claude/worktrees/elastic-jennings/test/client/oauth.test.ts +328 -0
- package/.claude/worktrees/elastic-jennings/test/commands/add-remove.test.ts +253 -0
- package/.claude/worktrees/elastic-jennings/test/commands/exec.test.ts +105 -0
- package/.claude/worktrees/elastic-jennings/test/commands/info.test.ts +48 -0
- package/.claude/worktrees/elastic-jennings/test/commands/list.test.ts +39 -0
- package/.claude/worktrees/elastic-jennings/test/commands/skill.test.ts +98 -0
- package/.claude/worktrees/elastic-jennings/test/config/env.test.ts +61 -0
- package/.claude/worktrees/elastic-jennings/test/config/loader.test.ts +139 -0
- package/.claude/worktrees/elastic-jennings/test/fixtures/.keep +0 -0
- package/.claude/worktrees/elastic-jennings/test/fixtures/auth.json +10 -0
- package/.claude/worktrees/elastic-jennings/test/fixtures/mock-config/.keep +0 -0
- package/.claude/worktrees/elastic-jennings/test/fixtures/mock-config/servers.json +8 -0
- package/.claude/worktrees/elastic-jennings/test/fixtures/mock-server.ts +113 -0
- package/.claude/worktrees/elastic-jennings/test/fixtures/search.json +15 -0
- package/.claude/worktrees/elastic-jennings/test/fixtures/servers.json +18 -0
- package/.claude/worktrees/elastic-jennings/test/integration/stdio-server.test.ts +149 -0
- package/.claude/worktrees/elastic-jennings/test/output/formatter.test.ts +54 -0
- package/.claude/worktrees/elastic-jennings/test/output/logger.test.ts +89 -0
- package/.claude/worktrees/elastic-jennings/test/search/indexer.test.ts +32 -0
- package/.claude/worktrees/elastic-jennings/test/search/keyword.test.ts +80 -0
- package/.claude/worktrees/elastic-jennings/test/search/semantic.test.ts +32 -0
- package/.claude/worktrees/elastic-jennings/test/validation/schema.test.ts +113 -0
- package/.claude/worktrees/elastic-jennings/tsconfig.json +29 -0
- package/.cursor/rules/mcpx.mdc +165 -0
- package/LICENSE +21 -0
- package/README.md +627 -0
- package/package.json +58 -0
- package/src/cli.ts +72 -0
- package/src/client/browser.ts +24 -0
- package/src/client/debug-fetch.ts +81 -0
- package/src/client/elicitation.ts +368 -0
- package/src/client/http.ts +25 -0
- package/src/client/manager.ts +566 -0
- package/src/client/oauth.ts +314 -0
- package/src/client/sse.ts +17 -0
- package/src/client/stdio.ts +12 -0
- package/src/client/trace.ts +184 -0
- package/src/commands/add.ts +179 -0
- package/src/commands/auth.ts +114 -0
- package/src/commands/exec.ts +156 -0
- package/src/commands/index.ts +62 -0
- package/src/commands/info.ts +63 -0
- package/src/commands/list.ts +64 -0
- package/src/commands/ping.ts +69 -0
- package/src/commands/prompt.ts +60 -0
- package/src/commands/remove.ts +67 -0
- package/src/commands/resource.ts +46 -0
- package/src/commands/search.ts +49 -0
- package/src/commands/servers.ts +66 -0
- package/src/commands/skill.ts +112 -0
- package/src/commands/task.ts +82 -0
- package/src/config/env.ts +41 -0
- package/src/config/loader.ts +156 -0
- package/src/config/schemas.ts +152 -0
- package/src/context.ts +62 -0
- package/src/lib/input.ts +36 -0
- package/src/output/formatter.ts +884 -0
- package/src/output/logger.ts +173 -0
- package/src/search/index.ts +69 -0
- package/src/search/indexer.ts +92 -0
- package/src/search/keyword.ts +86 -0
- package/src/search/semantic.ts +75 -0
- package/src/search/staleness.ts +8 -0
- 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
|