run-mcp 1.7.0 → 1.7.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.
Files changed (3) hide show
  1. package/README.md +82 -38
  2. package/dist/index.js +64 -14
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -60,14 +60,28 @@ You'll see an interactive prompt:
60
60
 
61
61
  run-mcp [options] [target_command...]
62
62
 
63
- Options:
64
- -V, --version Show version number
65
- -o, --out-dir <path> Directory to save intercepted images and audio
66
- -t, --timeout <ms> Default tool call timeout in milliseconds (default: 300000) (Agent Mode only)
67
- --max-text <chars> Max text response length before truncation (default: 50000) (Agent Mode only)
68
- --mcp Force start Agent Server mode even if run interactively without arguments
69
- -s, --script <file> Read commands from a file instead of stdin (REPL Mode only)
70
- -h, --help Display help for command
63
+ <!-- OPTIONS_START -->
64
+ | Option | Description |
65
+ | :--- | :--- |
66
+ | `-V, --version` | output the version number |
67
+ | `-o, --out-dir <path>` | Directory to save intercepted images and audio |
68
+ | `-t, --timeout <ms>` | Default tool call timeout in milliseconds (default: 300000) (Agent Mode only) |
69
+ | `--max-text <chars>` | Max text response length before truncation (default: 50000) (Agent Mode only) |
70
+ | `-m, --media-threshold <kb>` | Media size threshold in KB to save to disk (0 to always save, -1 to keep inline) |
71
+ | `--mcp` | Force start Agent Server mode even if run interactively without arguments |
72
+ | `-s, --script <file>` | Read commands from a file instead of stdin (REPL Mode only) |
73
+ | `--color <mode>` | Color output mode: always, never, auto (default: auto) |
74
+ | `--open-media` | Automatically open intercepted images and audio files using the host OS viewer |
75
+ | `--sandbox <mode>` | Sandbox execution mode: auto, docker, native, audit, none (default: "none") |
76
+ | `--scan` | Scan the current workspace and parent directories for any JSON files containing mcpServers |
77
+ | `--allow-read <paths...>` | Paths to allow reading under the sandbox |
78
+ | `--allow-write <paths...>` | Paths to allow writing under the sandbox |
79
+ | `--allow-net <domains...>` | Network domains to allow connecting to under the sandbox |
80
+ | `--deny-read <paths...>` | Paths to deny reading under the sandbox |
81
+ | `--deny-write <paths...>` | Paths to deny writing under the sandbox |
82
+ | `--deny-net <domains...>` | Network domains to deny connecting to under the sandbox |
83
+ | `-h, --help` | display help for command |
84
+ <!-- OPTIONS_END -->
71
85
 
72
86
  Examples:
73
87
  $ run-mcp # Test harness (agent mode)
@@ -81,12 +95,20 @@ Examples:
81
95
 
82
96
  For CI/CD pipelines, shell scripts, or parsing via `jq`, `run-mcp` exposes a suite of headless subcommands that pipe clean JSON to stdout and isolate standard errors and progress updates to stderr.
83
97
 
84
- ### ⚠️ Strictly Required Double-Dash `--`
98
+ ### ⚠️ Double-Dash `--` Separator
85
99
 
86
- To prevent argument parsing conflicts between `run-mcp` and the target server, **you must always separate the target command with a double-dash `--`**. This applies to both default REPL launching and all headless subcommands.
100
+ To prevent argument parsing conflicts between `run-mcp` and the target server, you should separate the target command with a double-dash `--` when the target command itself contains flags or options.
87
101
 
88
- - **Correct**: `run-mcp list-tools -- node my-server.js`
89
- - **Incorrect**: `run-mcp list-tools node my-server.js` (will exit with a coaching error)
102
+ * **Required when the target command has options/flags:**
103
+ ```bash
104
+ run-mcp list-tools -- node my-server.js --verbose
105
+ ```
106
+ *(Must use `--` so `--verbose` is passed to your server, not parsed as an option for `run-mcp`.)*
107
+ * **Optional when the target command has no options/flags:**
108
+ ```bash
109
+ run-mcp list-tools node my-server.js
110
+ ```
111
+ *(Runs successfully without `--`.)*
90
112
 
91
113
  ### ⚡ HTTPie-Style Shorthand Arguments
92
114
 
@@ -119,14 +141,17 @@ run-mcp close-session main
119
141
 
120
142
  ### Available Headless Subcommands
121
143
 
