API Spec CLI
Agent-friendly CLI for exploring and calling OpenAPI and GraphQL APIs
Ask AI about API Spec CLI
Powered by Claude Β· Grounded in docs
I know everything about API Spec CLI. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
api-spec-cli
CLI for AI agents to explore and call OpenAPI, GraphQL, and MCP APIs. Output is JSON by default β compact, parseable, token-efficient.
Install
npm install -g api-spec-cli
Works with Node.js 18+. No other dependencies.
# Or run without installing
npx api-spec-cli <command>
How It Works
Every command is stateless β you specify the spec source on each call. Two paths:
| Path | When to use |
|---|---|
--spec <name> | Registered spec β auto-fetches and caches on first use |
| Inline flags | Ad-hoc β no registration, fetched each call |
Register once, use everywhere
spec add petstore --openapi https://petstore3.swagger.io/api/v3/openapi.json \
--base-url https://petstore3.swagger.io/api/v3 \
--description "Petstore example"
spec add hashnode --graphql https://gql.hashnode.com --auth YOUR_TOKEN
spec add agno --mcp-http https://docs.agno.com/mcp --description "Agno docs"
spec add fs --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"
Registration is instant β does not connect. Connection happens on first list/show/call and the result is cached at ~/spec-cli-config/cache/<name>.json.
Or use inline (no registration)
spec list --openapi https://petstore3.swagger.io/api/v3/openapi.json
spec list --graphql https://gql.hashnode.com
spec list --mcp-http https://docs.agno.com/mcp
spec list --mcp-sse http://localhost:3000/sse
spec list --mcp-stdio "npx -y @modelcontextprotocol/server-filesystem /tmp"
Inline fetches every call, nothing cached.
Discovery
Search across specs
grep searches operation/tool names and descriptions across all registered specs.
spec grep search # Substring match across all specs
spec grep "get*" # Glob: anything starting with "get"
spec grep "*list*" # Glob: anything containing "list"
spec grep search --spec agno # Limit to one spec
Matches on name and description. Case-insensitive. Plain text = substring, */? = glob.
List all specs in the registry
spec specs # Compact: name, type, enabled
spec specs --compact false # Full: includes source, config
List operations / tools
list is compact by default β just IDs, no schemas. Use --filter, --tag, --limit to narrow down.
spec list --spec agno # Registered spec (uses cache)
spec list --spec petstore --filter pet # Search by keyword
spec list --spec petstore --tag pets # OpenAPI: filter by tag
spec list --spec hashnode --tag mutation # GraphQL: filter by kind
spec list --spec petstore --limit 10 # First 10 only
spec list --spec petstore --limit 10 --offset 10 # Next 10
spec list --mcp-http https://docs.agno.com/mcp # Inline: no registration needed
Compact output:
{
"type": "mcp",
"total": 1,
"showing": 1,
"operations": [
{ "id": "search_agno", "description": "Search across the Agno knowledge base..." }
]
}
Use --compact false for full details including inputSchema for MCP tools.
Inspect one operation or tool
show gives you everything to make a call β params, body schema, response schemas, related types β in one call.
spec show --spec petstore getPetById # OpenAPI: by operationId
spec show --spec petstore /pet/{petId} # OpenAPI: by path
spec show --spec petstore "GET /pet/{petId}" # OpenAPI: by method + path
spec show --spec hashnode publishPost # GraphQL: by operation name
spec show --spec agno search_agno # MCP: by tool name
MCP output includes the full inputSchema so you know exactly what arguments to pass.
Drill into types (OpenAPI/GraphQL only)
spec types --spec petstore # List all schema names
spec types --spec petstore Pet # Inspect one schema
spec types --spec hashnode PublishPostInput # GraphQL input type
Calling APIs
# OpenAPI
spec call --spec petstore getPetById --var petId=1
spec call --spec petstore findPetsByStatus --query status=available
spec call --spec petstore addPet --data '{"name":"Rex","photoUrls":[]}'
# GraphQL (auto-generates query from schema)
spec call --spec hashnode me
spec call --spec hashnode publication --var host=blog.hashnode.dev
# MCP
spec call --spec agno search_agno --var query="how to create an agent"
spec call --spec agno search_agno --data '{"query":"agents"}'
# Read body from stdin (explicit --data -)
echo '{"query":"agents"}' | spec call --spec agno search_agno --data -
cat body.json | spec call --spec petstore addPet --data -
# Inline (no registration)
spec call --openapi https://petstore3.swagger.io/api/v3/openapi.json \
getPetById --var petId=1 --base-url https://petstore3.swagger.io/api/v3
Per-call overrides
Flags passed at call time win over registry entry config, which wins over .spec-cli/config.json.
spec call --spec agno search_agno --var query="foo" --header X-Tenant=acme
spec call --spec petstore getPetById --var petId=1 --auth staging-token
spec list --spec petstore --base-url https://staging.api.example.com
Registry Management
spec remove <name> # Delete entry and remove cache
spec enable <name> # Re-enable a disabled spec
spec disable <name> # Disable without removing
spec refresh <name> # Force re-fetch and update cache
spec add options
spec add <name> --openapi <url-or-file> [--base-url <url>] [--auth <token>] [--header k=v]
spec add <name> --graphql <url> [--auth <token>] [--header k=v]
spec add <name> --mcp-http <url> [--auth <token>] [--header k=v]
spec add <name> --mcp-sse <url> [--auth <token>] [--header k=v]
spec add <name> --mcp-stdio "<cmd args>" [--env KEY=VAL] [--cwd <path>]
[--description <text>] (all types)
All options are repeatable where it makes sense (--header, --env). --auth adds Authorization: Bearer <token> unless the header is already set.
Operation filtering works for all spec types β MCP, OpenAPI, and GraphQL:
# MCP: allow only read/list tools
spec add <name> --mcp-http <url> \
--allow-tool "read_*" --allow-tool "list_*" \
--disable-tool "delete_*"
# OpenAPI: allow only GET operations (by operationId)
spec add <name> --openapi <url> \
--allow-tool "get*" --allow-tool "find*"
# GraphQL: allow specific operations by exact name
spec add <name> --graphql <url> \
--allow-tool "me" --allow-tool "publication"
--allow-tool keeps only matching operations. --disable-tool removes matching operations (applied after allow). Both are repeatable.
Matching rules:
- Plain text β exact match (case-insensitive):
"me"matches onlyme - Glob patterns β anchored match:
"get*"matchesgetPetById,"*post*"matchescreatePost
Use grep for search (substring) β --allow-tool / --disable-tool for precise whitelists (exact or glob).
OAuth / Authentication
MCP HTTP and SSE servers that require OAuth 2.1 are handled automatically. spec-cli detects the 401 on spec add and runs the flow before returning.
Two modes depending on whether the server supports Dynamic Client Registration (DCR):
- DCR-enabled servers (e.g. self-hosted with Cloudflare workers-oauth-provider, Stytch, Curity) β no flags needed, browser opens automatically
- Pre-registered-only servers (e.g. GitHub) β pass
--oauth-client-idwith your app's client ID
Interactive (browser) β default
# DCR-enabled server: fully automatic
spec add myserver --mcp-http https://...
# GitHub (no DCR) β create an OAuth App at github.com/settings/developers first
# Set callback URL to http://127.0.0.1:8090/callback
spec add github --mcp-http https://api.githubcopilot.com/mcp/ \
--oauth-client-id <your-github-app-client-id> \
--oauth-callback-port 8090
Headless / device flow
spec add myserver --mcp-http https://... --oauth-flow device
# Prints a URL to stderr β open in any browser to authorize
Machine / CI (client credentials)
spec add myserver --mcp-http https://... \
--oauth-client-id <id> --oauth-client-secret <secret>
Re-authenticate
spec auth myserver # Re-run the OAuth flow
spec auth myserver --revoke # Clear stored token only
Tokens are stored in ~/spec-cli-config/tokens/<name>.json β separate from the cache, not touched by spec refresh.
OAuth flags
| Flag | Description |
|---|---|
--oauth-client-id <id> | Skip DCR β use a pre-registered OAuth app client ID |
--oauth-client-secret <secret> | Use client credentials flow (machine/CI) |
--oauth-callback-port <port> | Fixed callback port (required for apps with exact redirect URL match, e.g. GitHub) |
--oauth-flow device | Force device authorization flow (headless/SSH) |
Config
Persistent config stored in .spec-cli/config.json (lowest priority β overridden by registry entry config and call-time flags).
spec config set baseUrl https://api.example.com
spec config set auth my-token # Auto-adds "Bearer " prefix
spec config set auth "Basic dXNlcjpwYXNz" # Or explicit scheme
spec config set headers.X-API-Key abc123 # Custom header (dot notation)
spec config get
spec config unset auth
Validate
spec validate https://api.example.com/openapi.json
spec validate ./openapi.yaml
Reports broken $ref references, missing required fields, duplicate operationIds, invalid schema types, and more.
Output Format
JSON by default. Errors go to stderr as {"error": "message"} with a non-zero exit code.
spec list --spec petstore --format text
spec show --spec petstore getPetById --format yaml
spec list --spec petstore --format=json # equals syntax also works
Token Efficiency
listreturns only IDs by default β no schemasshowresolves$refcompactly β nested refs show as names, not explosionstypeslets you inspect one schema at a time--limit/--offsetpaginate large APIs--filterand--tagnarrow results before output
MCP Options
# Retry on connection failure (useful for stdio servers that take time to start)
MCP_MAX_RETRIES=3 # Attempts (default: 3)
MCP_RETRY_DELAY=1000 # Base delay in ms, doubles each attempt, capped at 5s (default: 1000)
# HTTP timeout for OpenAPI/GraphQL calls
SPEC_HTTP_TIMEOUT=30000 # ms (default: 30000)
Stdio env vars support ${VAR} expansion from the host environment:
spec add fs --mcp-stdio "npx -y server /tmp" --env "TOKEN=${MY_SECRET}"
Storage
| Path | Purpose |
|---|---|
~/spec-cli-config/registry.json | Global named registry |
~/spec-cli-config/cache/<name>.json | Cached spec per registered entry |
~/spec-cli-config/tokens/<name>.json | OAuth tokens per MCP entry |
.spec-cli/config.json | Project-local config (baseUrl, auth, headers) |
Planned
spec import <file>β bulk import servers from VS Codemcp.jsonor Claude Desktop config format
