Skip to content

mcp-server://

Expose Helix routes as tools on an MCP (Model Context Protocol) server. The consumer stands up an HTTP, SSE, or stdio MCP endpoint, walks the engine's registered workflows, and turns each invocable route into an MCP tool that external clients (Claude desktop, IDE plugins, other Helix nodes via mcp://) can list and call.

The server is consumer-only — CreateProducer returns an error. Wire it as a from: trigger; the steps below become the per-tool pipeline (rarely used — most servers fan out to other workflows).

URI shape

mcp-server://<host:port>?<params>
mcp-server://stdio?<params>
  • <host:port> is the listen address for HTTP / SSE transports.
  • The literal stdio (without scheme) switches to stdio transport — the MCP server reads/writes the process's stdin/stdout (used by IDE-launched MCP servers).

Parameters

Param Type Default Producer/Consumer/Both Description
(path) addr string — Consumer Listen address (0.0.0.0:8181) or stdio.
transport enum auto Consumer Force http (Streamable), sse, or stdio. Default: stdio when path is stdio, otherwise http.
name string helix-mcp Consumer Server identity (advertised to MCP clients).
version string 1.0.0 Consumer Server version.
workflows string (all) Consumer Comma-separated workflow IDs to expose. Other workflows are skipped.
api_keys string — Consumer Comma-separated API keys. When set, every request must carry Authorization: Bearer <key> or X-API-Key: <key> (constant-time compared).
cors_origins string — Consumer Comma-separated allowed CORS origins. * allows any.
ip_allowlist string — Consumer Comma-separated client IPs that are allowed to connect.
trusted_proxies string — Consumer Comma-separated IPs that bypass IP allowlist + API-key auth (gateway already authenticated upstream).
allowed_tools string (all) Consumer Tool-name whitelist. Empty = all exposed tools are callable.
blocked_tools string — Consumer Tool-name blacklist (applied before whitelist).
rate_limit integer — Consumer Requests per minute (token-bucket). 0 / unset = unlimited.
max_body_bytes integer 1048576 Consumer Max accepted request body size in bytes.

How routes are exposed

A workflow is exposed as an MCP tool when any of:

  1. The workflow's from: URI is tool://..., agui://..., or a2a-server://... (the AI-native triggers — always invocable).
  2. The workflow's from: URI is direct://, seda://, or http-server:// and the workflow has an input-schema: set (explicit opt-in for engineering-style routes).

Workflows without an input schema are skipped with a debug log. Tool names are derived from the workflow ID (sanitizeToolName replaces any character outside [a-zA-Z0-9_\-.] with _).

The route's description: becomes the MCP tool description. The input-schema: becomes the MCP tool inputSchema (with type: object and properties: {} filled in when missing, so strict validators like OpenAI's accept it). Agent-backed routes that lack an input-schema get an auto-generated one with {message, thread_id}.

Resources

In addition to tools, the server publishes one resource:

  • helix://workflows — JSON list of every workflow's {id, from, description, state}. Useful for clients that want to discover what's available before calling.

Headers and session

Each tool call materializes an exchange.NewWithPattern(InOut) with:

Header Description
HelixMcpToolName The tool name (route ID) being invoked.
HelixMcpRouteID Same as above — workflow ID.

The session ID is read from _meta.sessionId in the request arguments. Sessions persist helix.session.state between calls so a tool can carry conversation state.

Return-body shaping:

  • string / []byte → text content.
  • map[string]any / []any → JSON-marshalled text content.
  • everything else → ex.In().BodyAsString().

If ex.IsFailed() or the pipeline returns an error, the result is sent as IsError: true with the error text.

Examples

Expose two specific workflows over HTTP with API-key auth:

workflows:
  - id: mcp-server
    trigger:
      uri: mcp-server://0.0.0.0:8181?workflows=search,translate&api_keys=${MCP_KEY}&cors_origins=*
    steps: []

  - id: search
    description: "Search the knowledge base"
    input-schema:
      type: object
      properties:
        query: { type: string }
      required: [query]
    trigger: { uri: direct://search }
    steps:
      - target: tool://kb-search

  - id: translate
    description: "Translate text"
    input-schema:
      type: object
      properties:
        text:   { type: string }
        target: { type: string }
      required: [text, target]
    trigger: { uri: direct://translate }
    steps:
      - target: agent://translator

Use it from Claude desktop (~/.config/claude/claude_desktop_config.json):

{
  "mcpServers": {
    "helix": {
      "url": "http://helix.local:8181",
      "headers": { "X-API-Key": "${MCP_KEY}" }
    }
  }
}

Stdio (IDE-launched) variant:

workflows:
  - id: stdio-mcp
    trigger: { uri: mcp-server://stdio?name=helix-stdio }
    steps: []

Behind a gateway that already authenticates (skip MCP-level auth from those IPs):

trigger:
  uri: mcp-server://0.0.0.0:8181?api_keys=${KEY}&trusted_proxies=10.0.0.1,10.0.0.2

Behavior notes

  • Per-call security stack — CORS → trusted-proxy check → IP allowlist → API-key auth → rate limit → body-size cap. All five are independent; configure only what you need.
  • Constant-time auth comparison — crypto/subtle.ConstantTimeCompare is used so timing attacks against keys are not viable.
  • Skips its own route — the server never exposes the workflow that hosts it (id mcp-server).
  • Reuses the engine pipeline — every tool call runs through engine.BuildPipeline(route.Processors, hc.Interceptors(), route.ErrorHandler), so interceptors, tracing, and error handlers configured for the route apply to MCP-triggered calls.
  • Resources are read-only — helix://workflows lists workflows; there is no MCP write operation.

Source

pkg/component/mcp/server.go, pkg/component/mcp/tools.go

See also

  • mcp — the client side: call an external MCP server's tool.
  • tool, agent — the AI-native primitives that are auto-exposed.
  • a2a-server, agui, a2ui — sibling protocol servers.