@evantahler/mcpcli 0.1.1
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/LICENSE +21 -0
- package/README.md +432 -0
- package/package.json +56 -0
- package/skills/mcpcli.md +85 -0
- package/src/cli.ts +34 -0
- package/src/client/http.ts +99 -0
- package/src/client/manager.ts +204 -0
- package/src/client/oauth.ts +263 -0
- package/src/client/stdio.ts +12 -0
- package/src/commands/auth.ts +106 -0
- package/src/commands/call.ts +104 -0
- package/src/commands/index.ts +53 -0
- package/src/commands/info.ts +42 -0
- package/src/commands/list.ts +30 -0
- package/src/commands/search.ts +37 -0
- package/src/config/env.ts +41 -0
- package/src/config/loader.ts +118 -0
- package/src/config/schemas.ts +137 -0
- package/src/context.ts +41 -0
- package/src/output/formatter.ts +316 -0
- package/src/output/spinner.ts +39 -0
- package/src/search/index.ts +69 -0
- package/src/search/indexer.ts +91 -0
- package/src/search/keyword.ts +86 -0
- package/src/search/semantic.ts +75 -0
- package/src/validation/schema.ts +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Evan Tahler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
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
|
+
# Call a tool
|
|
38
|
+
mcpcli call 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 call <server> <tool> [json]` | Validate inputs locally, then execute tool |
|
|
63
|
+
| `mcpcli call <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
|
+
|
|
69
|
+
## Options
|
|
70
|
+
|
|
71
|
+
| Flag | Purpose |
|
|
72
|
+
| ------------------------- | -------------------------------------------------- |
|
|
73
|
+
| `-h, --help` | Show help |
|
|
74
|
+
| `-V, --version` | Show version |
|
|
75
|
+
| `-d, --with-descriptions` | Include tool descriptions in list output |
|
|
76
|
+
| `-c, --config <path>` | Specify config file location |
|
|
77
|
+
| `-v, --verbose` | Show HTTP request/response headers and timing |
|
|
78
|
+
| `-S, --show-secrets` | Show full auth tokens in verbose output (unmasked) |
|
|
79
|
+
| `-j, --json` | Force JSON output (default when piped) |
|
|
80
|
+
| `--no-daemon` | Disable connection pooling |
|
|
81
|
+
|
|
82
|
+
## Configuration
|
|
83
|
+
|
|
84
|
+
Config lives in `~/.config/mcpcli/` (or the current directory). Three files:
|
|
85
|
+
|
|
86
|
+
### `servers.json` — MCP Server Definitions
|
|
87
|
+
|
|
88
|
+
Standard MCP server config format. Supports both stdio and HTTP servers.
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"filesystem": {
|
|
94
|
+
"command": "npx",
|
|
95
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
|
|
96
|
+
"env": { "API_KEY": "${API_KEY}" },
|
|
97
|
+
"allowedTools": ["read_file", "list_directory"],
|
|
98
|
+
"disabledTools": ["delete_file"]
|
|
99
|
+
},
|
|
100
|
+
"github": {
|
|
101
|
+
"url": "https://mcp.github.com"
|
|
102
|
+
},
|
|
103
|
+
"internal-api": {
|
|
104
|
+
"url": "https://mcp.internal.example.com",
|
|
105
|
+
"headers": { "Authorization": "Bearer ${TOKEN}" }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Stdio servers** — `command` + `args`, spawned as child processes
|
|
112
|
+
**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.
|
|
113
|
+
|
|
114
|
+
Environment variables are interpolated via `${VAR_NAME}` syntax. Set `MCP_STRICT_ENV=false` to warn instead of error on missing variables.
|
|
115
|
+
|
|
116
|
+
**Tool filtering:**
|
|
117
|
+
|
|
118
|
+
- `allowedTools` — glob patterns for tools to expose (whitelist)
|
|
119
|
+
- `disabledTools` — glob patterns for tools to hide (blacklist, takes precedence)
|
|
120
|
+
|
|
121
|
+
### `auth.json` — OAuth Token Storage (managed automatically)
|
|
122
|
+
|
|
123
|
+
Stores OAuth tokens for HTTP MCP servers. You don't edit this directly — managed automatically.
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"github": {
|
|
128
|
+
"access_token": "gho_xxxx",
|
|
129
|
+
"refresh_token": "ghr_xxxx",
|
|
130
|
+
"expires_at": "2026-03-03T12:00:00Z",
|
|
131
|
+
"token_type": "bearer",
|
|
132
|
+
"scope": "repo,read:org"
|
|
133
|
+
},
|
|
134
|
+
"linear": {
|
|
135
|
+
"access_token": "lin_xxxx",
|
|
136
|
+
"refresh_token": "lin_ref_xxxx",
|
|
137
|
+
"expires_at": "2026-03-04T08:30:00Z",
|
|
138
|
+
"token_type": "bearer"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Tokens are automatically refreshed when expired (if a refresh token is available). Any command that connects to a server (`call`, `info`, `search`, listing) will refresh tokens transparently. `mcpcli auth <server> --status` shows current token state and TTL.
|
|
144
|
+
|
|
145
|
+
### `search.json` — Semantic Search Index (managed automatically)
|
|
146
|
+
|
|
147
|
+
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.
|
|
148
|
+
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
"version": 1,
|
|
152
|
+
"indexed_at": "2026-03-03T10:00:00Z",
|
|
153
|
+
"embedding_model": "Xenova/all-MiniLM-L6-v2",
|
|
154
|
+
"tools": [
|
|
155
|
+
{
|
|
156
|
+
"server": "linear",
|
|
157
|
+
"tool": "createIssue",
|
|
158
|
+
"description": "Create a new issue in Linear",
|
|
159
|
+
"input_schema": { "...": "..." },
|
|
160
|
+
"scenarios": ["Create a new issue in Linear", "create issue"],
|
|
161
|
+
"keywords": ["create", "issue"],
|
|
162
|
+
"embedding": [0.012, -0.034, "..."]
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Each tool gets:
|
|
169
|
+
|
|
170
|
+
- **scenarios** — the tool description plus a keyword phrase derived from the tool name
|
|
171
|
+
- **keywords** — terms extracted by splitting the tool name on `_`, `-`, and camelCase boundaries
|
|
172
|
+
- **embedding** — 384-dim vector for cosine similarity search
|
|
173
|
+
|
|
174
|
+
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.
|
|
175
|
+
|
|
176
|
+
## Config Resolution Order
|
|
177
|
+
|
|
178
|
+
1. `MCP_CONFIG_PATH` environment variable
|
|
179
|
+
2. `-c / --config` flag
|
|
180
|
+
3. `./servers.json` (current directory)
|
|
181
|
+
4. `~/.config/mcpcli/servers.json`
|
|
182
|
+
|
|
183
|
+
## Environment Variables
|
|
184
|
+
|
|
185
|
+
| Variable | Purpose | Default |
|
|
186
|
+
| -------------------- | --------------------------------- | ------------------- |
|
|
187
|
+
| `MCP_CONFIG_PATH` | Config directory path | `~/.config/mcpcli/` |
|
|
188
|
+
| `MCP_DEBUG` | Enable debug output | `false` |
|
|
189
|
+
| `MCP_TIMEOUT` | Request timeout (seconds) | `1800` |
|
|
190
|
+
| `MCP_CONCURRENCY` | Parallel server connections | `5` |
|
|
191
|
+
| `MCP_MAX_RETRIES` | Retry attempts | `3` |
|
|
192
|
+
| `MCP_STRICT_ENV` | Error on missing `${VAR}` | `true` |
|
|
193
|
+
| `MCP_NO_DAEMON` | Disable connection pooling | `false` |
|
|
194
|
+
| `MCP_DAEMON_TIMEOUT` | Idle connection timeout (seconds) | `60` |
|
|
195
|
+
|
|
196
|
+
## Connection Pooling
|
|
197
|
+
|
|
198
|
+
mcpcli runs a lightweight daemon that keeps MCP server connections warm. Stdio processes stay alive and HTTP connections are reused across invocations. The daemon exits after `MCP_DAEMON_TIMEOUT` seconds of inactivity (default 60s).
|
|
199
|
+
|
|
200
|
+
Disable with `--no-daemon` or `MCP_NO_DAEMON=true` for one-shot usage.
|
|
201
|
+
|
|
202
|
+
## OAuth Flow
|
|
203
|
+
|
|
204
|
+
For HTTP MCP servers that require OAuth:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Start the OAuth flow — opens browser for authorization
|
|
208
|
+
mcpcli auth github
|
|
209
|
+
|
|
210
|
+
# Check token status
|
|
211
|
+
mcpcli auth github -s
|
|
212
|
+
# => github: authenticated (expires in 47m)
|
|
213
|
+
|
|
214
|
+
# Force re-authentication
|
|
215
|
+
mcpcli auth github -r
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The OAuth flow:
|
|
219
|
+
|
|
220
|
+
1. Discovers the server's OAuth metadata via `/.well-known/oauth-authorization-server`
|
|
221
|
+
2. Starts a local callback server on a random port
|
|
222
|
+
3. Opens the browser for user authorization
|
|
223
|
+
4. Exchanges the authorization code for tokens
|
|
224
|
+
5. Stores tokens in `auth.json`
|
|
225
|
+
6. Automatically refreshes tokens before they expire on any subsequent command
|
|
226
|
+
|
|
227
|
+
## Search
|
|
228
|
+
|
|
229
|
+
`mcpcli search` is a single command that combines keyword matching and semantic vector search. By default, both strategies run and results are merged.
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Combined search (default) — keyword hits + semantic matches, merged and ranked
|
|
233
|
+
mcpcli search "send a message to slack"
|
|
234
|
+
# => slack/postMessage (0.94) Post a message to a channel
|
|
235
|
+
# => slack/sendDirectMessage (0.87) Send a DM to a user
|
|
236
|
+
# => teams/sendMessage (0.72) Send a Teams message
|
|
237
|
+
|
|
238
|
+
# Keyword only — fast glob match against tool names, descriptions, and keywords
|
|
239
|
+
mcpcli search -k "*pull*request*"
|
|
240
|
+
# => github/createPullRequest
|
|
241
|
+
# => github/getPullRequest
|
|
242
|
+
# => github/mergePullRequest
|
|
243
|
+
|
|
244
|
+
# Semantic only — vector similarity against intent
|
|
245
|
+
mcpcli search -q "review someone's code changes"
|
|
246
|
+
# => github/submitPullRequestReview (0.91) Submit a PR review
|
|
247
|
+
# => github/getPullRequest (0.85) Get PR details
|
|
248
|
+
# => github/listPullRequestCommits (0.78) List commits in a PR
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The combined search pipeline:
|
|
252
|
+
|
|
253
|
+
1. **Keyword match** — glob/substring against tool names, descriptions, and indexed keywords
|
|
254
|
+
2. **Semantic match** — embed the query, cosine similarity against tool embeddings
|
|
255
|
+
3. **Merge & rank** — combine both result sets, deduplicate, sort by score
|
|
256
|
+
4. **Return** — top results with similarity scores
|
|
257
|
+
|
|
258
|
+
The index updates incrementally — only new or changed tools are re-indexed. The first run indexes everything; subsequent runs are fast.
|
|
259
|
+
|
|
260
|
+
## Debugging with Verbose Mode
|
|
261
|
+
|
|
262
|
+
`-v` shows HTTP request/response details, like `curl -v`. Debug output goes to stderr so piping to `jq` still works.
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
# See full HTTP traffic
|
|
266
|
+
mcpcli -v call arcade Gmail_WhoAmI
|
|
267
|
+
|
|
268
|
+
# > POST https://api.arcade.dev/mcp/evan-coding
|
|
269
|
+
# > authorization: Bearer eyJhbGci...
|
|
270
|
+
# > content-type: application/json
|
|
271
|
+
# > accept: application/json, text/event-stream
|
|
272
|
+
# >
|
|
273
|
+
# {
|
|
274
|
+
# "method": "tools/call",
|
|
275
|
+
# "params": {
|
|
276
|
+
# "name": "Gmail_WhoAmI",
|
|
277
|
+
# "arguments": {}
|
|
278
|
+
# }
|
|
279
|
+
# }
|
|
280
|
+
# < 200 OK (142ms)
|
|
281
|
+
# < content-type: application/json
|
|
282
|
+
# < x-request-id: abc123
|
|
283
|
+
# <
|
|
284
|
+
# { "content": [ ... ] }
|
|
285
|
+
|
|
286
|
+
# Debug on stderr, clean JSON on stdout
|
|
287
|
+
mcpcli -v call arcade Gmail_WhoAmI | jq .
|
|
288
|
+
|
|
289
|
+
# Show full auth tokens (unmasked)
|
|
290
|
+
mcpcli -v -S call arcade Gmail_WhoAmI
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
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.
|
|
294
|
+
|
|
295
|
+
## Input Validation
|
|
296
|
+
|
|
297
|
+
`mcpcli call` 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.
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
# Missing required field — caught locally
|
|
301
|
+
mcpcli call github create_issue '{"title": "bug"}'
|
|
302
|
+
# => error: missing required field "repo" (github/create_issue)
|
|
303
|
+
|
|
304
|
+
# Wrong type — caught locally
|
|
305
|
+
mcpcli call github create_issue '{"repo": "foo", "title": 123}'
|
|
306
|
+
# => error: "title" must be a string, got number (github/create_issue)
|
|
307
|
+
|
|
308
|
+
# Valid — sent to server
|
|
309
|
+
mcpcli call github create_issue '{"repo": "foo", "title": "bug"}'
|
|
310
|
+
# => { ... }
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Validation covers:
|
|
314
|
+
|
|
315
|
+
- **Required fields** — errors before sending if any are missing
|
|
316
|
+
- **Type checking** — string, number, boolean, array, object
|
|
317
|
+
- **Enum values** — rejects values not in the allowed set
|
|
318
|
+
- **Nested objects** — validates recursively
|
|
319
|
+
|
|
320
|
+
If a tool's `inputSchema` is unavailable (some servers don't provide one), the call proceeds without local validation.
|
|
321
|
+
|
|
322
|
+
## Shell Output & Piping
|
|
323
|
+
|
|
324
|
+
Output is human-friendly by default, JSON when piped:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Human-readable
|
|
328
|
+
mcpcli info github
|
|
329
|
+
|
|
330
|
+
# JSON (piped)
|
|
331
|
+
mcpcli info github | jq '.tools[].name'
|
|
332
|
+
|
|
333
|
+
# Force JSON
|
|
334
|
+
mcpcli info github --json
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Tool call results are always JSON, designed for chaining:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# Search repos and read the first result
|
|
341
|
+
mcpcli call github search_repositories '{"query":"mcp"}' \
|
|
342
|
+
| jq -r '.content[0].text | fromjson | .items[0].full_name' \
|
|
343
|
+
| xargs -I {} mcpcli call github get_file_contents '{"owner":"{}","path":"README.md"}'
|
|
344
|
+
|
|
345
|
+
# Conditional execution
|
|
346
|
+
mcpcli call filesystem list_directory '{"path":"."}' \
|
|
347
|
+
| jq -e '.content[0].text | contains("package.json")' \
|
|
348
|
+
&& mcpcli call filesystem read_file '{"path":"./package.json"}'
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Stdin works for tool arguments:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
echo '{"path":"./README.md"}' | mcpcli call filesystem read_file
|
|
355
|
+
|
|
356
|
+
cat params.json | mcpcli call server tool
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Agent Integration
|
|
360
|
+
|
|
361
|
+
### Claude Code Skill
|
|
362
|
+
|
|
363
|
+
mcpcli ships a Claude Code skill at `skills/mcpcli.md` that teaches Claude Code how to discover and use MCP tools. Install it:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# Copy the skill to your global Claude Code skills
|
|
367
|
+
cp skills/mcpcli.md ~/.claude/skills/mcpcli.md
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
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:
|
|
371
|
+
|
|
372
|
+
1. **Search first** — `mcpcli search "<intent>"` to find relevant tools
|
|
373
|
+
2. **Inspect** — `mcpcli info <server>/<tool>` to get the schema before calling
|
|
374
|
+
3. **Call** — `mcpcli call <server> <tool> '<json>'` to execute
|
|
375
|
+
|
|
376
|
+
This keeps tool schemas out of the system prompt entirely. The agent discovers what it needs on-demand, saving tokens and context window space.
|
|
377
|
+
|
|
378
|
+
### Raw System Prompt (other agents)
|
|
379
|
+
|
|
380
|
+
For non-Claude-Code agents, add this to the system prompt:
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
You have access to MCP tools via the `mcpcli` CLI.
|
|
384
|
+
|
|
385
|
+
To discover tools:
|
|
386
|
+
mcpcli search "<what you want to do>" # combined keyword + semantic
|
|
387
|
+
mcpcli search -k "<pattern>" # keyword/glob only
|
|
388
|
+
mcpcli info <server>/<tool> # tool schema
|
|
389
|
+
|
|
390
|
+
To call tools:
|
|
391
|
+
mcpcli call <server> <tool> '<json args>'
|
|
392
|
+
|
|
393
|
+
Always search before calling — don't assume tool names.
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Development
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Install dependencies
|
|
400
|
+
bun install
|
|
401
|
+
|
|
402
|
+
# Run in development
|
|
403
|
+
bun run dev
|
|
404
|
+
|
|
405
|
+
# Run tests
|
|
406
|
+
bun test
|
|
407
|
+
|
|
408
|
+
# Build single binary
|
|
409
|
+
bun run build
|
|
410
|
+
|
|
411
|
+
# Lint
|
|
412
|
+
bun lint
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Tech Stack
|
|
416
|
+
|
|
417
|
+
| Layer | Choice |
|
|
418
|
+
| ----------- | ----------------------------------------------------- |
|
|
419
|
+
| Runtime | Bun |
|
|
420
|
+
| Language | TypeScript |
|
|
421
|
+
| MCP Client | `@modelcontextprotocol/sdk` |
|
|
422
|
+
| CLI Parsing | `commander` |
|
|
423
|
+
| Validation | `ajv` (JSON Schema) |
|
|
424
|
+
| Embeddings | `@huggingface/transformers` (Xenova/all-MiniLM-L6-v2) |
|
|
425
|
+
|
|
426
|
+
## Inspiration
|
|
427
|
+
|
|
428
|
+
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.
|
|
429
|
+
|
|
430
|
+
## License
|
|
431
|
+
|
|
432
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evantahler/mcpcli",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "A command-line interface for MCP servers. curl for MCP.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcpcli": "./src/cli.ts"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"skills",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"dev": "bun run src/cli.ts",
|
|
17
|
+
"test": "bun test",
|
|
18
|
+
"lint": "prettier --check .",
|
|
19
|
+
"format": "prettier --write .",
|
|
20
|
+
"build": "bun build --compile --minify --sourcemap ./src/cli.ts --outfile dist/mcpcli"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/evantahler/mcpcli.git"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"mcp",
|
|
31
|
+
"cli",
|
|
32
|
+
"model-context-protocol",
|
|
33
|
+
"ai",
|
|
34
|
+
"llm",
|
|
35
|
+
"tools"
|
|
36
|
+
],
|
|
37
|
+
"author": "Evan Tahler",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@huggingface/transformers": "^3.8.1",
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
42
|
+
"ajv": "^8.18.0",
|
|
43
|
+
"ansis": "^4.2.0",
|
|
44
|
+
"commander": "^14.0.3",
|
|
45
|
+
"nanospinner": "^1.2.2",
|
|
46
|
+
"picomatch": "^4.0.3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/bun": "latest",
|
|
50
|
+
"@types/picomatch": "^4.0.2",
|
|
51
|
+
"prettier": "^3.8.1"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"typescript": "^5"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/skills/mcpcli.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mcpcli
|
|
3
|
+
description: Discover and use MCP tools via the mcpcli CLI
|
|
4
|
+
trigger: when the user wants to interact with external services, APIs, or MCP tools
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# mcpcli — MCP Tool Discovery and Execution
|
|
8
|
+
|
|
9
|
+
You have access to external tools via `mcpcli`. Use this workflow:
|
|
10
|
+
|
|
11
|
+
## 1. Search for tools
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
mcpcli search "<what you want to do>"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 2. Inspect the tool schema
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
mcpcli call <server> <tool>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This shows parameters, types, required fields, and an example payload.
|
|
24
|
+
|
|
25
|
+
## 3. Call the tool
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mcpcli call <server> <tool> '<json args>'
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
|
|
33
|
+
- Always search before calling — don't assume tool names exist
|
|
34
|
+
- Always inspect the schema before calling — validate you have the right arguments
|
|
35
|
+
- Use `mcpcli search -k` for exact name matching
|
|
36
|
+
- Pipe results through `jq` when you need to extract specific fields
|
|
37
|
+
- Tool call results are always JSON with nested JSON strings auto-parsed
|
|
38
|
+
- Use `-v` for verbose HTTP debugging if a call fails unexpectedly
|
|
39
|
+
|
|
40
|
+
## Examples
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Find tools related to sending messages
|
|
44
|
+
mcpcli search "send a message"
|
|
45
|
+
|
|
46
|
+
# See what parameters Slack_SendMessage needs
|
|
47
|
+
mcpcli call arcade Slack_SendMessage
|
|
48
|
+
|
|
49
|
+
# Send a message
|
|
50
|
+
mcpcli call arcade Slack_SendMessage '{"channel":"#general","message":"hello"}'
|
|
51
|
+
|
|
52
|
+
# Chain commands — search repos and read the first result
|
|
53
|
+
mcpcli call github search_repositories '{"query":"mcp"}' \
|
|
54
|
+
| jq -r '.content[0].text.items[0].full_name' \
|
|
55
|
+
| xargs -I {} mcpcli call github get_file_contents '{"owner":"{}","path":"README.md"}'
|
|
56
|
+
|
|
57
|
+
# Read args from stdin
|
|
58
|
+
echo '{"path":"./README.md"}' | mcpcli call filesystem read_file
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Authentication
|
|
62
|
+
|
|
63
|
+
Some HTTP servers require OAuth. If you see an "Not authenticated" error:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
mcpcli auth <server> # authenticate via browser
|
|
67
|
+
mcpcli auth <server> -s # check token status
|
|
68
|
+
mcpcli deauth <server> # remove stored auth
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Available commands
|
|
72
|
+
|
|
73
|
+
| Command | Purpose |
|
|
74
|
+
| -------------------------------------- | ---------------------------------- |
|
|
75
|
+
| `mcpcli` | List all servers and tools |
|
|
76
|
+
| `mcpcli -d` | List with descriptions |
|
|
77
|
+
| `mcpcli call <server>` | List tools for a server |
|
|
78
|
+
| `mcpcli call <server> <tool>` | Show tool help and example payload |
|
|
79
|
+
| `mcpcli call <server> <tool> '<json>'` | Execute a tool |
|
|
80
|
+
| `mcpcli info <server>/<tool>` | Show tool schema |
|
|
81
|
+
| `mcpcli search "<query>"` | Search tools |
|
|
82
|
+
| `mcpcli search -k "<pattern>"` | Keyword/glob search only |
|
|
83
|
+
| `mcpcli search -q "<query>"` | Semantic search only |
|
|
84
|
+
| `mcpcli index` | Build/rebuild search index |
|
|
85
|
+
| `mcpcli auth <server>` | Authenticate with OAuth |
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { program } from "commander";
|
|
4
|
+
import { registerListCommand } from "./commands/list.ts";
|
|
5
|
+
import { registerInfoCommand } from "./commands/info.ts";
|
|
6
|
+
import { registerSearchCommand } from "./commands/search.ts";
|
|
7
|
+
import { registerCallCommand } from "./commands/call.ts";
|
|
8
|
+
import { registerAuthCommand, registerDeauthCommand } from "./commands/auth.ts";
|
|
9
|
+
import { registerIndexCommand } from "./commands/index.ts";
|
|
10
|
+
|
|
11
|
+
declare const BUILD_VERSION: string | undefined;
|
|
12
|
+
|
|
13
|
+
const version = typeof BUILD_VERSION !== "undefined" ? BUILD_VERSION : "0.1.0-dev";
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name("mcpcli")
|
|
17
|
+
.description("A command-line interface for MCP servers. curl for MCP.")
|
|
18
|
+
.version(version)
|
|
19
|
+
.option("-c, --config <path>", "config directory path")
|
|
20
|
+
.option("-d, --with-descriptions", "include tool descriptions in output")
|
|
21
|
+
.option("-j, --json", "force JSON output")
|
|
22
|
+
.option("-v, --verbose", "show HTTP request/response details")
|
|
23
|
+
.option("-S, --show-secrets", "show full auth tokens in verbose output")
|
|
24
|
+
.option("--no-daemon", "disable connection pooling");
|
|
25
|
+
|
|
26
|
+
registerListCommand(program);
|
|
27
|
+
registerInfoCommand(program);
|
|
28
|
+
registerSearchCommand(program);
|
|
29
|
+
registerCallCommand(program);
|
|
30
|
+
registerAuthCommand(program);
|
|
31
|
+
registerDeauthCommand(program);
|
|
32
|
+
registerIndexCommand(program);
|
|
33
|
+
|
|
34
|
+
program.parse();
|