4.5 KiB
4.5 KiB
CLI Generator Plan
Default behavior: generating generated/<server>-cli.ts if no output path is provided. Bundling is opt-in via --bundle and produces a single JS file with shebang; otherwise we emit TypeScript targeting Node.js.
Goal
Create an mcp-runtime generate-cli command that produces a standalone CLI for a single MCP server. The generated CLI should feel like a Unix tool: subcommands map to MCP tools, arguments translate to schema fields, and output can be piped/redirected easily.
High-Level Requirements
- Input: Identify the target server either by shorthand name or by providing an explicit MCP server definition.
- Output: Emit a TypeScript file (ESM) targeting Node.js by default (
generated/<server>-cli.tsunless--outputoverrides). Bundling to a standalone JS file happens only when--bundleis passed. - Runtime Selection: Node.js by default; allow
--runtime bunto emit Bun-friendly entry points if requested. - Schema-Aware CLI: Leverage
createServerProxyto map positional/flag arguments to MCP tool schemas, including defaults and required validation. - Unix-Friendly Output: Provide
--output text|json|markdown|rawflags so results can be piped; default to human-readable text. Include--timeout(default 30s) to cap call duration. - Shell Completion (optional): Generate completion scripts for bash/zsh/fish if requested.
- Documentation: Update README (or similar) to show how to generate and use the CLI.
Steps
- Command Scaffolding
- Add
generate-clisubcommand to the existing CLI. - Parse flags:
--server,--output,--runtime=node|bun,--format=ts|js,--bundle, etc.
- Add
- Server Resolution
- If
--servermatches a configured name (vialoadServerDefinitions), use that server definition. - Otherwise, if the value looks like a file path, load a Cursor-style JSON definition from disk.
- Otherwise, attempt to parse inline JSON/JSON5.
- Validate that a definition is found; prompt on failure.
- If
- Tool Introspection
- Use
listTools(server, { includeSchema: true })to inspect MCP tool schemas. - For each tool, extract required/optional arguments, types, and defaults.
- Use
- Template Generation
- Build a template (probably EJS or string interpolation) that:
- Imports
createRuntimeandcreateServerProxy. - Creates a CLI (likely using
commanderor a minimal custom parser) with subcommands per tool. - Bakes in server metadata (command/url, headers, etc.) or references config path if preferred.
- Adds output-format handling.
- Imports
- Include
package.jsonscaffolding if--bundleor--packageis set.
- Build a template (probably EJS or string interpolation) that:
- Optional Bundling
- If requested, run a bundler (e.g.,
tsup) to emit a single JS file with shebang. - Otherwise, leave as TypeScript/ESM and document how to run (
node path/to/cli.jsorbun path/to/cli.ts).
- If requested, run a bundler (e.g.,
- Testing
- Add generator unit tests (snapshot the emitted CLI for known schemas).
- Add integration tests that run the generated script against a mock MCP server.
- Docs/Examples
- Document usage in README.
- Provide an example generated CLI under
examples/generated/<server>-cli.ts. (e.g.,examples/generated/context7-cli.ts).
Notes
- 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 yet honors
--config/--serveroverrides at execution time.
Status
- ✅
generate-clisubcommand scaffolding implemented (core schema mapping, commander-based output). - ✅ Inline JSON / file / shorthand server resolution wired up.
- ✅ CLI generator writes TypeScript by default and supports optional bundling via esbuild.
- ✅ New integration test (
tests/generate-cli.test.ts) spins up a mock MCP server and validates the generated CLI end-to-end. - ⏳ Current blocker: bundled output still references helper functions outside scope (e.g.,
normalizeEmbeddedServer), causing runtime failures. Need to inline helper or avoid bundling until fixed.
Next steps:
- Inline or export utility helpers so bundled output can execute without missing references (resolve
normalizeEmbeddedServererror). - Clean up esbuild configuration to produce consistent shebang and module format (node vs bun).
- Polish README/Docs to highlight
generate-cliusage once bundling is stable.