plugin-mcp
| Placement | runtime (out-of-process over gRPC) |
| Source | github.com/opencharly/charly/candy/plugin-mcp |
| Version | 2026.178.1430 |
| Candy | plugin-mcp |
This plugin is not listed in charly/charly.yml’s compiled_plugins:. It is not part of the shipped binary: charly builds and loads it out-of-process over gRPC when a plan references one of its words (the coexist path).
Providers
Section titled “Providers”The reserved words this plugin serves:
mcp— command classmcp— verb class
What it does
Section titled “What it does”OUT-OF-TREE charly plugin serving TWO MCP capabilities — a standalone Go module (go.mod + main.go) that speaks the Model Context Protocol over go-plugin gRPC via the charly plugin SDK (github.com/opencharly/sdk). charly’s loader fetches this candy’s repo, go-builds the provider binary on the HOST, and serves it OUT-OF-PROCESS via LocalTransport, so the github.com/modelcontextprotocol/go-sdk library lives HERE, out of charly’s core:
-
verb:mcp — the
mcpMCP-protocol CHECK verb (the go-sdk CLIENT). Since the schema-compaction cutover an authoredmcp:step desugars to the internal plugin/plugin_input envelope, and every mcp-exclusive modifier (method/mcp_name/tool/uri/input) lives in the plugin’s OWN #McpInput (schema/mcp.cue); the verb dispatches through the provider registry exactly like a built-in (ResolveVerb → grpcProvider → invokeVerbProvider). The plugin resolves the declared mcp_provides (cc.ResolveImageLabel) + the picked, host-routable dial endpoint (cc.ResolveEndpoint) via the generic reverse-legs (the host owns the podman / OCI-label / port-mapping machinery) — so this plugin needs no container inspection. Full 7-method surface (ping/servers/list-tools/list-resources/list-prompts/call/read). -
command:mcp —
charly mcp …(the go-sdk SERVER), the externalized MCP bridge ported out of charly’s core (the deleted charly/mcp_server.go; the C1 dep-shed that removes go-sdk from the core binary entirely). It builds the tool surface from the host CLI MODEL (charly __cli-model→ sdk.CLIModel) and fork/execscharly <cmd>per tool call — the host stamps CHARLY_BIN with the spawning binary. charly DISPATCHES the command by fork/exec’ing this binary in CLI mode (sdk.Main → cliMain), so it owns real terminal stdio:--stdioserves the editor/LLM integration over stdin/stdout,--listenserves Streamable HTTP (the in-container supervised deployment).
verb:mcp is served over gRPC (the provider registry); command:mcp is served
via the CLI fork/exec path — so command:mcp is declared in plugin.providers
(for the CLI-grammar prescan + baked manifest) but NOT advertised in Describe.
The R10 consumer is an MCP-providing pod bed whose check composes this plugin
(e.g. jupyter / chrome-devtools-mcp) plus the charly-mcp candy that runs
charly mcp serve.
Parameter schema
Section titled “Parameter schema”The CUE schema below is the authoritative grammar for this plugin’s input. It is the same single source that generates the plugin’s Go parameter types and answers the runtime Describe RPC, so this page cannot disagree with either.
schema/mcp.cue
Section titled “schema/mcp.cue”// The `mcp` plugin's OWN CUE schema — the typed plugin_input for the `mcp`// Model-Context-Protocol check verb. It is the SINGLE SOURCE for this plugin's// params, used two ways (the same contract core `spec` and the http plugin use)://// 1. GENERATE the Go param struct — `cue exp gengotypes` (driven by the cue:gen// pipeline, which wraps this with `package params` + `@go(params)`) emits// ../params/cue_types_gen.go, so the provider decodes plugin_input into a// TYPED struct, never a hand-parsed map.// 2. VALIDATE authored input AT RUNTIME — the plugin serves this source over the// Describe channel; the host splices it onto the base (base ++ plugin) and// validates every authored `mcp:` step's plugin_input against #McpInput.//// Since the schema-compaction cutover the per-verb fields LEFT core #Op: an// authored `mcp: <method>` step (scalar sugar) or `mcp: {method: …, tool: …}`// (map form) desugars to the INTERNAL plugin/plugin_input envelope, and every// mcp-exclusive modifier lives HERE — the former core #McpMethod enum is this// def's `method` field. `mcp_name` is read by the plugin (resolve.go's pickMcpEntry// picks the declared mcp_provide entry it names) and is an authored mcp-step field,// so it lives in this def for the closed input validation. The// shared assertion matchers (exit_status/stdout/stderr) and the general// `timeout` stay on core #Op, read off the step Op by the provider.//// SELF-CONTAINED: it references NO base def, so it compiles standalone// (gengotypes + the load-gate compile) AND splices onto the base (base ++ plugin// is a def-name collision check, not a base-reference resolver).#McpInput: { // method — the mcp method to dispatch (the former core #McpMethod enum; also // the scalar-sugar primary: `mcp: <method>`). method: "ping" | "servers" | "list-tools" | "list-resources" | "list-prompts" | "call" | "read" // mcp_name — which declared mcp_provide server to dial when the image // declares several (plugin-side disambiguation; auto-picked when single). mcp_name?: string @go(McpName) // tool — the tool name `call` invokes. tool?: string // uri — the resource URI `read` reads. uri?: string @go(URI) // input — the optional JSON argument blob `call` passes to the tool. input?: string}See also the candy reference for this candy’s install surface.