122
- - `call <tool> [json_or_shorthand_args]`
123
- - `list-tools`
124
- - `list-resources`
125
- - `list-prompts`
126
- - `read <uri>`
127
- - `describe <tool>`
128
- - `get-prompt <name> [json_or_shorthand_args]`
144
+ <!-- SUBCOMMANDS_START -->
145
+ - `call [options] <tool> [json_args] [target_command...]`
146
+ - `list-tools [options] [target_command...]`
147
+ - `list-resources [options] [target_command...]`
148
+ - `list-prompts [options] [target_command...]`
149
+ - `read [options] <uri> [target_command...]`
150
+ - `describe [options] <tool> [target_command...]`
151
+ - `get-prompt [options] <name> [json_args] [target_command...]`
152
+ - `daemon [options] <session_name> [target_command...]`
129
153
  - `close-session <session_name>`
154
+ <!-- SUBCOMMANDS_END -->
130
155
 
131
156
  Use `run-mcp <subcommand> --help` for specific command options.
132
157
 
@@ -154,30 +179,49 @@ Add `run-mcp` to your agent's MCP configuration using `npx`:
154
179
 
155
180
  Then use these tools from your agent:
156
181
 
157
- | Tool | Description |
158
- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
159
- | `connect_to_mcp` | Spawn and connect to a local MCP server. Use `include` to get tools/resources/prompts inline. Shows a diff on reconnect. |
160
- | `disconnect_from_mcp` | Tear down the connection |
161
- | `mcp_server_status` | Check connection status |
162
- | `call_mcp_primitive` | Call a tool, read a resource, or get a prompt. Auto-connects if not already connected. Use `disconnect_after` for one-shot tests. |
163
- | `list_mcp_primitives` | List tools, resources, and/or prompts on the connected server |
164
- | `get_mcp_server_stderr` | View target server stderr output |
165
- | `list_available_mcp_servers` | Discover other local MCP servers configured on the host machine |
182
+ <!-- AGENT_TOOLS_START -->
183
+ | Tool | Description |
184
+ | :--- | :--- |
185
+ | `connect_to_mcp` | Spawn and connect (use include to get tools/resources/prompts) |
186
+ | `call_mcp_primitive` | Call a tool, read a resource, or get a prompt (auto-connects) |
187
+ | `list_mcp_primitives` | List tools, resources, and/or prompts |
188
+ | `disconnect_from_mcp` | Tear down and reconnect after changes |
189
+ | `mcp_server_status` | Check connection status |
190
+ | `get_mcp_server_stderr` | View target server stderr output |
191
+ | `validate_mcp_server` | Validate an MCP server command and collect diagnostics |
192
+ | `search_all_local_mcp_servers` | Scan and search all local MCP servers for a query |
193
+ <!-- AGENT_TOOLS_END -->
166
194
 
167
195
  ## REPL Mode Commands
168
196
 
169
197
  Once connected via `run-mcp <command>`, the following shorthand commands are available:
170
198
 
171
- | Command | Description |
172
- | ------------------------------------ | --------------------------------------------------------------------------------------------------------- |
173
- | `explore` | Open interactive fuzzy-search selector for tools, resources, and prompts |
174
- | `tools/list` | List all tools exposed by the target server |
175
- | `tools/describe <name>` | Show a tool's full input schema |
176
- | `tools/call <name> [json] [--clear]` | Call a tool. Launch interactive wizard if no JSON provided. Use `--clear` to ignore remembered arguments. |
177
- | `tools/forget [name]` | Clear remembered interactive arguments for a tool, or all tools if no name provided. |
178
- | `status` | Show target server status (PID, uptime, connection) |
179
- | `help` | Show available commands |
180
- | `exit` / `quit` | Disconnect and exit |
199
+ <!-- REPL_COMMANDS_START -->
200
+ | Command | Description |
201
+ | :--- | :--- |
202
+ | `tools/list` | List all available tools |
203
+ | `tools/describe <name>` | Show a tool's input schema |
204
+ | `tools/call <name> [json] [opts]` | Call a tool (interactive if no json) |
205
+ | `tools/scaffold <name>` | Generate argument template for a tool |
206
+ | `resources/list` | List all available resources |
207
+ | `resources/read <uri>` | Read a resource by URI |
208
+ | `resources/templates` | List resource templates |
209
+ | `resources/subscribe <uri>` | Subscribe to resource changes |
210
+ | `resources/unsubscribe <uri>` | Unsubscribe from resource changes |
211
+ | `prompts/list` | List all available prompts |
212
+ | `prompts/get <name> [json_args]` | Get a prompt with arguments |
213
+ | `ping` | Verify connection, show round-trip time |
214
+ | `log-level <level>` | Set server logging verbosity |
215
+ | `history [count|clear]` | Show request/response history |
216
+ | `notifications [count|clear]` | Show server notifications |
217
+ | `roots/list` | Show configured client roots |
218
+ | `roots/add <uri> [name]` | Add a root directory |
219
+ | `roots/remove <uri>` | Remove a root directory |
220
+ | `!! / last` | Re-run the last command |
221
+ | `reconnect` | Disconnect and reconnect |
222
+ | `timing` | Show tool call performance stats |
223
+ | `status` | Show target server status |
224
+ <!-- REPL_COMMANDS_END -->
181
225
 
