cli-mcp features¶
Inventory of what cli-mcp does today. Scope changes should land in the same commit that touches code, so this file stays a faithful mirror of the public API.
Dual-mode (CLI + MCP, same binary)¶
climcp.AttachMCP(root, opts)- appends anmcpsubcommand group to root with two leaves:serve(stdio) andserve-http(Streamable HTTP). Afterapp.Run(ctx, os.Args), the same binary is a normal CLI by default and an MCP server when invoked as<root> mcp serveor<root> mcp serve-http. Themcpsubtree is auto-excluded from the projected MCP tool surface. Seeexamples/dual-mode.mcp serve-httpflags ---addr(with$ADDRenv override),--landing,--no-health. Defaults match the bareRunStreamableHTTP.
Projection¶
climcp.NewServer(*cli.Command, Options) (*mcp.Server, error)- Walks a urfave/cli v3 command tree, registers every leaf command as an MCP tool. Hidden commands skipped.Options.IncludeGroupsexposes non-leaves too.Options.SkipPathshides specific dotted paths.- Tool name - Path segments from root's children joined by
Options.NameJoiner(default_). The root command's name is dropped to avoid redundancy withOptions.Name. Underscore is the safe default because mcporter and similar clients parseserver.tooland would split inside a dot-joined tool name. SetNameJoiner: "."for dot-joined output when every consumer handles dots correctly. - Input schema - Derived from
cmd.Flags: typed properties (boolean/integer/number/string/array) with aliases listed in the description and required flags marked. Positional args expose as anargsarray of string. - Tool execution - Reconstructs argv from MCP input, invokes
root.Run(ctx, argv)in-process, captures stdout / stderr viacmd.Writer. Non-zero exit code surfaces viaCallToolResult.IsError.
Transports¶
- stdio -
climcp.ServeStdio(ctx, root, opts). Default for editor/agent integrations (Claude Code, mcp-inspector, mcporter). - Streamable HTTP (handler) -
climcp.StreamableHTTPHandler(root, opts) (http.Handler, error). Returns the bare handler; mount on anynet/httpserver. - Streamable HTTP (batteries-included) -
climcp.RunStreamableHTTP(ctx, root, opts, srv) error. Builds the projected server, mounts/mcpplus an optional healthcheck and landing page, blocks until ctx is cancelled with graceful shutdown. Pairs withclimcp.AddrFromEnv(fallback)for the container-vs-dev binding convention. - Deprecated - HTTP+SSE (2024-11-05) is reachable through the SDK but not surfaced here.
Server helpers¶
climcp.AddrFromEnv(fallback string) string- returns$ADDRif non-empty, else fallback. Lets the same binary bind127.0.0.1in local dev and0.0.0.0:PORTin a container without if/else inmain.climcp.WriteJSON(w io.Writer, v any) error- indented JSON encoder for tool Action functions that return structured data. MCP renders the text content verbatim, so indented JSON is what an agent sees.
Extension-namespace annotations¶
cli-mcp relays known cli.Command.Metadata keys onto MCP Tool wire fields so client extensions (notably cli-web-ops) can consume them:
| Metadata key | Type | Where it goes |
|---|---|---|
webops.favorite |
bool | tool.Meta["webops.favorite"] |
webops.label |
string | tool.Meta["webops.label"] |
webops.group |
string | tool.Meta["webops.group"] |
webops.confirm |
bool | tool.Annotations.DestructiveHint |
Composition with cli-guard¶
When the wrapped command tree routes through cli-guard/verb.Wrap, MCP tool calls inherit argv validation and audit logging for free. No additional wiring.
Examples (examples/)¶
- serve/ - Stdio-based demo, single-binary
hellotool. - serve-http/ - Streamable HTTP demo binding 127.0.0.1:9090/mcp.
Deployment¶
deploy/Caddyfile.example- Tailscale-bound reverse proxy with bearer-token gate. SSE-friendly (flush_interval -1).
Repo development¶
.coily/coily.yamldeclares local dev verbs.Makefileis the source of truth.coily lintvalidates the yaml/Makefile contract on every CI run..golangci.yaml,staticcheck.confmirror urfave/cli.- GitHub Actions CI runs vet/build/test/lint.