cli-wrap-mcp
Provides tools for exploring GitHub repositories and pull requests by wrapping the GitHub CLI (gh).
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cli-wrap-mcpEcho 'Hello, World!' using the echo tool."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cli-wrap-mcp
Turn any CLI into an MCP server with a declarative YAML config.
cli-wrap-mcp is a small engine that reads a YAML file describing a set of tools
(each tool = one argv template + typed, validated parameters) and serves them as an
MCP stdio server. No code generation, no per-tool server projects — one config file
per server.
server:
name: gh-explorer
description: Read-only GitHub exploration tools.
tools:
- name: pr_view
description: Show a pull request.
argv: ["gh", "pr", "view", "{number}", "--repo", "{repo}", "--json", "title,body,state"]
params:
number:
type: integer
description: PR number.
repo:
type: string
description: Repository in owner/name form.
pattern: "[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+"Why
Giving an agent raw shell access means permissioning at the granularity of "can run commands". Wrapping a CLI as an MCP server flips that: the agent sees a small set of narrow, typed, validated tools, and you manage permissions per MCP server / per tool. A config file is all it takes to mint a new server, so each domain (GitHub exploration, build tooling, ...) can ship its own MCP definition without owning any engine code.
Related MCP server: MCP-Ables
Safety design
Safety is the core of this engine, enforced at execution and load time:
No shell, ever. Commands run as
argvarrays withshell=False. There is no code path that concatenates a shell string, so; rm -rf /,$(...), pipes etc. stay inert single arguments.Validation before interpolation. Every parameter value must pass its
typecheck,pattern(regex fullmatch), andenumbefore it is rendered into argv.Argument-injection guard. Rendered values starting with
-are rejected by default, so a model cannot smuggle--force-style flags into a positional slot. Opt out per parameter withallow_dash_prefix: true.Strict placeholders.
{param}only — format specs, conversions, attribute or index access ({p.__class__}) are load-time errors, as are placeholders that reference undefined parameters.stdout is protocol-only. The MCP stdio channel is never polluted; all engine logging goes to stderr.
Bounded output. Inline tool output is truncated at
inline_max_output_bytesby default;inline_on_large_output: filediverts oversized output to a file (path plus head/tail excerpts), andoutput_mode: filealways writes the full output to a file — success or failure — for audit-trail use. Callers can also pass the auto-injectedfile_output_dirparameter to force the full output into a directory of their choosing.Job isolation. Background job IDs are strictly format-checked, blocking path traversal through
job_id.Guardrails, not a sandbox. For "arbitrary subcommand" tools (an
arrayparam withallow_dash_prefix: true),deny_pattern, forced trailing flags, andenvforcing constrain what the model can do — but a determined CLI often has more than one spelling for the same effect. Treat them as accident prevention and put the real security boundary in the credentials the wrapped CLI runs with (seeexamples/gcloud.yml).
Trust model: the YAML config is a trusted local file (it decides which binaries can run); the tool arguments coming from the model are untrusted and constrained as above. The wrapped CLI runs with your local privileges.
Install / run
Requires Python >= 3.11. With uv:
uvx cli-wrap-mcp@0.1.0 --config /path/to/config.ymlOr straight from git (pin a tag, or a commit SHA for full immutability):
uvx --from git+https://github.com/hkak03key/cli-wrap-mcp@v0.1.0 cli-wrap-mcp --config /path/to/config.yml
uvx --from git+https://github.com/hkak03key/cli-wrap-mcp@<commit-sha> cli-wrap-mcp --config /path/to/config.ymlTry the bundled examples:
uvx cli-wrap-mcp@0.1.0 --config examples/echo.ymlexamples/gcloud.yml shows the "arbitrary subcommand with
forced env vars and options" pattern (variadic array param + deny_pattern +
env forcing).
Claude Code
Project .mcp.json:
{
"mcpServers": {
"echo-demo": {
"command": "uvx",
"args": ["cli-wrap-mcp@0.1.0", "--config", "./configs/echo.yml"]
}
}
}From a Claude Code plugin, ship only your configs and reference them via
${CLAUDE_PLUGIN_ROOT}:
{
"mcpServers": {
"gh-explorer": {
"command": "uvx",
"args": ["cli-wrap-mcp@0.1.0", "--config", "${CLAUDE_PLUGIN_ROOT}/configs/gh-explorer.yml"]
}
}
}Config reference
Top level:
Key | Required | Description |
| yes | MCP server name. |
| no | Served as the MCP |
| no | Default output mode for all tools: |
| no | Default inline size limit for all tools. |
| no | Default overflow behavior for all tools: |
| no | Default output root for all tools (absolute path; see per-tool |
| no | Environment variables forced for every tool (mapping of |
| yes | List of tool definitions (at least one). |
Per tool:
Key | Required | Default | Description |
| yes | — | Tool name, |
| no |
| Tool description shown to the model. |
| yes | — | Non-empty list of strings. |
| no |
|
|
| no |
| Sync-mode timeout. |
| no | inherits |
|
| no | inherits | Inline size limit ( |
| no | inherits | What happens when inline output exceeds the limit: |
| no | inherits | Output root for this tool (absolute path). File outputs go to |
| no |
| Mapping of parameter name → spec. |
| no |
| Environment variables forced for this tool. Merged over |
Per parameter (params.<name>):
Key | Required | Default | Description |
| no |
|
|
| no |
| Shown in the tool schema. |
| no |
| Optional parameters must have a |
| no | — | Regex allowlist, string/array params, matched with |
| no | — | Regex blocklist, string/array params: a value that |
| no | — | Allowed values (type-checked at load time; string items for arrays). |
| no | — | Used when the argument is omitted (type-checked at load time). |
| no |
| Permit values starting with |
Array (variadic) parameters
type: array accepts a list of strings and expands into that many argv elements —
use it to pass a variable-length subcommand tail (gcloud {args}). Rules:
The placeholder must be an entire argv element (
"{args}"); embedding it in a larger element ("--x={args}") is a load-time error, because the expansion would collapse into one element and change meaning.pattern,deny_pattern,enum, and the dash-prefix guard are applied to each item individually; every item stays exactly one argv element (no shell, no word splitting).An empty list expands to zero elements. Optional arrays default to
[]unless an explicitdefaultis given.Fixed argv elements placed after the placeholder still apply, which lets a config force trailing flags that override anything the model passed earlier (for argparse-style CLIs the last occurrence of a flag wins).
Parameter names must match [a-z_][a-z0-9_]* and must not be Python keywords.
file_output_dir is reserved: the engine injects it into every sync tool as an
optional absolute-path parameter; when set, the full output is always written under
that directory — regardless of size, exit code, or the tool's output_mode — and
only the file path plus excerpts are returned. It overrides the config-level
file_output_dir for that call.
File output layout
Every file output is a per-invocation directory (same layout as job dirs):
<root>/outputs/<tool>-<timestamp>-<id>/
stdout.log # full stdout
stderr.log # full stderr
meta.json # tool, argv, started_at, exit_code (timed_out on timeout)
<root>/jobs/<job_id>/
stdout.log stderr.log meta.json pid exit_codemeta.json records what was executed, so a file-mode tool leaves a self-contained
audit trail: what ran, when, what it printed (including failures and timeouts,
best-effort). <root> resolution: per-call file_output_dir param > tool
file_output_dir > defaults.file_output_dir > ~/.cache/cli-mcp/<server>/
(override the cache location with CLI_MCP_CACHE_DIR).
Job mode
mode: job wraps long-running commands. Instead of one tool, four are exposed:
<name>_start— starts the command detached (own process group), returns ajob_id<name>_status— running/exited state plus stdout/stderr tails<name>_result— final output (tail-limited byinline_max_output_bytes)<name>_cancel— SIGTERM to the whole process group
Job logs and metadata persist under <root>/jobs/ (the tool's file_output_dir,
or the cache dir), so finished jobs remain inspectable (best-effort) even across
server restarts. See examples/sleep-job.yml.
Development
uv sync
uv run pytestReleases are published to PyPI via GitHub Releases using
Trusted Publishing (OIDC, no API tokens) —
see .github/workflows/publish.yml.
License
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceSimple MCP Runner makes it effortless to safely expose system commands to language models via a lightweight MCP server—all configurable with a clean, minimal YAML file and zero boilerplate.MIT
- Flicense-qualityDmaintenanceTurns any shell command into an MCP server by defining command-line tools in simple YAML files. Enables AI agents to execute system commands, security scanners, DevOps tools, and CLI utilities directly from chat interfaces.4
- Alicense-qualityDmaintenanceAn MCP server that publishes CLI tools on your machine for discoverability by LLMs81MIT
- FlicenseBqualityDmaintenanceA flexible MCP server that enables users to define and execute arbitrary command-line tools through secure, JSON-based configuration files. It features parameter sanitization, directory scoping, and execution controls to safely integrate CLI utilities with Claude Desktop.11
Related MCP Connectors
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.
Scans MCP servers for tool poisoning, prompt injection and supply chain risks.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/hkak03key/cli-wrap-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server