mcp-agents 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.
Files changed (3) hide show
  1. package/README.md +4 -3
  2. package/package.json +1 -1
  3. package/server.js +41 -19
package/README.md CHANGED
@@ -24,6 +24,7 @@ npx mcp-agents
24
24
  # Specific provider
25
25
  npx mcp-agents --provider claude
26
26
  npx mcp-agents --provider gemini
27
+ npx mcp-agents --provider gemini --sandbox false
27
28
  ```
28
29
 
29
30
  The server speaks [JSON-RPC over stdio](https://modelcontextprotocol.io/docs/concepts/transports#stdio). It prints `[mcp-agents] ready (provider: <name>)` to stderr when it's listening.
@@ -50,7 +51,7 @@ Each `--provider` flag maps to a single exposed tool:
50
51
  | Parameter | Type | Required | Description |
51
52
  |-----------|------|----------|-------------|
52
53
  | `prompt` | `string` | yes | The prompt to send to Gemini CLI |
53
- | `sandbox` | `boolean` | no | Run in sandbox mode (`-s` flag) |
54
+ | `sandbox` | `boolean` | no | Run in sandbox mode (`-s` flag, default: false) |
54
55
  | `timeout_ms` | `integer` | no | Timeout in ms (default: 120 000) |
55
56
 
56
57
  ### `codex` (pass-through)
@@ -78,7 +79,7 @@ Add entries to your project's `.mcp.json`:
78
79
  },
79
80
  "gemini": {
80
81
  "command": "npx",
81
- "args": ["-y", "mcp-agents@latest", "--provider", "gemini"]
82
+ "args": ["-y", "mcp-agents@latest", "--provider", "gemini", "--sandbox", "false"]
82
83
  }
83
84
  }
84
85
  }
@@ -108,7 +109,7 @@ args = ["-y", "mcp-agents", "--provider", "claude"]
108
109
 
109
110
  [mcp_servers.gemini]
110
111
  command = "npx"
111
- args = ["-y", "mcp-agents", "--provider", "gemini"]
112
+ args = ["-y", "mcp-agents", "--provider", "gemini", "--sandbox", "false"]
112
113
  ```
113
114
 
114
115
  Then in a Codex session you can call the `claude_code` or `gemini` tools, which shell out to the respective CLIs.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-agents",
3
- "version": "0.3.6",
3
+ "version": "0.5.0",
4
4
  "description": "MCP server that wraps AI CLI tools (Claude Code, Gemini CLI, Codex CLI) for use by any MCP client",
5
5
  "type": "module",
