Turn any MCP server into a native command-line application.
Server tools become verbs. Resources become nouns. Prompts become workflows. No MCP protocol knowledge required at the terminal.
# One binary. Any server. Real CLI commands.
email ls
email send --to user@example.com --subject "Hi" --body "Meeting at 3"
email get mail://inbox
staging deploy --version 2.1.0 --background
prod --json doctor | jq '.data.server'MCP (Model Context Protocol) defines a powerful standard for servers to expose tools, resources, and prompts. But interacting with an MCP server requires JSON-RPC plumbing, session negotiation, and protocol-level knowledge — none of which belongs in a CLI.
mcp2cli bridges that gap:
| Problem | mcp2cli |
|---|---|
| MCP requires JSON-RPC plumbing | Auto-discovers capabilities → typed --flags from JSON Schema |
| Testing MCP servers needs custom client code | Point, shoot: mcp2cli --url http://localhost:3001/mcp ls |
| Each server needs its own CLI wrapper | One binary + config files = unlimited server bindings |
| AI agents can't easily call MCP tools from shell | --json output → structured envelopes for programmatic parsing |
| CI/CD can't orchestrate MCP operations | Exit codes, JSON output, pipes, --timeout, --background |
| Server tools have cryptic protocol names | Profile overlays rename, group, and hide commands |
cargo install --path .# HTTP server — just point and go
mcp2cli --url http://127.0.0.1:3001/mcp ls
mcp2cli --url http://127.0.0.1:3001/mcp echo --message hello
# Stdio server — just run
mcp2cli --stdio "npx @modelcontextprotocol/server-everything" ls# Create a config
mcp2cli config init --name email --app bridge \
--transport streamable_http --endpoint https://mcp.example.com/email
# Create a symlink alias
mcp2cli link create --name email
# Authenticate (the email server needs a bearer token)
email auth login
# Use it like a standalone app
email ls # Discover capabilities
email send --to user@example.com \
--subject "Hi" --body "Meeting at 3" # Call a tool
email search --query "from:boss" # Search the mailbox
email get mail://inbox # Read a resource
email doctor # Health checkmcp2cli config init --name demo --app bridge \
--transport streamable_http --endpoint https://demo.invalid/mcp
mcp2cli use demo
mcp2cli lsmcp2cli discovers → builds manifest → generates CLI → parses input → executes MCP call
- Discovers the server's tools, resources, resource templates, and prompts
- Builds a command manifest — each capability becomes a typed command with flags derived from JSON Schema
- Generates a clap CLI tree — dotted names become nested subcommands, required fields become required flags
- Parses your input against the generated tree with full type validation
- Executes the MCP operation and renders the result
| JSON Schema | CLI flag | Example |
|---|---|---|
string |
--name <TEXT> |
--message hello |
integer |
--count <INT> |
--steps 5 |
number |
--rate <NUM> |
--temperature 0.7 |
boolean |
--flag |
--include-image |
enum |
--kind <A|B|C> |
--level error |
array |
--tags <VAL,...> |
--labels bug,urgent |
| Complex | --config <JSON> |
--config '{"a":1}' |
Dotted tool names automatically become nested subcommands:
# Server tools: send, reply, draft.create
email send --to user@example.com --subject "Hi" --body "Hello"
email reply --thread-id 123 --body "Thanks"
email draft create --subject "New draft"- Discovery-driven CLI — server capabilities auto-generate typed CLI commands with
--flagsfrom JSON Schema - Named configs & aliases —
mcp2cli use <name>, symlink aliases (email,prod,staging), dispatch routing - Profile overlays — rename, hide, group, alias commands; rename flags; change resource verbs
- Ad-hoc connections —
--urland--stdiofor config-free, zero-setup usage - Fuzzy matching — "Did you mean?" suggestions for mistyped commands
- Streamable HTTP — JSON-RPC over HTTP with SSE streaming and session negotiation
- Stdio — spawn local subprocess servers, communicate via stdin/stdout
- Demo mode —
demo.invalidfile-backed backend for offline learning and testing
Full MCP 2025-11-25 implementation. See the Protocol Coverage reference for per-feature detail, source pointers, and CLI examples.
| Category | Methods / notifications | mcp2cli surface |
|---|---|---|
| Lifecycle | initialize, notifications/initialized, ping |
One handshake per session; ping exposed as a CLI command |
| Discovery | tools/list, resources/list, resources/templates/list, prompts/list + notifications/*/list_changed |
ls populates a persistent cache; list-change notifications invalidate it automatically |
| Tool invocation | tools/call |
Typed clap flags from JSON Schema (required/optional, enums, defaults, nested objects); progress token attached automatically |
| Resources | resources/read, resources/subscribe, resources/unsubscribe, notifications/resources/updated |
get <URI> for concrete reads; parameterised templates surface as commands; subscribe/unsubscribe stream change events |
| Prompts | prompts/get |
Each prompt becomes a command with typed argument flags derived from the prompt definition |
| Completions | completion/complete |
complete command with ref context (resource or prompt) per MCP 2025-11-25 |
| Logging | logging/setLevel, notifications/message |
log level <LEVEL>; server-emitted logs are surfaced as runtime events and written to the configured sinks |
| Progress | notifications/progress + _meta.progressToken |
Progress tokens auto-attached to long-running ops; ticks rendered to stderr or event sinks |
| Cancellation | notifications/cancelled (bidirectional) |
Ctrl+C sends a cancel for the in-flight request; inbound cancels are acknowledged |
| Elicitation (server→client) | elicitation/create |
Interactive terminal prompt — form mode (typed fields from JSON Schema) + URL mode (open-in-browser) |
| Sampling (server→client) | sampling/createMessage |
Human-in-the-loop review with tool display before forwarding to the LLM |
| Roots (server→client) | roots/list |
Client advertises configurable root URIs; servers query on demand |
| Tasks (MCP 2025-11-25) | tasks/get, tasks/result, tasks/cancel, _meta.task on tools/call |
--background creates a task; jobs show/wait/cancel/watch tracks it across invocations |
- Authentication —
auth login/logout/statuswith file-backed token persistence - Event system — 5 sink types: stderr, HTTP webhook, Unix socket, SSE server, command exec
- Output formats —
--json,--output json|ndjson|human— every command supports structured output - Request timeouts — global default + per-command
--timeoutoverride - Daemon mode — keep MCP connections warm between invocations (Unix socket IPC)
- Doctor & Inspect — runtime health diagnostics, full capability dump
Each alias routes to a different MCP server. Each feels like its own standalone application.
# Set up multiple servers
mcp2cli config init --name dev --transport stdio --stdio-command ./dev-server
mcp2cli config init --name staging --transport streamable_http --endpoint https://staging.api/mcp
mcp2cli config init --name prod --transport streamable_http --endpoint https://prod.api/mcp
# Create aliases
mcp2cli link create --name dev
mcp2cli link create --name staging
mcp2cli link create --name prod
# Each alias is its own CLI
dev ls # Local dev server
staging deploy --version 1.2.3 # Staging HTTP server
prod doctor # Production health checkEvery command supports structured JSON output:
# JSON envelope
email --json ls | jq '.data.items[].id'
# Tool result
email --json send --to user@example.com --subject "Hi" --body "Hello" | jq '.data.content[0].text'
# Health check data
email --json doctor | jq '.data.server'
# Machine-readable discovery
email --json ls --tools | jq '[.data.items[] | {id, kind, summary}]'Consistent envelope format:
{
"app_id": "email",
"command": "invoke",
"summary": "called send",
"lines": ["..."],
"data": { "content": [...] }
}Customize the CLI surface per-server — no server changes needed:
profile:
display_name: "Email CLI"
aliases:
long-running-operation: lro # Rename commands
echo: ping
hide:
- debug-tool # Hide from help/ls
groups:
mail: # Custom grouping
- send
- reply
- draft-create
flags:
echo:
message: msg # Rename flags
resource_verb: fetch # "fetch" instead of "get"Each named config is a YAML file. Minimal example:
schema_version: 1
server:
transport: streamable_http
endpoint: http://localhost:3001/mcpFull example with all options:
schema_version: 1
app:
profile: bridge
server:
display_name: My MCP Server
transport: stdio # or streamable_http
endpoint: null # required for streamable_http
stdio:
command: npx
args: ['@modelcontextprotocol/server-everything']
roots:
- uri: "file:///home/user/project"
name: "Project Root"
defaults:
output: human # human | json | ndjson
timeout_seconds: 120 # 0 = no timeout
logging:
level: warn
format: pretty
outputs:
- kind: stderr
auth:
browser_open_command: null
events:
enable_stdio_events: true
# http_endpoint: "http://127.0.0.1:9090/events"
# local_socket_path: "/tmp/mcp2cli-events.sock"
# sse_endpoint: "127.0.0.1:9091"
# command: "logger -t mcp2cli '${MCP_EVENT_MESSAGE}'"
profile:
display_name: "My Tool"
aliases: {}
hide: []
groups: {}
flags: {}
resource_verb: getAlways available alongside server-derived commands:
| Command | Description |
|---|---|
ls [--tools|--resources|--prompts] [--filter] |
Discover capabilities |
ping |
Server liveness with latency |
doctor |
Runtime health diagnostics |
inspect |
Full capability dump |
auth login|logout|status |
Authentication management |
jobs list|show|wait|cancel|watch |
Background job management |
log <LEVEL> |
Set server-side log level |
subscribe <URI> / unsubscribe <URI> |
Resource change notifications |
complete <REF> <NAME> <ARG> |
Tab-completion from server |
Manage configs and aliases — no server connection needed:
| Command | Description |
|---|---|
mcp2cli config init [options] |
Create a named config |
mcp2cli config list |
List all configs |
mcp2cli config show --name <NAME> |
Show a config |
mcp2cli use <NAME> |
Set active config |
mcp2cli link create --name <NAME> |
Create symlink alias |
mcp2cli daemon start|stop|status |
Manage connection daemons |
mcp2cli is useful across the entire MCP lifecycle:
| Use Case | How |
|---|---|
| Test an MCP server | mcp2cli --url http://localhost:3001/mcp doctor — instant health check |
| E2E conformance testing | Bash test suites that validate every MCP spec section with assertions |
| Local server development | mcp2cli --stdio "./my-server" ls — test as you build, zero client code |
| AI agent tool-use | --json output → parse in Python/Node → agents call any MCP tool |
| CI/CD pipelines | JSON output, exit codes, --timeout, --background — pipeline-native |
| Infrastructure automation | Per-service aliases → k8s deploy, db backup, mon status |
| Shell scripting | Pipe to jq, loop over tools, retry with backoff |
| Multi-server orchestration | Named configs + symlinks = cross-service workflows in bash |
| Production monitoring | Event sinks → webhooks, SSE, Unix sockets, custom commands |
cargo test --lib # Unit tests
cargo test --test integration # Integration tests
cargo test # All tests# Streamable HTTP server
npx @modelcontextprotocol/server-everything streamableHttp
# → http://127.0.0.1:3001/mcp
# Stdio server
npx @modelcontextprotocol/server-everythingUse mcp2cli as a conformance test harness:
# Quick smoke test
mcp2cli --url http://localhost:3001/mcp doctor
# Structured conformance suite
./run-conformance.sh --url http://localhost:3001/mcp| Document | Description |
|---|---|
| Getting Started | Install, configure, run your first command |
| CLI Reference | Every command, flag, and option |
| Config Reference | Complete YAML schema |
| config.example.yaml | Annotated config template |
| Feature | Guide |
|---|---|
| Discovery-driven CLI | docs/features/discovery-driven-cli.md |
| Profile overlays | docs/features/profile-overlays.md |
| Transports | docs/features/transports.md |
| Ad-hoc connections | docs/features/ad-hoc-connections.md |
| Request timeouts | docs/features/request-timeouts.md |
| Fuzzy matching | docs/features/fuzzy-matching.md |
| Daemon mode | docs/features/daemon-mode.md |
| Background jobs | docs/features/background-jobs.md |
| Event system | docs/features/event-system.md |
| Authentication | docs/features/authentication.md |
| Output formats | docs/features/output-formats.md |
| Elicitation & sampling | docs/features/elicitation-and-sampling.md |
| Named configs & aliases | docs/features/named-configs-and-aliases.md |
| Article | Audience |
|---|---|
| AI Agents + MCP via CLI | Agent developers |
| E2E & Conformance Testing | MCP server authors |
| Testing MCP Servers | Server validation |
| Local Development & Prototyping | Server developers |
| Shell Scripting with MCP | DevOps |
| Multi-Server Workflows | Platform engineers |
| Platform Engineering | Infrastructure teams |
| From Zero to Production | Production deployment |
| Document | Description |
|---|---|
| Design Proposal | Architecture of the discovery-driven dynamic CLI |
| MCP Spec Compliance | Spec compliance audit and gap tracking |
| Implementation Plan | MCP 2025-11-25 compliance roadmap |
mcp2cli collects anonymous, non-sensitive usage telemetry to help us understand which features are used and where to focus improvements. We follow the same opt-out model used by Homebrew, Rust, and VS Code.
- Command category (e.g. "tool_invoke", "discover", "auth" — never the actual tool/prompt name)
- Transport type used (stdio, HTTP)
- Whether features like
--json,--background,--timeout, daemon, profile overlay, or ad-hoc mode were used - Outcome (success/error) and duration in milliseconds
- OS, architecture, and CLI version
- A random installation UUID (not tied to your identity)
- No server endpoints, URIs, tool names, argument values, file paths, or configuration content
- No IP addresses or user identifiers
- No environment variables or credentials
Any one of these disables telemetry completely:
# Config file
telemetry:
enabled: false
# Environment variable
export MCP2CLI_TELEMETRY=off
# CLI flag (per-invocation)
mcp2cli --no-telemetry ls
# Respect DO_NOT_TRACK standard (https://consoledonottrack.com/)
export DO_NOT_TRACK=1Events are written to ~/.local/share/mcp2cli/telemetry.ndjson as newline-delimited JSON. You can inspect, delete, or rotate this file at any time.
mcp2cli is operated and developed by TSOK — The Source of Knowledge
AI Laboratory (tsok.org), with engineering and
agent operations supported by TSOK-Bot (tsok.bot),
TSOK's in-house AI agent platform. The project is released under the
Apache License 2.0; see LICENSE.
Apache License 2.0 — see LICENSE.