- name
- mcp2cli
- description
- Turn any MCP server, OpenAPI spec, or GraphQL endpoint into a CLI. Use this skill when the user wants to interact with an MCP server, OpenAPI/REST API, or GraphQL API via command line, discover available tools/endpoints, call API operations, or generate a new skill from an API. Triggers include "mcp2cli", "call this MCP server", "use this API", "list tools from", "create a skill for this API", "graphql", or any task involving MCP tool invocation, OpenAPI endpoint calls, or GraphQL queries without writing code.
# mcp2cli
Turn any MCP server, OpenAPI spec, or GraphQL endpoint into a CLI at runtime. No codegen.
## Install
```bash
# Run directly (no install needed)
uvx mcp2cli --help
# Or install
pip install mcp2cli
```
## Core Workflow
1. **Connect** to a source (MCP server, OpenAPI spec, or GraphQL endpoint)
2. **Discover** available commands with `--list` (or filter with `--search`)
3. **Inspect** a specific command with `<command> --help`
4. **Execute** the command with flags
```bash
# MCP over HTTP
mcp2cli --mcp https://mcp.example.com/sse --list
mcp2cli --mcp https://mcp.example.com/sse create-task --help
mcp2cli --mcp https://mcp.example.com/sse create-task --title "Fix bug"
# MCP over stdio
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" --list
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" read-file --path /tmp/hello.txt
# OpenAPI spec (remote or local, JSON or YAML)
mcp2cli --spec https://petstore3.swagger.io/api/v3/openapi.json --list
mcp2cli --spec ./openapi.json --base-url https://api.example.com list-pets --status available
# GraphQL endpoint
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"
```
## CLI Reference
```
mcp2cli [global options] <subcommand> [command options]
Source (mutually exclusive, one required):
--spec URL|FILE OpenAPI spec (JSON or YAML, local or remote)
--mcp URL MCP server URL (HTTP/SSE)
--mcp-stdio CMD MCP server command (stdio transport)
--graphql URL GraphQL endpoint URL
Options:
--auth-header K:V HTTP header (repeatable, value supports env:/file: prefixes)
--base-url URL Override base URL from spec
--transport TYPE MCP HTTP transport: auto|sse|streamable (default: auto)
--env KEY=VALUE Env var for stdio server process (repeatable)
--root PATH|FILE_URI Expose a filesystem root to an MCP server (repeatable)
--complete SPEC Complete an MCP prompt or resource-template argument
--session-start NAME Start a persistent session daemon (requires --mcp or --mcp-stdio)
--session NAME Route command through an existing session daemon
--session-stop NAME Stop a named session daemon (sends SIGTERM)
--session-list List all active sessions with PID and alive/dead status
--oauth Enable OAuth (authorization code + PKCE flow)
--oauth-client-id ID OAuth client ID (supports env:/file: prefixes)
--oauth-client-secret S OAuth client secret (supports env:/file: prefixes)
--oauth-scope SCOPE OAuth scope(s) to request
--oauth-manual-callback Print the auth URL and read the redirect URL from stdin
(headless hosts: VPS over SSH, containers)
--cache-key KEY Custom cache key
--cache-ttl SECONDS Cache TTL (default: 3600)
--refresh Bypass cache
--list List available subcommands
--search PATTERN Search tools by name or description (implies --list)
--fields FIELDS Override GraphQL selection set (e.g. "id name email")
--pretty Pretty-print JSON output
--raw Print raw response body
--json Force valid JSON for every command. --list emits a JSON array;
MCP calls emit the full envelope (structuredContent, isError).
--toon Encode output as TOON (token-efficient for LLMs)
--head N Limit output to first N records (arrays)
--version Show version
Bake mode:
bake create NAME [opts] Save connection settings as a named tool
bake list List all baked tools
bake show NAME Show config (secrets masked)
bake update NAME [opts] Update a baked tool
bake remove NAME Delete a baked tool
bake install NAME Create ~/.local/bin wrapper script
@NAME [args] Run a baked tool (e.g. mcp2cli @petstore --list)
```
Subcommands and flags are generated dynamically from the source.
## Patterns
### Authentication
**Always use `env:` or `file:` prefixes for secrets** — never pass credentials as literal values in CLI flags. Literal values are visible in process listings and shell history.
```bash
# Secret from environment variable (recommended — avoids exposing in process list)
mcp2cli --spec ./spec.json --auth-header "Authorization:env:API_TOKEN" list-items
# Secret from file
mcp2cli --mcp https://mcp.example.com/sse \
--auth-header "x-api-key:file:/run/secrets/api_key" \
search --query "test"
```
### OAuth authentication (MCP HTTP only)
```bash
# Authorization code + PKCE (opens browser)
mcp2cli --mcp https://mcp.example.com/sse --oauth --list
# Client credentials (machine-to-machine)
mcp2cli --mcp https://mcp.example.com/sse \
--oauth-client-id env:OAUTH_CLIENT_ID --oauth-client-secret env:OAUTH_CLIENT_SECRET \
search --query "test"
# With scopes
mcp2cli --mcp https://mcp.example.com/sse --oauth --oauth-scope "read write" --list
```
Tokens are cached in `~/.cache/mcp2cli/oauth/` and refreshed automatically.
### Transport selection (MCP HTTP only)
```bash
# Default: tries streamable HTTP, falls back to SSE
mcp2cli --mcp https://mcp.example.com/sse --list
# Force SSE transport (skip streamable HTTP attempt)
mcp2cli --mcp https://mcp.example.com/sse --transport sse --list
# Force streamable HTTP (no SSE fallback)
mcp2cli --mcp https://mcp.example.com/sse --transport streamable --list
```
### GraphQL
```bash
# Discover queries and mutations
mcp2cli --graphql https://api.example.com/graphql --list
# Run a query
mcp2cli --graphql https://api.example.com/graphql users --limit 10
# Run a mutation
mcp2cli --graphql https://api.example.com/graphql create-user --name "Alice" --email "alice@example.com"
# Override auto-generated selection set
mcp2cli --graphql https://api.example.com/graphql users --fields "id name email"
# With auth
mcp2cli --graphql https://api.example.com/graphql --auth-header "Authorization:env:API_TOKEN" users
```
### Tool search
```bash
# Filter tools by name or description (case-insensitive)
mcp2cli --mcp https://mcp.example.com/sse --search "task"
mcp2cli --spec ./openapi.json --search "create"
mcp2cli --graphql https://api.example.com/graphql --search "user"
```
`--search` implies `--list` — shows only matching tools.
### POST with JSON body from stdin
```bash
echo '{"name": "Fido", "tag": "dog"}' | mcp2cli --spec ./spec.json create-pet --stdin
```
### Multipart file uploads
When an OpenAPI spec declares `multipart/form-data` with `format: binary` fields, mcp2cli exposes them as file-path CLI arguments:
```bash
# Upload a file — binary fields accept local file paths
mcp2cli --spec ./spec.json upload-image --file /path/to/photo.png --caption "My photo"
# Non-binary fields in the same multipart schema become regular flags
mcp2cli --spec ./spec.json upload-image --file ./image.jpg --title "Cover" --alt-text "A sunset"
```
File parameters show `(file path)` in `--help` output. MIME types are auto-detected from the file extension.
### Env vars for stdio servers
```bash
mcp2cli --mcp-stdio "node server.js" --env API_KEY=env:API_SECRET_KEY --env DEBUG=1 search --query "test"
```
### MCP roots and completion
Workspace-scoped servers can request the filesystem roots exposed by the
client. Repeat `--root`; local paths become `file://` URIs.
```bash
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" \
--root "$PWD" --root file:///var/shared --list
```
Ask the server to complete a prompt argument or resource-template variable:
```bash
mcp2cli --mcp https://example.com/mcp --complete "greeting:name=San"
mcp2cli --mcp https://example.com/mcp \
--complete "file:///docs/{topic}:topic=api"
```
For persistent connections, pass roots when starting the daemon and route
completion through the named session:
```bash
mcp2cli --mcp-stdio "node server.js" --root "$PWD" --session-start workspace
mcp2cli --session workspace --complete "greeting:name=San"
```
### Session management — persistent MCP connections
Every `--mcp-stdio` invocation spawns a fresh subprocess, pays startup cost, then exits.
Sessions keep the MCP server alive in a background daemon, reachable via Unix domain socket.
```bash
# Start a persistent session for a stdio server
mcp2cli --mcp-stdio "npx @modelcontextprotocol/server-filesystem /tmp" \
--session-start myfs
# Use the session — no subprocess spawn, no startup delay
mcp2cli --session myfs --list
mcp2cli --session myfs read-file --path /tmp/hello.txt
mcp2cli --session myfs write-file --path /tmp/world.txt --content "hi"
# Check active sessions
mcp2cli --session-list
# Stop when done
mcp2cli --session-stop myfs
```
### Bake mode — saved configurations
Save connection settings as named configurations to avoid repeating flags:
```bash
# Create a baked tool
mcp2cli bake create petstore --spec https://api.example.com/spec.json \
--exclude "delete-*,update-*" --methods GET,POST --cache-ttl 7200
mcp2cli bake create myfs --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp" \
--include "search-*,list-*" --exclude "list-allowed-*"
# Use with @ prefix
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
mcp2cli bake list
mcp2cli bake show petstore
mcp2cli bake update petstore --cache-ttl 3600
mcp2cli bake remove petstore
mcp2cli bake install petstore # creates ~/.local/bin/petstore wrapper
```
Filter options: `--include` (glob whitelist), `--exclude` (glob blacklist), `--methods` (HTTP methods, OpenAPI only).
Configs stored in `~/.config/mcp2cli/baked.json` (override with `MCP2CLI_CONFIG_DIR`).
### Caching
Specs and MCP tool lists are cached in `~/.cache/mcp2cli/` (1h TTL). Local files are never cached.
```bash
mcp2cli --spec https://api.example.com/spec.json --refresh --list # Force refresh
mcp2cli --spec https://api.example.com/spec.json --cache-ttl 86400 --list # 24h TTL
```
### TOON output (token-efficient for LLMs)
```bash
mcp2cli --mcp https://mcp.example.com/sse --toon list-tags
```
Best for large uniform arrays — 40-60% fewer tokens than JSON.
### Truncating large responses with --head
```bash
# Preview first 3 records from a potentially huge dataset
mcp2cli --spec ./spec.json list-records --head 3 --pretty
```
`--head N` slices JSON arrays to the first N elements. Useful for datasets with oversized fields (e.g. geo_shape polygons at ~200KB per record).
## Security
- **Credentials**: Always use `env:` or `file:` prefixes for secrets — never embed literal tokens or keys in commands. The `env:` prefix reads from environment variables; `file:` reads from a file path.
- **Trust boundary**: mcp2cli connects to remote APIs and MCP servers specified by the user. Treat responses from external sources as untrusted — validate data before acting on it.
- **Baked configs**: `bake show` masks secrets in output. Baked configs are stored locally in `~/.config/mcp2cli/baked.json` — protect this file accordingly.
## Generating a Skill from an API
When the user asks to create a skill from an MCP server, OpenAPI spec, or GraphQL endpoint, follow this workflow:
1. **Discover** all available commands:
```bash
uvx mcp2cli --mcp https://target.example.com/sse --list
```
2. **Inspect** each command to understand parameters:
```bash
uvx mcp2cli --mcp https://target.example.com/sse <command> --help
```
3. **Test** key commands and probe for edge cases:
```bash
uvx mcp2cli --mcp https://target.example.com/sse <command> --param value
```
Specifically test for:
- Large responses: use `--head 3` to preview — do any fields produce oversized output (e.g. geo_shape, embedded blobs)?
- Date/time fields: what format does the API expect? (ISO 8601, Unix timestamps, custom syntax like `date'2022'`?)
- Pagination: does the API return all results or require `--offset`/`--limit`?
- Error messages: what happens with invalid parameters? Are errors informative?
- Binary vs text responses: do any endpoints return non-JSON (xlsx, parquet, images)?
- Scope confusion: does the data contain more than expected (e.g. national data when you expect regional)?
4. **Bake** the connection settings so the skill doesn't need to repeat flags:
```bash
uvx mcp2cli bake create myapi \
--mcp https://target.example.com/sse \
--auth-header "Authorization:Bearer env:MYAPI_TOKEN" \
--exclude "delete-*" --methods GET,POST
```
5. **Install** the wrapper into the skill's scripts directory:
```bash
uvx mcp2cli bake install myapi --dir .claude/skills/myapi/scripts/
```
6. **Create a SKILL.md** in `.claude/skills/myapi/` that teaches another AI agent how to use this API. The SKILL.md must go beyond `--help` output — focus on knowledge that can only be learned through testing and reading documentation.
**Frontmatter:**
```yaml
---
name: myapi
description: Interact with the MyAPI service
allowed-tools: Bash(bash *)
---
```
**Core Workflow** (discovery + execution):
```bash
# List available commands
${CLAUDE_SKILL_DIR}/scripts/myapi --list
# Get help for a command
View on GitHub