@evantahler/mcpcli 0.3.6 → 0.5.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/README.md +33 -33
- package/package.json +1 -1
- package/skills/mcpcli.md +11 -11
- package/src/cli.ts +2 -2
- package/src/commands/{call.ts → exec.ts} +3 -3
- package/src/config/loader.ts +2 -2
package/README.md
CHANGED
|
@@ -34,8 +34,8 @@ mcpcli info github
|
|
|
34
34
|
# Inspect a specific tool
|
|
35
35
|
mcpcli info github search_repositories
|
|
36
36
|
|
|
37
|
-
#
|
|
38
|
-
mcpcli
|
|
37
|
+
# Execute a tool
|
|
38
|
+
mcpcli exec github search_repositories '{"query": "mcp server"}'
|
|
39
39
|
|
|
40
40
|
# Search tools — combines keyword and semantic matching
|
|
41
41
|
mcpcli search "post a ticket to linear"
|
|
@@ -59,8 +59,8 @@ mcpcli search -q "manage pull requests"
|
|
|
59
59
|
| `mcpcli search -q <query>` | Semantic search only |
|
|
60
60
|
| `mcpcli index` | Build/rebuild the search index |
|
|
61
61
|
| `mcpcli index -i` | Show index status |
|
|
62
|
-
| `mcpcli
|
|
63
|
-
| `mcpcli
|
|
62
|
+
| `mcpcli exec <server> <tool> [json]` | Validate inputs locally, then execute tool |
|
|
63
|
+
| `mcpcli exec <server>` | List available tools for a server |
|
|
64
64
|
| `mcpcli auth <server>` | Authenticate with an HTTP MCP server (OAuth) |
|
|
65
65
|
| `mcpcli auth <server> -s` | Check auth status and token TTL |
|
|
66
66
|
| `mcpcli auth <server> -r` | Force token refresh |
|
|
@@ -134,7 +134,7 @@ mcpcli remove my-api --dry-run
|
|
|
134
134
|
|
|
135
135
|
## Configuration
|
|
136
136
|
|
|
137
|
-
Config lives in `~/.
|
|
137
|
+
Config lives in `~/.mcpcli/` (or the current directory). Three files:
|
|
138
138
|
|
|
139
139
|
### `servers.json` — MCP Server Definitions
|
|
140
140
|
|
|
@@ -193,7 +193,7 @@ Stores OAuth tokens for HTTP MCP servers. You don't edit this directly — manag
|
|
|
193
193
|
}
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
Tokens are automatically refreshed when expired (if a refresh token is available). Any command that connects to a server (`
|
|
196
|
+
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.
|
|
197
197
|
|
|
198
198
|
### `search.json` — Semantic Search Index (managed automatically)
|
|
199
199
|
|
|
@@ -231,18 +231,18 @@ Scenarios and keywords are extracted heuristically from tool names and descripti
|
|
|
231
231
|
1. `MCP_CONFIG_PATH` environment variable
|
|
232
232
|
2. `-c / --config` flag
|
|
233
233
|
3. `./servers.json` (current directory)
|
|
234
|
-
4. `~/.
|
|
234
|
+
4. `~/.mcpcli/servers.json`
|
|
235
235
|
|
|
236
236
|
## Environment Variables
|
|
237
237
|
|
|
238
|
-
| Variable | Purpose | Default
|
|
239
|
-
| ----------------- | --------------------------- |
|
|
240
|
-
| `MCP_CONFIG_PATH` | Config directory path | `~/.
|
|
241
|
-
| `MCP_DEBUG` | Enable debug output | `false`
|
|
242
|
-
| `MCP_TIMEOUT` | Request timeout (seconds) | `1800`
|
|
243
|
-
| `MCP_CONCURRENCY` | Parallel server connections | `5`
|
|
244
|
-
| `MCP_MAX_RETRIES` | Retry attempts | `3`
|
|
245
|
-
| `MCP_STRICT_ENV` | Error on missing `${VAR}` | `true`
|
|
238
|
+
| Variable | Purpose | Default |
|
|
239
|
+
| ----------------- | --------------------------- | ------------ |
|
|
240
|
+
| `MCP_CONFIG_PATH` | Config directory path | `~/.mcpcli/` |
|
|
241
|
+
| `MCP_DEBUG` | Enable debug output | `false` |
|
|
242
|
+
| `MCP_TIMEOUT` | Request timeout (seconds) | `1800` |
|
|
243
|
+
| `MCP_CONCURRENCY` | Parallel server connections | `5` |
|
|
244
|
+
| `MCP_MAX_RETRIES` | Retry attempts | `3` |
|
|
245
|
+
| `MCP_STRICT_ENV` | Error on missing `${VAR}` | `true` |
|
|
246
246
|
|
|
247
247
|
## OAuth Flow
|
|
248
248
|
|
|
@@ -308,7 +308,7 @@ The index updates incrementally — only new or changed tools are re-indexed. Th
|
|
|
308
308
|
|
|
309
309
|
```bash
|
|
310
310
|
# See full HTTP traffic
|
|
311
|
-
mcpcli -v
|
|
311
|
+
mcpcli -v exec arcade Gmail_WhoAmI
|
|
312
312
|
|
|
313
313
|
# > POST https://api.arcade.dev/mcp/evan-coding
|
|
314
314
|
# > authorization: Bearer eyJhbGci...
|
|
@@ -329,7 +329,7 @@ mcpcli -v call arcade Gmail_WhoAmI
|
|
|
329
329
|
# { "content": [ ... ] }
|
|
330
330
|
|
|
331
331
|
# Debug on stderr, clean JSON on stdout
|
|
332
|
-
mcpcli -v
|
|
332
|
+
mcpcli -v exec arcade Gmail_WhoAmI | jq .
|
|
333
333
|
|
|
334
334
|
# Show full auth tokens (unmasked)
|
|
335
335
|
mcpcli -v -S call arcade Gmail_WhoAmI
|
|
@@ -339,19 +339,19 @@ The `>` / `<` convention matches curl — `>` for request, `<` for response. The
|
|
|
339
339
|
|
|
340
340
|
## Input Validation
|
|
341
341
|
|
|
342
|
-
`mcpcli
|
|
342
|
+
`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.
|
|
343
343
|
|
|
344
344
|
```bash
|
|
345
345
|
# Missing required field — caught locally
|
|
346
|
-
mcpcli
|
|
346
|
+
mcpcli exec github create_issue '{"title": "bug"}'
|
|
347
347
|
# => error: missing required field "repo" (github/create_issue)
|
|
348
348
|
|
|
349
349
|
# Wrong type — caught locally
|
|
350
|
-
mcpcli
|
|
350
|
+
mcpcli exec github create_issue '{"repo": "foo", "title": 123}'
|
|
351
351
|
# => error: "title" must be a string, got number (github/create_issue)
|
|
352
352
|
|
|
353
353
|
# Valid — sent to server
|
|
354
|
-
mcpcli
|
|
354
|
+
mcpcli exec github create_issue '{"repo": "foo", "title": "bug"}'
|
|
355
355
|
# => { ... }
|
|
356
356
|
```
|
|
357
357
|
|
|
@@ -362,7 +362,7 @@ Validation covers:
|
|
|
362
362
|
- **Enum values** — rejects values not in the allowed set
|
|
363
363
|
- **Nested objects** — validates recursively
|
|
364
364
|
|
|
365
|
-
If a tool's `inputSchema` is unavailable (some servers don't provide one),
|
|
365
|
+
If a tool's `inputSchema` is unavailable (some servers don't provide one), execution proceeds without local validation.
|
|
366
366
|
|
|
367
367
|
## Shell Output & Piping
|
|
368
368
|
|
|
@@ -379,26 +379,26 @@ mcpcli info github | jq '.tools[].name'
|
|
|
379
379
|
mcpcli info github --json
|
|
380
380
|
```
|
|
381
381
|
|
|
382
|
-
Tool
|
|
382
|
+
Tool results are always JSON, designed for chaining:
|
|
383
383
|
|
|
384
384
|
```bash
|
|
385
385
|
# Search repos and read the first result
|
|
386
|
-
mcpcli
|
|
386
|
+
mcpcli exec github search_repositories '{"query":"mcp"}' \
|
|
387
387
|
| jq -r '.content[0].text | fromjson | .items[0].full_name' \
|
|
388
|
-
| xargs -I {} mcpcli
|
|
388
|
+
| xargs -I {} mcpcli exec github get_file_contents '{"owner":"{}","path":"README.md"}'
|
|
389
389
|
|
|
390
390
|
# Conditional execution
|
|
391
|
-
mcpcli
|
|
391
|
+
mcpcli exec filesystem list_directory '{"path":"."}' \
|
|
392
392
|
| jq -e '.content[0].text | contains("package.json")' \
|
|
393
|
-
&& mcpcli
|
|
393
|
+
&& mcpcli exec filesystem read_file '{"path":"./package.json"}'
|
|
394
394
|
```
|
|
395
395
|
|
|
396
396
|
Stdin works for tool arguments:
|
|
397
397
|
|
|
398
398
|
```bash
|
|
399
|
-
echo '{"path":"./README.md"}' | mcpcli
|
|
399
|
+
echo '{"path":"./README.md"}' | mcpcli exec filesystem read_file
|
|
400
400
|
|
|
401
|
-
cat params.json | mcpcli
|
|
401
|
+
cat params.json | mcpcli exec server tool
|
|
402
402
|
```
|
|
403
403
|
|
|
404
404
|
## Agent Integration
|
|
@@ -416,7 +416,7 @@ Then in any Claude Code session, the agent can use `/mcpcli` or the skill trigge
|
|
|
416
416
|
|
|
417
417
|
1. **Search first** — `mcpcli search "<intent>"` to find relevant tools
|
|
418
418
|
2. **Inspect** — `mcpcli info <server> <tool>` to get the schema before calling
|
|
419
|
-
3. **
|
|
419
|
+
3. **Execute** — `mcpcli exec <server> <tool> '<json>'` to execute
|
|
420
420
|
|
|
421
421
|
This keeps tool schemas out of the system prompt entirely. The agent discovers what it needs on-demand, saving tokens and context window space.
|
|
422
422
|
|
|
@@ -432,10 +432,10 @@ To discover tools:
|
|
|
432
432
|
mcpcli search -k "<pattern>" # keyword/glob only
|
|
433
433
|
mcpcli info <server> <tool> # tool schema
|
|
434
434
|
|
|
435
|
-
To
|
|
436
|
-
mcpcli
|
|
435
|
+
To execute tools:
|
|
436
|
+
mcpcli exec <server> <tool> '<json args>'
|
|
437
437
|
|
|
438
|
-
Always search before
|
|
438
|
+
Always search before executing — don't assume tool names.
|
|
439
439
|
```
|
|
440
440
|
|
|
441
441
|
## Development
|
package/package.json
CHANGED
package/skills/mcpcli.md
CHANGED
|
@@ -22,19 +22,19 @@ mcpcli info <server> <tool>
|
|
|
22
22
|
|
|
23
23
|
This shows parameters, types, required fields, and the full JSON Schema.
|
|
24
24
|
|
|
25
|
-
## 3.
|
|
25
|
+
## 3. Execute the tool
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
mcpcli
|
|
28
|
+
mcpcli exec <server> <tool> '<json args>'
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
## Rules
|
|
32
32
|
|
|
33
|
-
- Always search before
|
|
34
|
-
- Always inspect the schema before
|
|
33
|
+
- Always search before executing — don't assume tool names exist
|
|
34
|
+
- Always inspect the schema before executing — validate you have the right arguments
|
|
35
35
|
- Use `mcpcli search -k` for exact name matching
|
|
36
36
|
- Pipe results through `jq` when you need to extract specific fields
|
|
37
|
-
- Use `-v` for verbose HTTP debugging if
|
|
37
|
+
- Use `-v` for verbose HTTP debugging if an exec fails unexpectedly
|
|
38
38
|
|
|
39
39
|
## Examples
|
|
40
40
|
|
|
@@ -46,15 +46,15 @@ mcpcli search "send a message"
|
|
|
46
46
|
mcpcli info arcade Slack_SendMessage
|
|
47
47
|
|
|
48
48
|
# Send a message
|
|
49
|
-
mcpcli
|
|
49
|
+
mcpcli exec arcade Slack_SendMessage '{"channel":"#general","message":"hello"}'
|
|
50
50
|
|
|
51
51
|
# Chain commands — search repos and read the first result
|
|
52
|
-
mcpcli
|
|
52
|
+
mcpcli exec github search_repositories '{"query":"mcp"}' \
|
|
53
53
|
| jq -r '.content[0].text | fromjson | .items[0].full_name' \
|
|
54
|
-
| xargs -I {} mcpcli
|
|
54
|
+
| xargs -I {} mcpcli exec github get_file_contents '{"owner":"{}","path":"README.md"}'
|
|
55
55
|
|
|
56
56
|
# Read args from stdin
|
|
57
|
-
echo '{"path":"./README.md"}' | mcpcli
|
|
57
|
+
echo '{"path":"./README.md"}' | mcpcli exec filesystem read_file
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
## Authentication
|
|
@@ -76,8 +76,8 @@ mcpcli deauth <server> # remove stored auth
|
|
|
76
76
|
| `mcpcli -d` | List with descriptions |
|
|
77
77
|
| `mcpcli info <server>` | Show tools for a server |
|
|
78
78
|
| `mcpcli info <server> <tool>` | Show tool schema |
|
|
79
|
-
| `mcpcli
|
|
80
|
-
| `mcpcli
|
|
79
|
+
| `mcpcli exec <server>` | List tools for a server |
|
|
80
|
+
| `mcpcli exec <server> <tool> '<json>'` | Execute a tool |
|
|
81
81
|
| `mcpcli search "<query>"` | Search tools (keyword + semantic) |
|
|
82
82
|
| `mcpcli search -k "<pattern>"` | Keyword/glob search only |
|
|
83
83
|
| `mcpcli search -q "<query>"` | Semantic search only |
|
package/src/cli.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { program } from "commander";
|
|
|
4
4
|
import { registerListCommand } from "./commands/list.ts";
|
|
5
5
|
import { registerInfoCommand } from "./commands/info.ts";
|
|
6
6
|
import { registerSearchCommand } from "./commands/search.ts";
|
|
7
|
-
import {
|
|
7
|
+
import { registerExecCommand } from "./commands/exec.ts";
|
|
8
8
|
import { registerAuthCommand, registerDeauthCommand } from "./commands/auth.ts";
|
|
9
9
|
import { registerIndexCommand } from "./commands/index.ts";
|
|
10
10
|
import { registerAddCommand } from "./commands/add.ts";
|
|
@@ -27,7 +27,7 @@ program
|
|
|
27
27
|
registerListCommand(program);
|
|
28
28
|
registerInfoCommand(program);
|
|
29
29
|
registerSearchCommand(program);
|
|
30
|
-
|
|
30
|
+
registerExecCommand(program);
|
|
31
31
|
registerAuthCommand(program);
|
|
32
32
|
registerDeauthCommand(program);
|
|
33
33
|
registerIndexCommand(program);
|
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
import { logger } from "../output/logger.ts";
|
|
10
10
|
import { validateToolInput } from "../validation/schema.ts";
|
|
11
11
|
|
|
12
|
-
export function
|
|
12
|
+
export function registerExecCommand(program: Command) {
|
|
13
13
|
program
|
|
14
|
-
.command("
|
|
14
|
+
.command("exec <server> [tool] [args]")
|
|
15
15
|
.description("execute a tool (omit tool name to list available tools)")
|
|
16
16
|
.action(async (server: string, tool: string | undefined, argsStr: string | undefined) => {
|
|
17
17
|
const { manager, formatOptions } = await getContext(program);
|
|
@@ -52,7 +52,7 @@ export function registerCallCommand(program: Command) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const spinner = logger.startSpinner(`
|
|
55
|
+
const spinner = logger.startSpinner(`Executing ${server}/${tool}...`, formatOptions);
|
|
56
56
|
const result = await manager.callTool(server, tool, args);
|
|
57
57
|
spinner.stop();
|
|
58
58
|
console.log(formatCallResult(result, formatOptions));
|
package/src/config/loader.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
validateSearchIndex,
|
|
12
12
|
} from "./schemas.ts";
|
|
13
13
|
|
|
14
|
-
const DEFAULT_CONFIG_DIR = join(homedir(), ".
|
|
14
|
+
const DEFAULT_CONFIG_DIR = join(homedir(), ".mcpcli");
|
|
15
15
|
|
|
16
16
|
const EMPTY_SERVERS: ServersFile = { mcpServers: {} };
|
|
17
17
|
const EMPTY_AUTH: AuthFile = {};
|
|
@@ -42,7 +42,7 @@ function resolveConfigDir(configFlag?: string): string {
|
|
|
42
42
|
// 3. ./servers.json exists in cwd → use cwd
|
|
43
43
|
// (checked at load time, not here — we return the candidate dir)
|
|
44
44
|
|
|
45
|
-
// 4. Default ~/.
|
|
45
|
+
// 4. Default ~/.mcpcli/
|
|
46
46
|
return DEFAULT_CONFIG_DIR;
|
|
47
47
|
}
|
|
48
48
|
|