mcp2cli
Turn any MCP server, OpenAPI spec, or GraphQL endpoint into a CLI — at runtime, with zero codegen.
Save 96–99% of the tokens wasted on tool schemas every turn.
Read the full writeup →
Install
# Run directly without installing
uvx mcp2cli --help
# Or install globally
uv tool install mcp2cli
AI Agent Skill
mcp2cli ships with an installable skill that teaches AI coding agents (Claude Code, Cursor, Codex) how to use it. Once installed, your agent can discover and call any MCP server or OpenAPI endpoint — and even generate new skills from APIs.
npx skills add knowsuchagency/mcp2cli --skill mcp2cli
After installing, try prompts like:
mcp2cli --mcp https://mcp.example.com/sse— interact with an MCP servermcp2cli create a skill for https://api.example.com/openapi.json— generate a skill from an API
Usage
MCP HTTP/SSE mode
# Connect to an MCP server over HTTP
mcp2cli --mcp https://mcp.example.com/sse --list
# Call a tool
mcp2cli --mcp https://mcp.example.com/sse search --query "test"
# With auth header
mcp2cli --mcp https://mcp.example.com/sse --auth-header "x-api-key:sk-..." \
query --sql "SELECT 1"
# Force a specific transport (skip streamable HTTP fallback dance)
mcp2cli --mcp https://mcp.example.com/sse --transport sse --list
# Search tools by name or description (case-insensitive substring match)
mcp2cli --mcp https://mcp.example.com/sse --search "task"
--search implies --list and works across all modes (--mcp, --spec, --graphql, --mcp-stdio).
OAuth authentication
APIs that require OAuth are supported out of the box — across MCP, OpenAPI, and GraphQL modes. mcp2cli handles token acquisition, caching, and refresh automatically.
# Authorization code + PKCE flow (opens browser for login)
mcp2cli --mcp https://mcp.example.com/sse --oauth --list
mcp2cli --spec https://api.example.com/openapi.json --oauth --list
mcp2cli --graphql https://api.example.com/graphql --oauth --list
# Client credentials flow (machine-to-machine, no browser)
mcp2cli --spec https://api.example.com/openapi.json \
--oauth-client-id "my-client-id" \
--oauth-client-secret "my-secret" \
list-pets
# With specific scopes
mcp2cli --graphql https://api.example.com/graphql --oauth --oauth-scope "read write" users
# Local spec file — use --base-url for OAuth discovery
mcp2cli --spec ./openapi.json --base-url https://api.example.com --oauth --list
Tokens are persisted in ~/.cache/mcp2cli/oauth/ so subsequent calls reuse existing tokens
and refresh automatically when they expire.
Headless hosts — no browser on the machine running mcp2cli
The default authorization-code flow starts a callback server on 127.0.0.1, which only
works when the browser runs on the same machine. On a VPS over SSH or in a container,
add --oauth-manual-callback: mcp2cli prints the authorization URL instead of opening a
browser, and reads the redirect back from stdin.
mcp2cli --mcp https://mcp.linear.app/mcp --oauth --oauth-manual-callback --list
Open the printed URL in a browser on any machine, authorize, then paste the URL you land
on. That page will fail to load — nothing is listening on the loopback port — which is
expected; only its address matters, because it carries the code and state parameters.
PKCE and state verification are unchanged, so paste the URL unmodified.
Secrets from environment or files
Sensitive values (--auth-header values, --oauth-client-id, --oauth-client-secret) support
env: and file: prefixes to avoid passing secrets as CLI arguments (which are visible in
process listings):
# Read from environment variable
mcp2cli --mcp https://mcp.example.com/sse \
--auth-header "Authorization:env:MY_API_TOKEN" \
--list
# Read from file
mcp2cli --mcp https://mcp.example.com/sse \
--oauth-client-secret "file:/run/secrets/client_secret" \
--oauth-client-id "my-client-id" \
--list
# Works with secret managers that inject env vars
fnox exec -- mcp2cli --mcp https://mcp.example.com/sse \
--oauth-client-id "env:OAUTH_CLIENT_ID" \
--oauth-client-secret "env:OAUTH_CLIENT_SECRET" \
--list
MCP stdio mode
# List tools from an MCP server
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" --list
# Call a tool
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" \
read-file --path /tmp/hello.txt
# Pass environment variables to the server process
mcp2cli --mcp-stdio "node server.js" --env API_KEY=sk-... --env DEBUG=1 \
search --query "test"
MCP roots and completion
Expose one or more filesystem roots when a server scopes operations to a
workspace. Paths are converted to file:// URIs; explicit roots must also use
the file:// scheme.
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" \
--root "$PWD" --root file:///var/shared --list
Request prompt-argument or resource-template completions with
REF:ARG=PREFIX:
mcp2cli --mcp https://example.com/mcp \
--complete "greeting:name=San"
mcp2cli --mcp https://example.com/mcp \
--complete "file:///docs/{topic}:topic=api"
Both options work when starting a persistent session; roots are retained by
the session daemon and completion requests can be sent through --session.
OpenAPI mode
# List all commands from a remote spec
mcp2cli --spec https://petstore3.swagger.io/api/v3/openapi.json --list
# Call an endpoint
mcp2cli --spec ./openapi.json --base-url https://api.example.com list-pets --status available
# With auth
mcp2cli --spec ./spec.json --auth-header "Authorization:Bearer tok_..." create-item --name "Test"
# POST with JSON body from stdin
echo '{"name": "Fido", "tag": "dog"}' | mcp2cli --spec ./spec.json create-pet --stdin
# Local YAML spec
mcp2cli --spec ./api.yaml --base-url http://localhost:8000 --list
GraphQL mode
# List all queries and mutations from a GraphQL endpoint
mcp2cli --graphql https://api.example.com/graphql --list
# Call a query
mcp2cli --graphql https://api.example.com/graphql users --limit 10
# Call a mutation
mcp2cli --graphql https://api.example.com/graphql create-user --name "Alice" --email "[email protected]"
# Override auto-generated selection set fields
mcp2cli --graphql https://api.example.com/graphql users --fields "id name email"
# With auth
mcp2cli --graphql https://api.example.com/graphql --auth-header "Authorization:Bearer tok_..." users
mcp2cli introspects the endpoint, discovers queries and mutations, auto-generates selection sets, and constructs parameterized queries with proper variable declarations. No SDL parsing, no code generation — just point and run.
Bake mode — save connection settings
Tired of repeating --spec/--mcp/--mcp-stdio plus auth flags on every invocation? Bake them into a named configuration:
# Create a baked tool from an OpenAPI spec
mcp2cli bake create petstore --spec https://api.example.com/spec.json \
--exclude "delete-*,update-*" --methods GET,POST --cache-ttl 7200
# Create a baked tool from an MCP stdio server
mcp2cli bake create myfs --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp" \
--include "search-*,list-*" --exclude "list-allowed-*"
# Use a baked tool with @ prefix — no connection flags needed
mcp2cli @petstore --list
mcp2cli @petstore list-pets --limit 10
mcp2cli @myfs --list # search-files, list-directory, list-directory-with-sizes
mcp2cli @myfs search-files --path /tmp --pattern "**/*.md" # pattern is a glob, relative to --path
# Manage baked tools
mcp2cli bake list # show all baked tools
mcp2cli bake show petstore # show config (secrets masked)
mcp2cli bake update petstore --cache-ttl 3600
mcp2cli bake remove petstore
mcp2cli bake install petstore # creates ~/.local/bin/petstore wrapper
mcp2cli bake install petstore --dir ./scripts/ # install wrapper to custom directory
Filtering options:
--include— comma-separated glob patterns to whitelist tools (e.g."list-*,get-*")--exclude— comma-separated glob patterns to blacklist tools (e.g."delete-*")--methods— comma-separated HTTP methods to allow (e.g."GET,POST", OpenAPI only)
Configs are stored in ~/.config/mcp2cli/baked.json. Override with MCP2CLI_CONFIG_DIR.
bake show masks the credential values it knows about — the OAuth client secret and every --auth-header value — while leaving env:/file: references readable so the config stays diagnosable. Val