182
226
  ### Examples
183
227
 
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { spawn } from "child_process";
11
11
 
12
12
  // src/config-scanner.ts
13
13
  import { existsSync } from "fs";
14
- import { readFile } from "fs/promises";
14
+ import { readFile, readdir } from "fs/promises";
15
15
  import { homedir } from "os";
16
16
  import path from "path";
17
17
  import process2 from "process";
@@ -57,10 +57,14 @@ function getConfigPaths() {
57
57
  { source: "Gemini CLI (Project)", file: path.join(cwd, ".gemini", "settings.json") },
58
58
  { source: "Claude Code (Global)", file: path.join(home, ".claude.json") },
59
59
  { source: "Claude Code (Project)", file: path.join(cwd, ".mcp.json") },
60
- { source: "Antigravity", file: path.join(home, ".gemini", "antigravity", "mcp_config.json") }
60
+ { source: "Antigravity", file: path.join(home, ".gemini", "antigravity", "mcp_config.json") },
61
+ {
62
+ source: "Gemini App (Global)",
63
+ file: path.join(home, ".gemini", "config", "mcp_config.json")
64
+ }
61
65
  ];
62
66
  }
63
- async function discoverServers() {
67
+ async function discoverServers(options) {
64
68
  const servers = [];
65
69
  const paths = getConfigPaths();
66
70
  for (const { source, file } of paths) {
@@ -86,10 +90,52 @@ async function discoverServers() {
86
90
  } catch {
87
91
  }
88
92
  }
93
+ if (options?.scan) {
94
+ try {
95
+ let currentDir = process2.cwd();
96
+ const visited = /* @__PURE__ */ new Set();
97
+ while (currentDir && !visited.has(currentDir)) {
98
+ visited.add(currentDir);
99
+ if (existsSync(currentDir)) {
100
+ const files = await readdir(currentDir, { withFileTypes: true });
101
+ for (const file of files) {
102
+ if (file.isFile() && file.name.endsWith(".json")) {
103
+ if (file.name === "package-lock.json" || file.name === "package.json" || file.name === "tsconfig.json") {
104
+ continue;
105
+ }
106
+ const filePath = path.join(currentDir, file.name);
107
+ try {
108
+ const content = await readFile(filePath, "utf8");
109
+ if (content.includes("mcpServers")) {
110
+ const json = JSON.parse(content);
111
+ if (json.mcpServers && typeof json.mcpServers === "object") {
112
+ for (const [name, config] of Object.entries(json.mcpServers)) {
113
+ if (config && typeof config === "object" && config.command) {
114
+ servers.push({
115
+ name,
116
+ config,
117
+ source: `Local Workspace (${file.name})`
118
+ });
119
+ }
120
+ }
121
+ }
122
+ }
123
+ } catch {
124
+ }
125
+ }
126
+ }
127
+ }
128
+ const parent = path.dirname(currentDir);
129
+ if (parent === currentDir) break;
130
+ currentDir = parent;
131
+ }
132
+ } catch {
133
+ }
134
+ }
89
135
  return servers;
90
136
  }
91
- async function pickDiscoveredServer() {
92
- const servers = await discoverServers();
137
+ async function pickDiscoveredServer(options) {
138
+ const servers = await discoverServers(options);
93
139
  if (servers.length === 0) {
94
140
  return null;
95
141
  }
@@ -99,7 +145,7 @@ async function pickDiscoveredServer() {
99
145
  if (!uniqueServers.has(key)) {
100
146
  uniqueServers.set(key, s);
101
147
  } else {
102
- if (s.source.includes("Project")) {
148
+ if (s.source.includes("Project") || s.source.includes("Local Workspace")) {
103
149
  uniqueServers.set(key, s);
104
150
  }
105
151
  }
@@ -1430,7 +1476,7 @@ var TargetManager = class _TargetManager extends EventEmitter {
1430
1476
  this.transport = stdioTransport;
1431
1477
  }
1432
1478
  this.client = new Client(
1433
- { name: "run-mcp", version: "1.7.0" },
1479
+ { name: "run-mcp", version: "1.7.1" },
1434
1480
  {
1435
1481
  capabilities: {
1436
1482
  roots: { listChanged: true },
@@ -4425,7 +4471,7 @@ async function startServer(opts) {
4425
4471
  mediaThresholdKb: opts.mediaThresholdKb
4426
4472
  });
4427
4473
  const mcpServer = new McpServer(
4428
- { name: "run-mcp", version: "1.7.0" },
4474
+ { name: "run-mcp", version: "1.7.1" },
4429
4475
  {
4430
4476
  capabilities: {
4431
4477
  tools: {},
@@ -5020,7 +5066,7 @@ Available: ${available}`
5020
5066
  },
5021
5067
  async () => {
5022
5068
  try {
5023
- const servers = await discoverServers();
5069
+ const servers = await discoverServers({ scan: opts.scan });
5024
5070
  if (servers.length === 0) {
5025
5071
  return {
5026
5072
  content: [
@@ -5454,7 +5500,7 @@ ${stderrLines.join("\n") || "(none)"}`
5454
5500
  const searchTypes = type ?? ["tools"];
5455
5501
  const lowerQuery = query.toLowerCase();
5456
5502
  try {
5457
- const servers = await discoverServers();
5503
+ const servers = await discoverServers({ scan: opts.scan });
5458
5504
  if (servers.length === 0) {
5459
5505
  return {
5460
5506
  content: [{ type: "text", text: "No local MCP servers found to search." }]
@@ -5975,7 +6021,7 @@ program.command("close-session").argument("<session_name>", "Session name").desc
5975
6021
  }
5976
6022
  }
5977
6023
  });
5978
- program.name("run-mcp").description("A smart interactive REPL and live test harness for MCP servers").version("1.7.0").passThroughOptions().allowUnknownOption().argument(
6024
+ program.name("run-mcp").description("A smart interactive REPL and live test harness for MCP servers").version("1.7.1").passThroughOptions().allowUnknownOption().argument(
5979
6025
  "[target_command...]",
5980
6026
  "Command to spawn the target MCP server (starts REPL if provided, Agent server otherwise)"
5981
6027
  ).option("-o, --out-dir <path>", "Directory to save intercepted images and audio").option(
@@ -5990,7 +6036,10 @@ program.name("run-mcp").description("A smart interactive REPL and live test harn
5990
6036
  ).option("--mcp", "Force start Agent Server mode even if run interactively without arguments").option("-s, --script <file>", "Read commands from a file instead of stdin (REPL Mode only)").option("--color <mode>", "Color output mode: always, never, auto (default: auto)").option(
5991
6037
  "--open-media",
5992
6038
  "Automatically open intercepted images and audio files using the host OS viewer"
5993
- ).option("--sandbox <mode>", "Sandbox execution mode: auto, docker, native, audit, none", "none").addHelpText(
6039
+ ).option("--sandbox <mode>", "Sandbox execution mode: auto, docker, native, audit, none", "none").option(
6040
+ "--scan",
6041
+ "Scan the current workspace and parent directories for any JSON files containing mcpServers"
6042
+ ).addHelpText(
5994
6043
  "after",
5995
6044
  `
5996
6045
  Examples:
@@ -6085,10 +6134,11 @@ Shortcuts: tl td tc ts rl rr rt rs ru pl pg (see help for details)`
6085
6134
  allowNet: opts.allowNet,
6086
6135
  denyRead: opts.denyRead,
6087
6136
  denyWrite: opts.denyWrite,
6088
- denyNet: opts.denyNet
6137
+ denyNet: opts.denyNet,
6138
+ scan: opts.scan
6089
6139
  });
6090
6140
  } else {
6091
- const selected = await pickDiscoveredServer();
6141
+ const selected = await pickDiscoveredServer({ scan: opts.scan });
6092
6142
  if (!selected) {
6093
6143
  console.log("Run 'run-mcp --help' to see manual usage instructions.");
6094
6144
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run-mcp",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "A smart proxy and interactive REPL for Model Context Protocol (MCP) servers",
5
5
  "homepage": "https://github.com/funkyfunc/run-mcp#readme",
6
6
  "bugs": {
@@ -29,7 +29,7 @@
29
29
  "run-mcp": "dist/index.js"
30
30
  },
31
31
  "scripts": {
32
- "build": "tsup",
32
+ "build": "tsup && node scripts/update-readme-help.js",
33
33
  "build:fixtures": "tsup tests/fixtures/mock-server.ts tests/fixtures/vulnerable-stdio-server.ts --format esm --target node18 --out-dir tests/fixtures/dist",
34
34
  "dev": "tsup --watch",
35
35
  "start": "node dist/index.js",