| summary | Behavior and architecture of mcporter generate-cli, including outputs, runtimes, regeneration, and policy boundaries. | |
|---|---|---|
| read_when |
|
mcporter generate-cli produces a standalone CLI for one MCP server. Tool schemas become subcommands and schema fields become positional arguments or flags. By default, the command writes <server>.ts in the working directory. Bundling is opt-in via --bundle; Rolldown handles Node.js output, while Bun’s native bundler handles Bun output. Use --bundler to override that choice.
- Generated CLI depends on the latest
commanderfor argument parsing. - Default timeout for tool calls is 30 seconds, overridable via
--timeout. - Runtime flag remains (
--runtime bun) to tailor shebang/usage instructions, but Node.js is the default. - Generated CLI embeds the resolved server definition and always targets that snapshot (no external
--configor--serveroverrides at runtime).
# Minimal: infer the name from the command URL and emit TypeScript (optionally bundle)
npx mcporter generate-cli \
--command https://mcp.context7.com/mcp \
--minify
# Provide explicit name/description and compile a Bun binary (falls back to Node if Bun missing)
npx mcporter generate-cli \
--name context7 \
--command https://mcp.context7.com/mcp \
--description "Context7 docs MCP" \
--runtime bun \
--compile
chmod +x context7
./context7
# show the embedded help + tool list
# Shareable "one weird trick" for chrome-devtools (no config required)
npx mcporter generate-cli --command "npx -y chrome-devtools-mcp@latest"--minifyshrinks the bundled output via the selected bundler (output defaults to<server>.js).--compile [path]implies bundling and invokesbun build --compileto create the native executable (Bun only). When you omit the path, the compiled binary inherits the server name.- Use
--server '{...}'when you need advanced configuration (headers, env vars, stdio commands, OAuth metadata). - Omit
--nameto let mcporter infer it from the command URL (for example,https://mcp.context7.com/mcpbecomescontext7). - When targeting an existing config entry, you can skip
--serverand pass the name as a positional argument:npx mcporter generate-cli linear --bundle dist/linear.js. - When the MCP server is a stdio command, you can also skip
--commandby quoting the inline command as the first positional argument (e.g.,npx mcporter generate-cli "npx -y chrome-devtools-mcp@latest"). - Generated CLIs preserve
lifecycle: "keep-alive"for embedded stdio servers. At runtime they create a stable generated config under~/.mcporter/generated/(or$XDG_STATE_HOME/mcporter/generated/when set), auto-start the daemon as needed, and keep the server process alive across separate generated-CLI invocations. - Narrow the CLI to a specific subset of tools with
--include-tools:npx mcporter generate-cli linear --include-tools issues_list,issues_create. - Hide debug or admin tools with
--exclude-tools:npx mcporter generate-cli linear --exclude-tools debug_tool,admin_reset.
- Every generated artifact embeds its metadata (generator version, resolved server definition, invocation flags). A hidden
__mcporter_inspectsubcommand prints the payload without contacting the MCP server, so binaries remain self-describing even after being copied to another machine. mcporter inspect-cli <artifact>shells out to that embedded command and prints a human summary (pass--jsonfor raw output). The summary includes a ready-to-rungenerate-clicommand you can reuse directly.mcporter generate-cli --from <artifact>replays the stored invocation against the latest mcporter build.--server,--runtime,--timeout,--minify/--no-minify,--bundle,--compile,--output, and--dry-runlet you override specific pieces of the stored metadata when necessary.- Because the metadata lives inside the artifact, any template, bundle, or compiled binary can be refreshed after a generator upgrade without juggling sidecar files.
A generated CLI or typed client can be invoked independently of the MCP client that originally configured the server. It therefore does not automatically inherit that client's approval prompts, tool-call policies, or audit trail.
Use --include-tools to reduce the generated surface, but do not treat a static
tool list as dynamic authorization. Deployments that need per-call policy should
route the generated command through an external wrapper or policy gateway that:
- normalizes the server, tool name, and arguments;
- evaluates current policy and requests approval when required;
- blocks the call or invokes the generated CLI; and
- persists a redacted decision and result record.
Conceptual wrapper pseudocode (not a built-in mcporter API):
const operation = normalize({ server, tool, arguments });
let decision;
let outcome = 'evaluation_failed';
let result;
let failure;
try {
decision = await gateway.evaluate(operation);
if (decision.action === 'block') {
outcome = 'blocked';
failure = 'policy_block';
throw new Error(decision.reason);
}
if (decision.action === 'approve' && !(await approvals.confirm(decision))) {
outcome = 'approval_declined';
failure = 'approval_declined';
throw new Error('Approval declined');
}
try {
result = await generatedCli.call(tool, arguments);
outcome = 'succeeded';
return result;
} catch (error) {
outcome = 'execution_failed';
failure = classifyError(error);
throw error;
}
} catch (error) {
failure ??= classifyError(error);
throw error;
} finally {
await audit.append(redact({ operation, decision, outcome, result, failure }));
}The finally path records a redacted outcome for blocked requests, declined
approvals, policy-evaluation failures, execution failures, and successful calls.
The wrapper governs only calls routed through it. Direct execution of the
generated artifact bypasses that policy boundary.