Skip to main content

What is MCP?

The Model Context Protocol (MCP) is an open standard for connecting large language models to external tools, APIs, and data sources. An MCP server exposes a catalogue of callable tools — each with a name, description, and JSON Schema for its parameters — and the LLM decides at runtime which tool to call and with what arguments. MCP servers run as stdio subprocesses: the client spawns the server binary, communicates over stdin/stdout, and tears it down when the session ends. This model keeps servers lightweight and language-agnostic — you can use npx-hosted community servers or ship your own binary.

How Voxray uses MCP

At pipeline startup, Voxray’s MCP client connects to the configured server subprocess, calls ListTools to enumerate available tools, and converts each MCP tool schema into a FunctionSchema that the LLM service understands. Those schemas are registered on the LLM provider before the first user turn. During a conversation, when the LLM decides to call a tool, it produces a structured tool-call that Voxray’s ToolHandler intercepts. The handler opens a fresh subprocess session, calls session.CallTool() with the LLM-supplied arguments, extracts the text content from the result, optionally applies a per-tool output transform, and returns the result string back to the LLM — which then continues the conversation with that context.

Configuration

Add an mcp block to your config.json:
tools_filter is a whitelist, not a blacklist. If you specify any entries, only those exact tool names are registered — all others are silently skipped. Leave it empty to expose every tool the server advertises.

Tool discovery

Client.GetToolsSchema(ctx) handles discovery:
  1. Spawns the MCP server via mcp.CommandTransport{Command: ...}.
  2. Calls session.ListTools() to retrieve the full tool catalogue.
  3. Iterates each tool, skipping any not present in ToolsFilter (when set).
  4. Converts MCP’s InputSchema (a JSON Schema object) into Voxray’s FunctionSchema, preserving properties and required arrays.
  5. Returns a ToolsSchema with all accepted tools.
RegisterTools calls GetToolsSchema and then calls llm.RegisterTool(schema, handler) for each result, binding a ToolHandler closure that knows which tool name to forward to the subprocess.

Tool execution

Each tool handler is a closure over the tool name. When invoked:
Each tool call opens its own subprocess connection. This is intentional: MCP stdio servers are stateless per invocation, and sharing a single long-lived session across concurrent tool calls would require additional synchronization.

Output filters

ToolsOutputFilters is a map[string]func(any) any set directly on the Client struct in Go code (not configurable via JSON). Use it when the raw MCP tool output needs to be trimmed, reformatted, or redacted before the LLM sees it:
Output filters run in the tool handler goroutine and block the LLM response. Keep them fast. For heavy processing (parsing, summarisation), consider a background worker with a channel.

LLM provider compatibility

MCP tool integration requires the LLM service to implement the LLMServiceWithTools interface. Currently supported providers:
If you configure mcp but your llm_provider does not implement LLMServiceWithTools, tool registration is silently skipped and the agent will run without tools. Check startup logs for mcp: entries to confirm tools were registered.

Common MCP servers

Filesystem server example

Brave Search example

Set BRAVE_API_KEY in your environment before starting Voxray.

Custom Go MCP server

Lifecycle

Tool discovery at Pipeline.Setup() adds a round-trip to the MCP server before the first call is answered. For latency-sensitive deployments, pre-warm pipelines or use tools_filter to limit the number of tools that need to be introspected.