Skip to main content
fastmcp list and fastmcp call let you poke at a server interactively, but they’re developer tools — you always have to spell out the server spec, the tool name, and the arguments. fastmcp generate-cli takes the next step: it connects to a server, reads its schemas, and writes a standalone Python script where every tool is a proper subcommand with typed flags, help text, and tab completion. The result is a CLI that feels like it was hand-written for that specific server. The key insight is that MCP tool schemas already contain everything a CLI framework needs: parameter names, types, descriptions, required/optional status, and defaults. generate-cli maps that schema into cyclopts commands, so JSON Schema types become Python type annotations, descriptions become --help text, and required parameters become mandatory flags.

Generating a Script

Point the command at any server spec — URLs, Python files, discovered server names, MCPConfig JSON — and it writes a CLI script:
The second positional argument sets the output path. When omitted, it defaults to cli.py. If the file already exists, the command refuses to overwrite unless you pass -f:
Name-based resolution works here too, so if you have a server configured in Claude Desktop, Cursor, or any other supported editor, you can reference it by name. Run fastmcp discover to see what’s available.
The --timeout and --auth flags work the same way they do in fastmcp list and fastmcp call.

What You Get

The generated script is a regular Python file — executable, editable, and yours. Here’s what it looks like in practice:
The call-tool subcommand is where the generated code lives. Each tool on the server becomes its own command:
And each tool has typed parameters with help text pulled directly from the server’s schema:
Tool names are preserved exactly as the server defines them — underscores stay as underscores, so call-tool get_forecast matches what the server expects.

How It Works

The generated script is a client, not a server. It doesn’t bundle or embed the MCP server — it connects to it on every invocation. For URL-based servers, the server needs to be running. For stdio-based servers, the command specified in CLIENT_SPEC must be available on the system’s PATH. At the top of the generated file, a CLIENT_SPEC variable holds the resolved transport: either a URL string or a StdioTransport with the command and arguments baked in. Every invocation connects through this spec, so the script works without any external configuration.

Parameter Handling

Parameters are mapped intelligently based on their complexity: Simple types (string, integer, number, boolean) become typed Python parameters with clean flags:
Arrays of simple types (array with string/integer/number/boolean items) become list[T] parameters that accept multiple flags:
Complex types (objects, nested arrays, or unions) accept JSON strings. The tool’s --help displays the full JSON schema so you know exactly what structure to pass:
Required parameters are mandatory flags; optional ones default to their schema default or None. Empty values are filtered out before calling the server. Beyond tool commands, the script includes generic commands that work regardless of what the server exposes: list-tools, list-resources, read-resource, list-prompts, and get-prompt. These connect to the server at runtime, so they always reflect the server’s current state even if the tools have changed since generation.

Editing the Output

The most common edit is changing CLIENT_SPEC. If you generated from a local dev server and want to point at production, just change the string. If you generated from a discovered name and want to pin the transport, replace it with an explicit URL or StdioTransport. Beyond that, it’s a regular Python file. You can add commands, change the output formatting, integrate it into a larger application, or strip out the parts you don’t need. The helper functions (_call_tool, _print_tool_result) are thin wrappers around fastmcp.Client that are easy to adapt. The generated script requires fastmcp as a dependency. If the script lives outside a project that already has fastmcp installed, uv run is the easiest way to run it without permanent installation: