{"id":46795153,"url":"https://github.com/knowsuchagency/mcp2cli","last_synced_at":"2026-04-04T13:56:48.785Z","repository":{"id":343143278,"uuid":"1176469774","full_name":"knowsuchagency/mcp2cli","owner":"knowsuchagency","description":"Turn any MCP, OpenAPI, or GraphQL server into a CLI — at runtime, with zero codegen","archived":false,"fork":false,"pushed_at":"2026-03-26T03:51:46.000Z","size":35326,"stargazers_count":1693,"open_issues_count":2,"forks_count":116,"subscribers_count":9,"default_branch":"main","last_synced_at":"2026-03-27T00:37:05.408Z","etag":null,"topics":["ai","cli","graphql","mcp","openapi"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/mcp2cli/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/knowsuchagency.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-09T03:46:37.000Z","updated_at":"2026-03-27T00:02:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/knowsuchagency/mcp2cli","commit_stats":null,"previous_names":["knowsuchagency/mcp2cli"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/knowsuchagency/mcp2cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowsuchagency%2Fmcp2cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowsuchagency%2Fmcp2cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowsuchagency%2Fmcp2cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowsuchagency%2Fmcp2cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/knowsuchagency","download_url":"https://codeload.github.com/knowsuchagency/mcp2cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/knowsuchagency%2Fmcp2cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31402276,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","cli","graphql","mcp","openapi"],"created_at":"2026-03-10T04:00:30.642Z","updated_at":"2026-04-04T13:56:48.777Z","avatar_url":"https://github.com/knowsuchagency.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/knowsuchagency/mcp2cli/main/assets/hero.png\" alt=\"mcp2cli — one CLI for every API\" width=\"700\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003emcp2cli\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  Turn any MCP server, OpenAPI spec, or GraphQL endpoint into a CLI — at runtime, with zero codegen.\u003cbr\u003e\n  \u003cstrong\u003eSave 96–99% of the tokens wasted on tool schemas every turn.\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n  \u003ca href=\"https://www.orangecountyai.com/blog/mcp2cli-one-cli-for-every-api-zero-wasted-tokens\"\u003e\u003cstrong\u003eRead the full writeup →\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Install\n\n```bash\n# Run directly without installing\nuvx mcp2cli --help\n\n# Or install globally\nuv tool install mcp2cli\n```\n\n## AI Agent Skill\n\nmcp2cli ships with an installable [skill](https://skills.sh) 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.\n\n```bash\nnpx skills add knowsuchagency/mcp2cli --skill mcp2cli\n```\n\nAfter installing, try prompts like:\n- `mcp2cli --mcp https://mcp.example.com/sse` — interact with an MCP server\n- `mcp2cli create a skill for https://api.example.com/openapi.json` — generate a skill from an API\n\n## Usage\n\n### MCP HTTP/SSE mode\n\n```bash\n# Connect to an MCP server over HTTP\nmcp2cli --mcp https://mcp.example.com/sse --list\n\n# Call a tool\nmcp2cli --mcp https://mcp.example.com/sse search --query \"test\"\n\n# With auth header\nmcp2cli --mcp https://mcp.example.com/sse --auth-header \"x-api-key:sk-...\" \\\n  query --sql \"SELECT 1\"\n\n# Force a specific transport (skip streamable HTTP fallback dance)\nmcp2cli --mcp https://mcp.example.com/sse --transport sse --list\n\n# Search tools by name or description (case-insensitive substring match)\nmcp2cli --mcp https://mcp.example.com/sse --search \"task\"\n```\n\n`--search` implies `--list` and works across all modes (`--mcp`, `--spec`, `--graphql`, `--mcp-stdio`).\n\n### OAuth authentication\n\nAPIs that require OAuth are supported out of the box — across MCP, OpenAPI, and GraphQL modes.\nmcp2cli handles token acquisition, caching, and refresh automatically.\n\n```bash\n# Authorization code + PKCE flow (opens browser for login)\nmcp2cli --mcp https://mcp.example.com/sse --oauth --list\nmcp2cli --spec https://api.example.com/openapi.json --oauth --list\nmcp2cli --graphql https://api.example.com/graphql --oauth --list\n\n# Client credentials flow (machine-to-machine, no browser)\nmcp2cli --spec https://api.example.com/openapi.json \\\n  --oauth-client-id \"my-client-id\" \\\n  --oauth-client-secret \"my-secret\" \\\n  list-pets\n\n# With specific scopes\nmcp2cli --graphql https://api.example.com/graphql --oauth --oauth-scope \"read write\" users\n\n# Local spec file — use --base-url for OAuth discovery\nmcp2cli --spec ./openapi.json --base-url https://api.example.com --oauth --list\n```\n\nTokens are persisted in `~/.cache/mcp2cli/oauth/` so subsequent calls reuse existing tokens\nand refresh automatically when they expire.\n\n### Secrets from environment or files\n\nSensitive values (`--auth-header` values, `--oauth-client-id`, `--oauth-client-secret`) support\n`env:` and `file:` prefixes to avoid passing secrets as CLI arguments (which are visible in\nprocess listings):\n\n```bash\n# Read from environment variable\nmcp2cli --mcp https://mcp.example.com/sse \\\n  --auth-header \"Authorization:env:MY_API_TOKEN\" \\\n  --list\n\n# Read from file\nmcp2cli --mcp https://mcp.example.com/sse \\\n  --oauth-client-secret \"file:/run/secrets/client_secret\" \\\n  --oauth-client-id \"my-client-id\" \\\n  --list\n\n# Works with secret managers that inject env vars\nfnox exec -- mcp2cli --mcp https://mcp.example.com/sse \\\n  --oauth-client-id \"env:OAUTH_CLIENT_ID\" \\\n  --oauth-client-secret \"env:OAUTH_CLIENT_SECRET\" \\\n  --list\n```\n\n### MCP stdio mode\n\n```bash\n# List tools from an MCP server\nmcp2cli --mcp-stdio \"npx @modelcontextprotocol/server-filesystem /tmp\" --list\n\n# Call a tool\nmcp2cli --mcp-stdio \"npx @modelcontextprotocol/server-filesystem /tmp\" \\\n  read-file --path /tmp/hello.txt\n\n# Pass environment variables to the server process\nmcp2cli --mcp-stdio \"node server.js\" --env API_KEY=sk-... --env DEBUG=1 \\\n  search --query \"test\"\n```\n\n### OpenAPI mode\n\n```bash\n# List all commands from a remote spec\nmcp2cli --spec https://petstore3.swagger.io/api/v3/openapi.json --list\n\n# Call an endpoint\nmcp2cli --spec ./openapi.json --base-url https://api.example.com list-pets --status available\n\n# With auth\nmcp2cli --spec ./spec.json --auth-header \"Authorization:Bearer tok_...\" create-item --name \"Test\"\n\n# POST with JSON body from stdin\necho '{\"name\": \"Fido\", \"tag\": \"dog\"}' | mcp2cli --spec ./spec.json create-pet --stdin\n\n# Local YAML spec\nmcp2cli --spec ./api.yaml --base-url http://localhost:8000 --list\n```\n\n### GraphQL mode\n\n```bash\n# List all queries and mutations from a GraphQL endpoint\nmcp2cli --graphql https://api.example.com/graphql --list\n\n# Call a query\nmcp2cli --graphql https://api.example.com/graphql users --limit 10\n\n# Call a mutation\nmcp2cli --graphql https://api.example.com/graphql create-user --name \"Alice\" --email \"alice@example.com\"\n\n# Override auto-generated selection set fields\nmcp2cli --graphql https://api.example.com/graphql users --fields \"id name email\"\n\n# With auth\nmcp2cli --graphql https://api.example.com/graphql --auth-header \"Authorization:Bearer tok_...\" users\n```\n\nmcp2cli 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.\n\n### Bake mode — save connection settings\n\nTired of repeating `--spec`/`--mcp`/`--mcp-stdio` plus auth flags on every invocation? Bake them into a named configuration:\n\n```bash\n# Create a baked tool from an OpenAPI spec\nmcp2cli bake create petstore --spec https://api.example.com/spec.json \\\n  --exclude \"delete-*,update-*\" --methods GET,POST --cache-ttl 7200\n\n# Create a baked tool from an MCP stdio server\nmcp2cli bake create mygit --mcp-stdio \"npx @mcp/github\" \\\n  --include \"search-*,list-*\" --exclude \"delete-*\"\n\n# Use a baked tool with @ prefix — no connection flags needed\nmcp2cli @petstore --list\nmcp2cli @petstore list-pets --limit 10\nmcp2cli @mygit search-repos --query \"rust\"\n\n# Manage baked tools\nmcp2cli bake list                         # show all baked tools\nmcp2cli bake show petstore                # show config (secrets masked)\nmcp2cli bake update petstore --cache-ttl 3600\nmcp2cli bake remove petstore\nmcp2cli bake install petstore             # creates ~/.local/bin/petstore wrapper\nmcp2cli bake install petstore --dir ./scripts/  # install wrapper to custom directory\n```\n\nFiltering options:\n- `--include` — comma-separated glob patterns to whitelist tools (e.g. `\"list-*,get-*\"`)\n- `--exclude` — comma-separated glob patterns to blacklist tools (e.g. `\"delete-*\"`)\n- `--methods` — comma-separated HTTP methods to allow (e.g. `\"GET,POST\"`, OpenAPI only)\n\nConfigs are stored in `~/.config/mcp2cli/baked.json`. Override with `MCP2CLI_CONFIG_DIR`.\n\n### Output control\n\n```bash\n# Pretty-print JSON (also auto-enabled for TTY)\nmcp2cli --spec ./spec.json --pretty list-pets\n\n# Raw response body (no JSON parsing)\nmcp2cli --spec ./spec.json --raw get-data\n\n# Filter JSON with jq (preferred over Python for JSON processing)\nmcp2cli --spec ./spec.json list-pets --jq '.[].name'\nmcp2cli --spec ./spec.json list-pets --jq '[.[] | select(.status == \"available\")] | length'\n\n# Truncate large responses to first N records\nmcp2cli --spec ./spec.json list-records --head 5\nmcp2cli --spec ./spec.json list-records --head 3 --jq '.'  # preview then filter\n\n# Pipe-friendly (compact JSON when not a TTY)\nmcp2cli --spec ./spec.json list-pets | jq '.[] | .name'\n\n# TOON output — token-efficient encoding for LLM consumption\n# Best for large uniform arrays (40-60% fewer tokens than JSON)\nmcp2cli --mcp https://mcp.example.com/sse --toon list-tags\n```\n\n### Caching\n\nSpecs and MCP tool lists are cached in `~/.cache/mcp2cli/` with a 1-hour TTL by default.\n\n```bash\n# Force refresh\nmcp2cli --spec https://api.example.com/spec.json --refresh --list\n\n# Custom TTL (seconds)\nmcp2cli --spec https://api.example.com/spec.json --cache-ttl 86400 --list\n\n# Custom cache key\nmcp2cli --spec https://api.example.com/spec.json --cache-key my-api --list\n\n# Override cache directory\nMCP2CLI_CACHE_DIR=/tmp/my-cache mcp2cli --spec ./spec.json --list\n```\n\nLocal file specs are never cached.\n\n## CLI reference\n\n```\nmcp2cli [global options] \u003csubcommand\u003e [command options]\n\nSource (mutually exclusive, one required):\n  --spec URL|FILE       OpenAPI spec (JSON or YAML, local or remote)\n  --mcp URL             MCP server URL (HTTP/SSE)\n  --mcp-stdio CMD       MCP server command (stdio transport)\n  --graphql URL         GraphQL endpoint URL\n\nOptions:\n  --auth-header K:V       HTTP header (repeatable, value supports env:/file: prefixes)\n  --base-url URL          Override base URL from spec\n  --transport TYPE        MCP HTTP transport: auto|sse|streamable (default: auto)\n  --env KEY=VALUE         Env var for MCP stdio server (repeatable)\n  --oauth                 Enable OAuth (authorization code + PKCE flow)\n  --oauth-client-id ID    OAuth client ID (supports env:/file: prefixes)\n  --oauth-client-secret S OAuth client secret (supports env:/file: prefixes)\n  --oauth-scope SCOPE     OAuth scope(s) to request\n  --cache-key KEY         Custom cache key\n  --cache-ttl SECONDS     Cache TTL (default: 3600)\n  --refresh               Bypass cache\n  --list                  List available subcommands\n  --search PATTERN        Search tools by name or description (implies --list)\n  --fields FIELDS         Override GraphQL selection set (e.g. \"id name email\")\n  --pretty                Pretty-print JSON output\n  --raw                   Print raw response body\n  --toon                  Encode output as TOON (token-efficient for LLMs)\n  --jq EXPR               Filter JSON output through jq expression\n  --head N                Limit output to first N records (arrays)\n  --version               Show version\n\nBake mode:\n  bake create NAME [opts]   Save connection settings as a named tool\n  bake list                 List all baked tools\n  bake show NAME            Show config (secrets masked)\n  bake update NAME [opts]   Update a baked tool\n  bake remove NAME          Delete a baked tool\n  bake install NAME         Create ~/.local/bin wrapper script\n  @NAME [args]              Run a baked tool (e.g. mcp2cli @petstore --list)\n```\n\nSubcommands and their flags are generated dynamically from the spec or MCP server tool definitions. Run `\u003csubcommand\u003e --help` for details.\n\n\u003e For token savings analysis, architecture details, and comparison to Anthropic's Tool Search, see the **[full writeup on the OCAI blog](https://www.orangecountyai.com/blog/mcp2cli-one-cli-for-every-api-zero-wasted-tokens)**.\n\n## Development\n\n```bash\n# Install with test + MCP deps\nuv sync --extra test\n\n# Run tests (96 tests covering OpenAPI, MCP stdio, MCP HTTP, caching, and token savings)\nuv run pytest tests/ -v\n\n# Run just the token savings tests\nuv run pytest tests/test_token_savings.py -v -s\n```\n\n---\n\n## License\n\n[MIT](LICENSE)\n\n---\n\n\u003csub\u003emcp2cli builds on ideas from [CLIHub](https://kanyilmaz.me/2026/02/23/cli-vs-mcp.html) by Kagan Yilmaz (CLI-based tool access for token efficiency)\u003c/sub\u003e\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknowsuchagency%2Fmcp2cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fknowsuchagency%2Fmcp2cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fknowsuchagency%2Fmcp2cli/lists"}