6
6
  "bin": {
package/server.js CHANGED
@@ -29,25 +29,27 @@ const CLI_BACKENDS = {
29
29
  claude: {
30
30
  command: "claude",
31
31
  toolName: "claude_code",
32
- description: "Run Claude Code CLI (claude -p) with a prompt.",
33
- buildArgs: (prompt) => ["--no-session-persistence", "-p", prompt],
32
+ description: "Run Claude Code CLI with a prompt (via stdin).",
33
+ stdinPrompt: true,
34
+ buildArgs: () => ["--no-session-persistence", "-p"],
34
35
  extraProperties: {},
35
36
  },
36
37
  gemini: {
37
38
  command: "gemini",
38
39
  toolName: "gemini",
39
40
  description: "Run Gemini CLI (gemini -p) with a prompt.",
41
+ stdinPrompt: false,
40
42
  buildArgs: (prompt, opts) => {
41
43
  const args = [];
42
- if (opts.sandbox !== false) args.push("-s");
44
+ if (opts.sandbox === true) args.push("-s");
43
45
  args.push("-p", prompt);
44
46
  return args;
45
47
  },
46
48
  extraProperties: {
47
49
  sandbox: {
48
50
  type: "boolean",
49
- default: true,
50
- description: "Run in sandbox mode (-s flag). Defaults to true.",
51
+ default: false,
52
+ description: "Run in sandbox mode (-s flag). Defaults to false.",
51
53
  },
52
54
  },
53
55
  },
@@ -92,20 +94,22 @@ Options:
92
94
  --provider <name> CLI backend to use (${providers}) [default: codex]
93
95
  --model <model> Model to use (codex) [default: gpt-5.3-codex]
94
96
  --model_reasoning_effort <e> Reasoning effort (codex) [default: high]
97
+ --sandbox <bool> Gemini sandbox mode (true/false) [default: false]
95
98
  --help, -h Show this help message
96
99
  --version, -v Show version number`);
97
100
  }
98
101
 
99
102
  /**
100
103
  * Parse CLI flags from process.argv.
101
- * Handles --help, --version, --provider, --model, --model_reasoning_effort, and unknown flags.
102
- * @returns {{ provider: string, model?: string, modelReasoningEffort?: string }}
104
+ * Handles --help, --version, --provider, --model, --model_reasoning_effort, --sandbox, and unknown flags.
105
+ * @returns {{ provider: string, model?: string, modelReasoningEffort?: string, sandbox: boolean }}
103
106
  */
104
107
  function parseArgs() {
105
108
  const args = process.argv.slice(2);
106
109
  let provider = "codex";
107
110
  let model;
108
111
  let modelReasoningEffort;
112
+ let sandbox = false;
109
113
 
110
114
  for (let i = 0; i < args.length; i++) {
111
115
  switch (args[i]) {
@@ -142,24 +146,32 @@ function parseArgs() {
142
146
  }
143
147
  modelReasoningEffort = args[++i];
144
148
  break;
149
+ case "--sandbox":
150
+ if (i + 1 >= args.length) {
151
+ process.stderr.write("error: --sandbox requires a value\n");
152
+ process.exit(1);
153
+ }
154
+ sandbox = args[++i] === "true";
155
+ break;
145
156
  default:
146
157
  process.stderr.write(`error: unknown option: ${args[i]}\n`);
147
158
  process.exit(1);
148
159
  }
149
160
  }
150
161
 
151
- return { provider, model, modelReasoningEffort };
162
+ return { provider, model, modelReasoningEffort, sandbox };
152
163
  }
153
164
 
154
165
  /**
155
166
  * Run a CLI command and return stdout (or stderr if stdout is empty).
156
167
  * @param {string} command
157
168
  * @param {string[]} args
158
- * @param {{ timeoutMs?: number }} [opts]
169
+ * @param {{ timeoutMs?: number, stdinData?: string }} [opts]
159
170
  * @returns {Promise<string>}
160
171
  */
161
172
  function runCli(command, args, opts = {}) {
162
173
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
174
+ const stdinData = opts.stdinData;
163
175
 
164
176
  return new Promise((resolve, reject) => {
165
177
  const child = execFile(
@@ -188,10 +200,13 @@ function runCli(command, args, opts = {}) {
188
200
  },
189
201
  );
190
202
 
191
- // Close stdin immediately so the child process doesn't wait for piped input.
192
- // execFile creates a pipe for stdin by default; leaving it open causes
193
- // the child to hang indefinitely waiting for EOF.
194
- child.stdin?.end();
203
+ // Pipe prompt via stdin to avoid arg-quoting issues, then close.
204
+ child.stdin?.on("error", () => {}); // ignore EPIPE if child exits early
205
+ if (stdinData != null) {
206
+ child.stdin?.end(stdinData, "utf8");
207
+ } else {
208
+ child.stdin?.end();
209
+ }
195
210
 
196
211
  child.on("error", (err) => {
197
212
  reject(new Error(`Failed to start ${command}: ${err.message}`));
@@ -235,7 +250,7 @@ function runCodexPassthrough({ model, modelReasoningEffort }) {
235
250
  // ---------------------------------------------------------------------------
236
251
 
237
252
  async function main() {
238
- const { provider: providerName, model, modelReasoningEffort } = parseArgs();
253
+ const { provider: providerName, model, modelReasoningEffort, sandbox } = parseArgs();
239
254
  const backend = CLI_BACKENDS[providerName];
240
255
 
241
256
  if (!backend) {
@@ -250,6 +265,10 @@ async function main() {
250
265
  return;
251
266
  }
252
267
 
268
+ if (backend.extraProperties.sandbox) {
269
+ backend.extraProperties.sandbox.default = sandbox;
270
+ }
271
+
253
272
  const server = new Server(
254
273
  { name: "mcp-agents", version: VERSION },
255
274
  { capabilities: { tools: {} } },
@@ -330,16 +349,19 @@ async function main() {
330
349
 
331
350
  const extraOpts = {};
332
351
  for (const key of Object.keys(backend.extraProperties)) {
333
- if (params.arguments?.[key] != null) {
334
- extraOpts[key] = params.arguments[key];
335
- }
352
+ extraOpts[key] = params.arguments?.[key] ?? backend.extraProperties[key].default;
336
353
  }
337
354
 
338
- const cliArgs = backend.buildArgs(prompt, extraOpts);
355
+ const cliArgs = backend.stdinPrompt
356
+ ? backend.buildArgs(extraOpts)
357
+ : backend.buildArgs(prompt, extraOpts);
358
+ const cliOpts = backend.stdinPrompt
359
+ ? { timeoutMs, stdinData: prompt }
360
+ : { timeoutMs };
339
361
 
340
362
  logErr(`[mcp-agents] tools/call: running ${backend.command} …`);
341
363
  try {
342
- const output = await runCli(backend.command, cliArgs, { timeoutMs });
364
+ const output = await runCli(backend.command, cliArgs, cliOpts);
343
365
  logErr("[mcp-agents] tools/call: done");
344
366
  return {
345
367
  content: [{ type: "text", text: output || "" }],