Skip to content

mcp://

Call a tool on an external MCP (Model Context Protocol) server from inside a Helix route. The producer opens a single MCP session per endpoint (lazy sync.Once), packs the exchange body into the tool's argument shape, invokes CallTool, and writes the text response back onto the exchange. Reach for mcp:// when an existing MCP server (Claude desktop tools, third-party MCP integrations, another Helix node running mcp-server://) exposes a tool you want to call from a workflow.

For the other half of the integration — exposing Helix routes as MCP tools — see mcp-server://.

URI shape

mcp://<server-addr>/<tool-name>?transport=<http|sse|stdio>
  • <server-addr> is the host:port (HTTP/SSE) or executable path (stdio) of the MCP server. The path is split at the last /: everything before is the address, the last segment is the tool name.
  • <tool-name> is the MCP tool to call. Can be overridden per exchange via the HelixMcpToolName header.
  • Producer-only — CreateConsumer returns an error.

Parameters

Param Type Default Producer/Consumer/Both Description
(path) server-addr string — Producer Host:port of the MCP server, or the binary path for stdio.
(path) tool-name string — Producer Tool to invoke. Required unless overridden by HelixMcpToolName.
transport enum http Producer http (Streamable HTTP — the default), sse (SSE), or stdio (subprocess).

The component uses the official Anthropic SDK github.com/modelcontextprotocol/go-sdk v1.4.0+. Identity is hard-coded to helix-mcp-client/1.0.0.

Headers

Read by the producer

Header Description
HelixMcpToolName Per-exchange override of the tool to call (wins over the URI path). Use this when the same connection invokes different tools depending on the exchange.

Written by the producer

Header Description
HelixMcpToolName The tool name actually invoked.
HelixMcpIsError Boolean — true if the MCP tool returned IsError=true.

When IsError=true, the producer also calls ex.SetException(...) so the route's error handler kicks in; the response body still contains the tool's text content (or "mcp tool returned error with no message").

Body shaping

The body is converted to MCP Arguments (map[string]any) by:

  • map[string]any → used as-is.
  • string, []byte, json.RawMessage → JSON-decoded into a map; on parse failure wrapped as {"input": <raw>}.
  • nil → {}.
  • anything else → {"input": fmt.Sprintf("%v", body)}.

The response is unpacked in this order: 1. concatenated TextContent from result.Content, 2. fallback to JSON-marshalled result.StructuredContent, 3. empty string.

Examples

Call an HTTP MCP server tool:

workflows:
  - id: ask-search
    trigger: { uri: direct://ask }
    steps:
      - set-body:
          starlang: '{ "query": payload, "limit": 5 }'
      - target: mcp://localhost:8181/search

Stdio transport (subprocess MCP server):

workflows:
  - id: filesystem-lookup
    trigger: { uri: direct://lookup }
    steps:
      - target: mcp:///usr/local/bin/mcp-fs/read_file?transport=stdio

Per-exchange tool selection:

workflows:
  - id: dispatch
    trigger: { uri: direct://dispatch }
    steps:
      - set-header:
          name: HelixMcpToolName
          starlang: header("X-Intent")
      - target: mcp://localhost:8181/_unused

End-to-end: read a payload, ask a remote MCP search tool, then summarize with a local agent:

workflows:
  - id: research
    trigger:
      uri: http-server://0.0.0.0:8080/research
    steps:
      - set-body:
          starlang: '{ "query": payload }'
      - target: mcp://kb-server.internal:8181/search
      - set-body:
          starlang: '"Summarize: " ++ payload'
      - target: agent://summarizer

Behavior notes

  • Lazy connect — the first Process call opens the session; subsequent calls reuse it. The init error is sticky (subsequent calls fail without retrying). Restart the route to retry.
  • Transport differences —
  • http uses the SDK's StreamableClientTransport against http://<addr>.
  • sse uses SSEClientTransport against http://<addr>.
  • stdio execs <addr> as a subprocess (the address is the binary path).
  • No reconnect — if the server drops the session, the next call returns an error from the SDK; there is no automatic reconnect loop.
  • No streaming back — MCP tool calls are RPC-style: the producer waits for the full result. If you need streaming, expose the tool via a different protocol (A2A, AG-UI).

Source

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

See also

  • mcp-server — the inverse: expose Helix routes as MCP tools.
  • a2a, a2a-server — A2A protocol equivalent.
  • tool — Helix-native tool primitive.