| name | mcp2cli-api-to-cli |
| description | 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
Skill by ara.so — MCP Skills collection.
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
uvx mcp2cli --help
uv tool install mcp2cli
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)
- GraphQL: Introspect and query GraphQL endpoints
All modes support:
- Dynamic command generation (no codegen step)
- Automatic caching with configurable TTL
- OAuth 2.0 flows (authorization code + PKCE, client credentials)
- Secret management (env vars, files)
- Usage tracking and intelligent tool ranking
MCP HTTP Mode
Connect to MCP servers over HTTP with automatic transport negotiation:
mcp2cli --mcp https://mcp.example.com/sse --list
mcp2cli --mcp https://mcp.example.com/sse search --query "rust async"
mcp2cli --mcp https://mcp.example.com/sse \
--auth-header "x-api-key:env:MCP_API_KEY" \
query --sql "SELECT * FROM users LIMIT 10"
mcp2cli --mcp https://mcp.example.com/sse --transport sse --list
mcp2cli --mcp https://mcp.example.com/sse --search "database"
MCP stdio Mode
Launch local MCP servers and communicate via stdio:
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" --list
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" \
read-file --path /tmp/data.json
mcp2cli --mcp-stdio "node ./custom-server.js" \
--env DATABASE_URL=env:DATABASE_URL \
--env DEBUG=1 \
search --query "test"
OpenAPI Mode
Generate CLI from OpenAPI specifications:
mcp2cli --spec https://petstore3.swagger.io/api/v3/openapi.json --list
mcp2cli --spec ./openapi.yaml --base-url https://api.example.com --list
mcp2cli --spec ./openapi.json --base-url https://api.example.com \
list-pets --status available --limit 20
echo '{"name": "Fido", "species": "dog"}' | \
mcp2cli --spec ./openapi.json create-pet --stdin
mcp2cli --spec ./openapi.json \
--auth-header "Authorization:Bearer env:API_TOKEN" \
create-item --name "New Item"
GraphQL Mode
Query GraphQL endpoints with automatic introspection:
mcp2cli --graphql https://api.example.com/graphql --list
mcp2cli --graphql https://api.example.com/graphql users --limit 10
mcp2cli --graphql https://api.example.com/graphql \
create-user --name "Alice" --email "alice@example.com"
mcp2cli --graphql https://api.example.com/graphql \
users --fields "id name email createdAt"
mcp2cli --graphql https://api.example.com/graphql \
--auth-header "Authorization:Bearer env:GRAPHQL_TOKEN" \
users
OAuth Authentication
All modes support OAuth 2.0 flows:
mcp2cli --mcp https://mcp.example.com/sse --oauth --list
mcp2cli --spec https://api.example.com/openapi.json --oauth list-users
mcp2cli --graphql https://api.example.com/graphql --oauth users
mcp2cli --spec https://api.example.com/openapi.json \
--oauth-client-id "env:OAUTH_CLIENT_ID" \
--oauth-client-secret "env:OAUTH_CLIENT_SECRET" \
list-resources
mcp2cli --graphql https://api.example.com/graphql \
--oauth --oauth-scope "read:users write:users" \
users
mcp2cli --spec ./openapi.json \
--base-url https://api.example.com \
--oauth \
--list
Tokens are cached in ~/.cache/mcp2cli/oauth/ and automatically refreshed.
Secret Management
Avoid passing secrets as CLI arguments:
mcp2cli --mcp https://mcp.example.com/sse \
--auth-header "Authorization:env:MY_API_TOKEN" \
--list
mcp2cli --spec ./openapi.json \
--oauth-client-secret "file:/run/secrets/client_secret" \
--oauth-client-id "file:/run/secrets/client_id" \
--list
vault kv get -field=token secret/api | \
MY_TOKEN=$(cat) mcp2cli --mcp https://mcp.example.com/sse \
--auth-header "Authorization:env:MY_TOKEN" \
search --query "data"
Bake Mode — Save Connection Settings
Create reusable named configurations:
mcp2cli bake create petstore \
--spec https://api.example.com/openapi.json \
--auth-header "Authorization:Bearer env:PETSTORE_TOKEN" \
--exclude "delete-*,update-*" \
--methods GET,POST \
--cache-ttl 7200
mcp2cli bake create github \
--mcp-stdio "npx @modelcontextprotocol/server-github" \
--env GITHUB_TOKEN=env:GITHUB_TOKEN \
--include "search-*,list-*" \
--exclude "delete-*"
mcp2cli bake create hasura \
--graphql https://hasura.example.com/v1/graphql \
--auth-header "x-hasura-admin-secret:env:HASURA_SECRET"
mcp2cli @petstore --list
mcp2cli @petstore list-pets --limit 5
mcp2cli @github search-repos --query "mcp server"
mcp2cli @hasura users --limit 10
mcp2cli bake list
mcp2cli bake show petstore
mcp2cli bake update petstore --cache-ttl 3600
mcp2cli bake remove petstore
mcp2cli bake install petstore
mcp2cli bake install petstore --dir ./scripts/
Filtering Options
mcp2cli bake create myapi \
--spec ./openapi.json \
--include "list-*,get-*,search-*"
mcp2cli bake create myapi \
--spec ./openapi.json \
--exclude "delete-*,destroy-*"
mcp2cli bake create myapi \
--spec ./openapi.json \
--methods GET,POST
Usage-Aware Tool Ranking
Reduce token costs with intelligent tool ranking:
mcp2cli @myapi --list
mcp2cli @myapi --list --top 10 --compact
mcp2cli @myapi --list --sort recent
mcp2cli @myapi --list --sort alpha
mcp2cli @myapi --list --verbose
Usage data is tracked locally in ~/.cache/mcp2cli/usage.json.
Output Control
mcp2cli --spec ./openapi.json --pretty list-users
mcp2cli --spec ./openapi.json --raw get-binary-data
mcp2cli --spec ./openapi.json list-logs --head 20
mcp2cli --mcp https://mcp.example.com/sse --toon list-large-dataset
mcp2cli --spec ./openapi.json list-users | jq '.[] | .email'
Caching
Control spec and tool list caching:
mcp2cli --spec https://api.example.com/openapi.json --refresh --list
mcp2cli --spec https://api.example.com/openapi.json --cache-ttl 604800 --list
mcp2cli --spec https://api.example.com/openapi.json --cache-key prod-api --list
MCP2CLI_CACHE_DIR=/tmp/my-cache mcp2cli --spec ./openapi.json --list
Default cache location: ~/.cache/mcp2cli/
Default TTL: 3600 seconds (1 hour)
Common Patterns
Create a Skill from an API
mcp2cli --spec https://api.example.com/openapi.json --list
mcp2cli bake create myservice \
--spec https://api.example.com/openapi.json \
--auth-header "Authorization:Bearer env:MYSERVICE_TOKEN"
mcp2cli @myservice list-resources --format json | jq '.[] | select(.active == true)'
Multi-Environment Setup
mcp2cli bake create myapi-dev \
--spec https://dev-api.example.com/openapi.json \
--auth-header "Authorization:Bearer env:DEV_TOKEN"
mcp2cli bake create myapi-prod \
--spec https://api.example.com/openapi.json \
--auth-header "Authorization:Bearer env:PROD_TOKEN"
mcp2cli @myapi-dev test-endpoint --data "test"
mcp2cli @myapi-prod get-metrics --period "24h"
Chaining with MCP Servers
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
mcp2cli @myapi --search "user"
mcp2cli @myapi --list | grep "^create-"
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
async def call_api():
spec = await load_spec("https://api.example.com/openapi.json")
response = await make_request(
spec=spec,
operation_id="listPets",
params={"limit": 10},
auth_headers={"Authorization": "Bearer token"}
)
return response
result = asyncio.run(call_api())
Troubleshooting
OAuth Flow Fails
rm -rf ~/.cache/mcp2cli/oauth/
mcp2cli --spec ./openapi.json --oauth --list --verbose
MCP Server Connection Issues
mcp2cli --mcp https://mcp.example.com/sse --transport sse --list
mcp2cli --mcp https://mcp.example.com/sse --transport streamable --list
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" \
--env DEBUG=* \
--list
Cache Issues
mcp2cli --spec ./openapi.json --refresh --list
rm -rf ~/.cache/mcp2cli/
MCP2CLI_CACHE_DIR=/tmp/test-cache mcp2cli --spec ./openapi.json --list
Tool Not Found After Baking
mcp2cli bake list
mcp2cli bake show myapi
mcp2cli bake update myapi --include "*"
Large Response Truncation
mcp2cli @myapi list-all --head 100
mcp2cli @myapi list-all --raw > output.json
mcp2cli @myapi list-all --toon
Configuration
Configuration directory: ~/.config/mcp2cli/
Cache directory: ~/.cache/mcp2cli/
Override with environment variables:
MCP2CLI_CONFIG_DIR: Configuration directory
MCP2CLI_CACHE_DIR: Cache directory
Baked tools are stored in ~/.config/mcp2cli/baked.json
Usage tracking in ~/.cache/mcp2cli/usage.json
OAuth tokens in ~/.cache/mcp2cli/oauth/