cli-mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
cli-mcp
Swagger for Command Line Tools
cli-mcp exposes command-line applications through a
Model Context Protocol (MCP) server — without you
writing a single line of MCP code.
Like Swagger/OpenAPI describes an HTTP API, cli-mcp describes CLI commands, their arguments,
and their results as structured tools. It also executes those tools with argument validation
and configured execution controls, and can export OpenAPI documentation.
Automatic discovery depends on the CLI's help format or supported framework; use a manifest
when explicit metadata is needed. Windows .bat/.cmd targets are not supported.
Today: CLI Tool -> custom MCP wrapper -> MCP client
With cli-mcp: CLI Tool -> cli-mcp -> MCP clientcli-mcp expose git
cli-mcp expose kubectl
cli-mcp expose docker
cli-mcp expose opcua-nodeset-linker✓ Binary detected
✓ Commands discovered
✓ Schemas generated
✓ MCP tools published
✓ MCP server startedWorks with Claude, Copilot, Cursor, VS Code, Cline, Roo Code, Open WebUI and any other MCP-compatible client.
Install
Requires Python 3.13 or newer. CI covers Windows and Linux with Python 3.13 and 3.14.
pip install cli-mcpor, for development:
git clone https://github.com/AndreasHeine/cli-mcp
cd cli-mcp
uv sync --extra dev
uv run cli-mcp --helpRelated MCP server: Portage
Quick start
Only expose trusted programs. These quick-start examples do not enable read-only mode or sandboxing; discovery itself runs help commands on the host.
# Discover commands and serve them over stdio (the default transport)
cli-mcp expose git
# Look at the generated tools without starting a server
cli-mcp inspect kubectl
# Serve over Streamable HTTP
cli-mcp serve docker --transport streamable-http --port 8801
# Export machine-readable artefacts
cli-mcp export git -o tools.md
cli-mcp export-schema git -o schemas.json
cli-mcp export-openapi git -o openapi.json
# Validate discovery quality
cli-mcp doctor git
# Generate a configuration template
cli-mcp init opcua-nodeset-linker -o cli-mcp.yamlClient configuration (.mcp.json, Claude Desktop, Cursor, VS Code, …):
The following is a common client configuration shape; VS Code and other clients may use different keys. See clients.md for client-specific recipes.
{
"mcpServers": {
"git": {
"command": "cli-mcp",
"args": ["serve", "git"]
},
"docker": {
"url": "http://127.0.0.1:8801/mcp"
}
}
}Working directory and Windows shells
Some CLIs resolve paths inside their input configuration relative to the process working directory, not relative to that configuration file. Configure an absolute existing directory for both discovery and execution:
binary: my-cli
execution:
cwd: 'C:\projects\my-cli'Without execution.cwd, the launch directory is used. Use an absolute manifest path when
changing the discovery directory. Configuration and tool definitions are loaded at startup:
restart the server and reconnect the client after changes.
PowerShell:
$env:PYTHONDONTWRITEBYTECODE = '1'
& 'C:\projects\cli-mcp\.venv\Scripts\python.exe' -B -m cli_mcp.cli.main expose --config 'C:\projects\cli-mcp\cli-mcp.yaml'cmd.exe (run these as two separate commands):
set PYTHONDONTWRITEBYTECODE=1
"C:\projects\cli-mcp\.venv\Scripts\python.exe" -B -m cli_mcp.cli.main expose --config "C:\projects\cli-mcp\cli-mcp.yaml"These examples assume an existing development environment at the shown location.
How discovery works
cli-mcp tries discovery strategies in order. The first strategy that yields usable commands
wins; manifest entries then add tools or replace discovered tools with the same name.
The final include/exclude filters select which tools are published, not which help commands
may execute.
Import reflection is disabled by default and requires --allow-reflection or
discovery.allow_import_reflection: true. It may execute target code.
discovery.max_depth limits the recursive walk; discovery.max_commands limits both published
tools and uncached help invocations, including root queries, failures and fallback flags.
The help budget is checked before spawning processes; cache hits do not consume it.
Strategy | How it works | Frameworks |
Native reflection | Inspects the real command objects in the target process | Python: argparse, click, typer · Node.js: commander.js |
Framework help grammars | Parses framework-specific help output with type/default/required semantics | Go: cobra · Rust: clap · .NET: System.CommandLine · Node.js: yargs · click · argparse |
Generic help parsing | Recursive | anything with |
Manifest file | User-provided YAML metadata, authoritative for matching tool names | supported executables and scripts |
Every discovered command becomes an MCP tool:
{
"name": "reduce",
"description": "Reduce an OPC UA nodeset",
"inputSchema": {
"type": "object",
"properties": {
"input": { "type": "string", "description": "Input nodeset file" },
"output": { "type": "string", "description": "Reduced nodeset file" }
},
"required": ["input", "output"]
}
}Calling the tool executes the original CLI:
linker reduce --input model.xml --output reduced.xmland returns:
{
"stdout": "...",
"stderr": "",
"exitCode": 0,
"executionTimeMs": 125,
"argv": ["linker", "reduce", "--input", "model.xml", "--output", "reduced.xml"],
"sandboxed": false,
"truncated": false
}The actual argv contains the resolved launch command, including interpreter prefixes where
needed. A connected client or completed MCP call does not prove CLI success: inspect exitCode
and stderr. Exitcode 0 does not establish side-effect freedom; sandboxed: false means the
target ran on the host.
Security
Security is a first-class concern, not an afterthought.
binary: opcua-nodeset-linker
security:
allowlist: [git, kubectl, docker, opcua-nodeset-linker]
readonly: true # deny unless the complete argv is explicitly listed
readonly_argv: [] # configure verified exact invocations before use
approval: true # human confirmation required
timeout_seconds: 30
max_output_bytes: 200000
sandbox:
backend: docker
image: my-cli-image:latest
network: falseAllow list — a non-empty list restricts configured binaries by basename; an empty list permits the configured binary. This is not an OS permission boundary.
Read-only mode — only explicitly listed complete argv vectors may execute; known risky commands and flags are additionally blocked. An empty
readonly_argvblocks every execution and triggers a startup warning; publishing tools does not authorize them.Approval mode —
auto/promptrequire a local human at a terminal; without a TTY approval-required execution is refused. Clients cannot approve their own calls. Legacyexplicitrefuses approval-required calls. Normal stdio clients do not provide a local TTY.Sandboxing — run the CLI inside Docker or Podman; the default working-directory mount is writable. Discovery still runs on the host. Firecracker support planned.
Argument validation — arguments are validated against the generated JSON schema before the requested tool process is spawned. Arguments are not interpolated into a shell string.
Read-only, approval and sandboxing are opt-in. Exact argv permissions do not prove that a program, its environment or its input files are harmless. Discovery is outside tool execution guards. Output limits bound retained stdout/stderr, not the target's own CPU or memory use. HTTP/SSE defaults to loopback and does not configure authentication or TLS; do not expose it publicly without appropriate protection.
Windows batch targets (.bat/.cmd) are rejected. Output is retained within a byte budget,
including timeouts. See security.md for limitations, configuration migration,
and non-invasive Windows/Linux tests using a single loopback ping.
Architecture
Clean architecture, one responsibility per package:
src/cli_mcp/
├── cli/ # Typer entry point (expose/inspect/serve/export/doctor/init)
├── discovery/ # provider protocol + strategies
├── schema/ # JSON Schema, Markdown docs, OpenAPI
├── executor/ # argv building, subprocess execution, approval, sandbox
├── mcp/ # MCPServer assembly, tool adapters
├── security/ # allow list, read-only rules, access policy
├── config/ # pydantic settings + YAML loading
├── transport/ # stdio, HTTP, Streamable HTTP, SSE
└── plugins/ # entry-point based provider discoveryDependencies point inward: the CLI depends on discovery/schema/executor/security; the MCP layer depends on nothing framework-specific. See docs/architecture.md.
Plugin system
Third parties add discovery providers without touching core code:
from cli_mcp.discovery.base import DiscoveryContext, DiscoveryResult, TargetInfo
class MyProvider:
name = "my-framework"
strategy = "help"
frameworks = ("my-framework",)
def supports(self, target: TargetInfo) -> bool:
return target.framework == "my-framework"
def discover(self, target: TargetInfo, ctx: DiscoveryContext) -> DiscoveryResult | None:
... # return CommandSpecsRegister it:
[project.entry-points."cli_mcp.discovery"]
my-framework = "my_pkg.provider:MyProvider"cli-mcp providers lists every registered provider.
Development
uv run ruff check .
uv run mypy src
uv run pytest # unit + integration + e2e, coverage gate at 90%
pre-commit run --all-filesThe full test suite creates temporary files and runs Git integration commands. For non-invasive validation without test caches, coverage files or generated target scripts, use the focused Windows/Linux commands in security.md.
GitHub Actions run lint, type checking, Windows/Linux tests (Python 3.13/3.14), and
distribution builds on pushes to master/main and pull requests. CI can also be started
manually from the Actions tab. Dependencies are installed from the checked-in lockfile.
Published GitHub releases (or a manual Release workflow run) validate and build distributions, then upload wheels and source distributions as workflow artifacts. PyPI publishing is disabled until a publishing account and trusted publisher are explicitly configured.
Examples
examples/cli-mcp.yaml— full configurationexamples/sample-clis/— small argparse/click/typer/commander apps used by the tests
Documentation
configuration.md — every config key and CLI flag
discovery.md — reflection, help parsing and manifests
security.md — allow list, read-only, approval, sandboxing
transports.md — stdio, HTTP, Streamable HTTP, SSE
clients.md — configuration recipes for Claude, VS Code, Cursor, Cline, Open WebUI
plugins.md — adding a discovery provider for a new framework
architecture.md — how the pipeline fits together
License
Apache License 2.0 — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Find, vet, and run MCP tools through a secure audited gateway with prompt-injection risk scoring
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
327 dev tools via REST API and MCP. Generate Dockerfiles, schemas, K8s, APIs, and more.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables users to define and run MCP tools using declarative YAML configs with built-in trust enforcement, credential brokering, and tamper-evident audit logging.14MIT
- AlicenseNot gradedqualityAmaintenanceTurns any command-line tool into an MCP server by parsing its --help, enabling AI assistants to discover and safely invoke CLI tools with validation, allow-listing, and sandboxing.MIT
- AlicenseNot gradedqualityAmaintenanceExposes selected operations of an existing REST/OpenAPI app as MCP tools with generated schemas, permission annotations, and a risk class, requiring explicit opt-in before anything is listed and a second flag for destructive calls. Enforces security-first guardrails such as environment-injected auth, a single confined base URL, timeouts, response caps, rate limiting, and a local test console for trying tools.MIT
- AlicenseNot gradedqualityCmaintenanceEnables developers to expose any dev tool as a safe, audited MCP server with permission tiers, audit logging, and automatic argument validation.MIT