Turn any MCP, OpenAPI, or GraphQL server into a CLI at runtime with zero codegen, saving 96-99% of tokens wasted on tool schemas
triggers
["create a CLI from an API specification","connect to an MCP server over HTTP","turn this OpenAPI spec into a command line tool","query a GraphQL endpoint from the command line","save API connection settings for reuse","use mcp2cli to interact with this service","generate a skill from an OpenAPI spec","list available tools from an MCP server"]
mcp2cli converts any MCP server, OpenAPI specification, or GraphQL endpoint into a CLI at runtime without code generation. It dramatically reduces token consumption by replacing repeated tool schema transmissions with simple CLI calls — saving 96-99% of tokens on every LLM turn.
Installation
# Run directly without installing
uvx mcp2cli --help# Or install globally
uv tool install mcp2cli
# Install as a skill for AI agents
npx skills add knowsuchagency/mcp2cli --skill mcp2cli
Core Concepts
mcp2cli operates in four modes:
MCP HTTP/SSE: Connect to MCP servers over HTTP with SSE or streamable HTTP transport
MCP stdio: Launch and communicate with local MCP servers via stdio
OpenAPI: Generate CLI from OpenAPI 3.x specs (JSON or YAML)
# Use filesystem MCP to read config, then call API
CONFIG=$(mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /etc" \
read-file --path /etc/myapp/config.json)
echo"$CONFIG" | jq -r '.api_endpoint' | \
xargs -I {} mcp2cli --spec {}/openapi.json --list
Filtering Large Tool Lists
# Search tools related to users
mcp2cli @myapi --search "user"# List only creation operations
mcp2cli @myapi --list | grep "^create-"# Get compact list of top tools for LLM context
mcp2cli @myapi --list --top 20 --compact
Python API Usage
While mcp2cli is primarily a CLI tool, you can use its components programmatically:
from mcp2cli.openapi import load_spec
from mcp2cli.client import make_request
import asyncio
asyncdefcall_api():
# Load OpenAPI spec
spec = await load_spec("https://api.example.com/openapi.json")
# Make request
response = await make_request(
spec=spec,
operation_id="listPets",
params={"limit": 10},
auth_headers={"Authorization": "Bearer token"}
)
return response
result = asyncio.run(call_api())
# Test transport explicitly
mcp2cli --mcp https://mcp.example.com/sse --transport sse --list
mcp2cli --mcp https://mcp.example.com/sse --transport streamable --list
# Check server logs if using stdio
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" \
--env DEBUG=* \
--list
Cache Issues
# Force refresh
mcp2cli --spec ./openapi.json --refresh --list
# Clear all cacherm -rf ~/.cache/mcp2cli/
# Use temporary cache location
MCP2CLI_CACHE_DIR=/tmp/test-cache mcp2cli --spec ./openapi.json --list
Tool Not Found After Baking
# Check baked tool exists
mcp2cli bake list
# Verify configuration
mcp2cli bake show myapi
# Recreate with explicit filters
mcp2cli bake update myapi --include "*"
Large Response Truncation
# Use --head to limit records
mcp2cli @myapi list-all --head 100
# Use --raw to get full response
mcp2cli @myapi list-all --raw > output.json
# Use TOON for token efficiency
mcp2cli @myapi list-all --toon