Install
$ agentstack add mcp-mcp2cli-source-code ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
mcp2cli
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'
Why mcp2cli?
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 |
Quick Start
Install
cargo install --path .
Option A: Ad-hoc — zero config
# 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
Option B: Named config + alias
# 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 check
Option C: Demo mode — no server needed
mcp2cli config init --name demo --app bridge \
--transport streamable_http --endpoint https://demo.invalid/mcp
mcp2cli use demo
mcp2cli ls
> [Full getting started guide →](docs/getting-started.md)
How It Works
mcp2cli 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
Schema-to-flag mapping
| JSON Schema | CLI flag | Example | |-------------|----------|---------| | string | --name | --message hello | | integer | --count | --steps 5 | | number | --rate | --temperature 0.7 | | boolean | --flag | --include-image | | enum | --kind | --level error | | array | --tags | --labels bug,urgent | | Complex | --config | --config '{"a":1}' |
Namespace grouping
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"
Features at a Glance
Core
- [Discovery-driven CLI](docs/features/discovery-driven-cli.md) — server capabilities auto-generate typed CLI commands with
--flagsfrom JSON Schema - [Named configs & aliases](docs/features/named-configs-and-aliases.md) —
mcp2cli use, symlink aliases (email,prod,staging), dispatch routing - [Profile overlays](docs/features/profile-overlays.md) — rename, hide, group, alias commands; rename flags; change resource verbs
- [Ad-hoc connections](docs/features/ad-hoc-connections.md) —
--urland--stdiofor config-free, zero-setup usage - [Fuzzy matching](docs/features/fuzzy-matching.md) — "Did you mean?" suggestions for mistyped commands
Transports
- [Streamable HTTP](docs/features/transports.md) — JSON-RPC over HTTP with SSE streaming and session negotiation
- [Stdio](docs/features/transports.md) — spawn local subprocess servers, communicate via stdin/stdout
- [Demo mode](docs/features/transports.md) —
demo.invalidfile-backed backend for offline learning and testing
Protocol Coverage
Full MCP 2025-11-25 implementation. See the [Protocol Coverage reference](docs/protocol-coverage.md) 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 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 ; 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](docs/features/elicitation-and-sampling.md) | Interactive terminal prompt — form mode (typed fields from JSON Schema) + URL mode (open-in-browser) | | Sampling (server→client) | [sampling/createMessage](docs/features/elicitation-and-sampling.md) | 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](docs/features/background-jobs.md) creates a task; jobs show/wait/cancel/watch tracks it across invocations |
Operations
- [Authentication](docs/features/authentication.md) —
auth login/logout/statuswith file-backed token persistence - [Event system](docs/features/event-system.md) — 5 sink types: stderr, HTTP webhook, Unix socket, SSE server, command exec
- [Output formats](docs/features/output-formats.md) —
--json,--output json|ndjson|human— every command supports structured output - [Request timeouts](docs/features/request-timeouts.md) — global default + per-command
--timeoutoverride - [Daemon mode](docs/features/daemon-mode.md) — keep MCP connections warm between invocations (Unix socket IPC)
- Doctor & Inspect — runtime health diagnostics, full capability dump
Multi-Server Workflow
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 check
JSON Output for Scripts & Agents
Every 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": [...] }
}
Profile Overlays
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"
Config Model
Each named config is a YAML file. Minimal example:
schema_version: 1
server:
transport: streamable_http
endpoint: http://localhost:3001/mcp
Full 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: get
> [Full config reference →](docs/reference/config-reference.md)
Runtime Commands
Always 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 | Set server-side log level | | subscribe / unsubscribe | Resource change notifications | | complete | Tab-completion from server |
Host Commands
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 | Show a config | | mcp2cli use | Set active config | | mcp2cli link create --name | Create symlink alias | | mcp2cli daemon start\|stop\|status | Manage connection daemons |
> [Full CLI reference →](docs/reference/cli-reference.md)
Use Cases
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 |
> [Detailed articles for each use case →](docs/index.md#articles--guides)
Testing
cargo test --lib # Unit tests
cargo test --test integration # Integration tests
cargo test # All tests
Local Validation Servers
# Streamable HTTP server
npx @modelcontextprotocol/server-everything streamableHttp
# → http://127.0.0.1:3001/mcp
# Stdio server
npx @modelcontextprotocol/server-everything
E2E Testing Your Own Server
Use 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
> [E2E conformance testing guide →](docs/articles/e2e-conformance-testing.md)
Documentation
Getting Started
| Document | Description | |----------|-------------| | [Getting Started](docs/getting-started.md) | Install, configure, run your first command | | [CLI Reference](docs/reference/cli-reference.md) | Every command, flag, and option | | [Config Reference](docs/reference/config-reference.md) | Complete YAML schema | | [config.example.yaml](config.example.yaml) | Annotated config template |
Feature Guides
| Feature | Guide | |---------|-------| | Discovery-driven CLI | [docs/features/discovery-driven-cli.md](docs/features/discovery-driven-cli.md) | | Profile overlays | [docs/features/profile-overlays.md](docs/features/profile-overlays.md) | | Transports | [docs/features/transports.md](docs/features/transports.md) | | Ad-hoc connections | [docs/features/ad-hoc-connections.md](docs/features/ad-hoc-connections.md) | | Request timeouts | [docs/features/request-timeouts.md](docs/features/request-timeouts.md) | | Fuzzy matching | [docs/features/fuzzy-matching.md](docs/features/fuzzy-matching.md) | | Daemon mode | [docs/features/daemon-mode.md](docs/features/daemon-mode.md) | | Background jobs | [docs/features/background-jobs.md](docs/features/background-jobs.md) | | Event system | [docs/features/event-system.md](docs/features/event-system.md) | | Authentication | [docs/features/authentication.md](docs/features/authentication.md) | | Output formats | [docs/features/output-formats.md](docs/features/output-formats.md) | | Elicitation & sampling | [docs/features/elicitation-and-sampling.md](docs/features/elicitation-and-sampling.md) | | Named configs & aliases | [docs/features/named-configs-
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: mcp2cli
- Source: mcp2cli/source-code
- License: Apache-2.0
- Homepage: https://mcp2cli.dev
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.