Skip to content

Agent Interoperability: MCP, UTCP, and A2A

In a nutshell

This page is about letting OVOS work together with other AI systems. OVOS can offer its abilities, like speech, translation, and reasoning, to outside AI tools. It can also call on them, using a few shared "languages" (the protocols MCP, UTCP, and A2A) so different systems can find and use each other. Think of it as agents agreeing on a common plug and socket so they can cooperate. See the Glossary for unfamiliar terms.

OVOS exposes its speech, translation, and reasoning services as agent tools via two discovery and calling protocols: MCP (Model Context Protocol) and UTCP (Universal Tool Calling Protocol). It also implements bidirectional A2A (Agent-to-Agent) bridging.

flowchart TD
    subgraph OVOS Service Servers
        STT[STT Server]
        TTS[TTS Server]
        TX[Translate Server]
        PS[Persona Server]
    end
    Ext["External MCP/UTCP<br/>client<br/>e.g. Claude Desktop"] -->|/mcp, /utcp| STT
    Ext -->|/mcp, /utcp| TTS
    Ext -->|/mcp, /utcp| TX
    Ext -->|"/mcp, /utcp,<br/>/tools/*"| PS
    PS -->|"/.well-known/<br/>agent-card.json,<br/>SendMessage"| A2AClient["External<br/>A2A client"]
    ExtA2A["External<br/>A2A server"] -->|"ovos-a2a-solver<br/>ChatEngine"| Persona[OVOS persona]
    ExtMCP["External MCP/UTCP<br/>server"] -->|"ovos-mcp-toolbox /<br/>ovos-utcp-toolbox"| Loop["Agentic loop<br/>ToolBox"]

Diagram: The flow starts at an external MCP/UTCP client or server and ends at OVOS's service servers or agentic loop ToolBox, branching between the persona server's A2A client link and the OVOS-persona A2A solver path.

Not what you're looking for?

This page is about LLM/agent tool protocols (MCP/A2A). If you're building a voice satellite or a remote voice client instead, see HiveMind Agents.


Protocol Overview

Protocol Discovery Invocation Deps
UTCP GET /utcp → UTCP 1.0 JSON manifest POST /utcp/{tool} or native HTTP endpoints None (always on)
MCP MCP initialize + list_tools call_tool over Streamable HTTP / SSE pip install …[mcp]
A2A GET /.well-known/agent-card.json (agent card; /.well-known/agent.json kept for 0.3.x clients) JSON-RPC 2.0 SendMessage / SendStreamingMessage (0.3.x clients: message/send / message/stream) pip install …[a2a]

MCP + UTCP on the Service Servers

STT Server

pip install --pre "ovos-stt-http-server[mcp]>=0.26.0a1"
ovos-stt-server --engine ovos-stt-plugin-whisper --port 8080
Endpoint Method Description
/utcp GET UTCP manifest (always on, no extra package required)
/mcp Streamable HTTP MCP server (opt-in: start with --mcp, requires the [mcp] extra)

MCP is opt-in: pass --mcp at startup (the flag exists on all the OVOS servers now). With the flag set but the extra missing, the server logs a warning and runs without the endpoint.

UTCP tools exposed: stt, lang_detect, status.

Claude Desktop config:

{
  "mcpServers": {
    "ovos-stt": {
      "transport": "http",
      "url": "http://localhost:8080/mcp"
    }
  }
}

TTS Server

pip install "ovos-tts-server[mcp]"
ovos-tts-server --engine ovos-tts-plugin-phoonnx --port 9666 --mcp
Endpoint Method Description
/utcp GET UTCP manifest (always on)
/mcp Streamable HTTP MCP server (requires [mcp] extra and --mcp flag)

UTCP tools exposed: tts_status, tts_synthesize_v2, tts_synthesize_legacy.

MCP tool: synthesize. Parameters: text (str), voice (str, optional), lang (str, optional). Returns base64 WAV.

# Discover all TTS tools via UTCP
curl -s http://localhost:9666/utcp | jq '.tools[].name'

# Synthesize via HTTP
curl -s 'http://localhost:9666/v2/synthesize?utterance=hello%20world' -o out.wav

Translate Server

pip install --pre "ovos-translate-server[mcp]>=0.10.0a1"
python -m ovos_translate_server --tx-engine ovos-google-translate-plugin --port 9686 --mcp
Endpoint Method Description
/utcp GET UTCP manifest (always on)
/mcp Streamable HTTP MCP server (requires [mcp] extra and the --mcp flag)

UTCP tools: ovos_translate.translate, ovos_translate.translate_with_source, ovos_translate.detect_language, ovos_translate.classify_language, ovos_translate.supported_languages, and the native HTTP REST endpoints.

MCP tools: translate (params: text, target_lang, optional source_lang), detect_language (param: text).

Persona Server: Tool Plugins via MCP + UTCP

The persona server surfaces every installed OPM ToolBox plugin as both a UTCP tool and an MCP tool.

pip install --pre "ovos-persona-server[mcp]"
ovos-persona-server --persona my_persona.json
Endpoint Method Description
/tools/manual GET UTCP 1.0 manifest of all installed tool plugins
/tools/{name} POST Direct HTTP invocation of a tool
/mcp Streamable HTTP MCP server (one tool per OPM ToolBox tool)
/mcp (stdio) Console script ovos-persona-tools-mcp

A2A (Agent-to-Agent Protocol)

A2A is the Google A2A open protocol. An A2A server publishes a discovery document (agent card) and accepts tasks via JSON-RPC 2.0.

Persona Server as A2A Server

pip install --pre "ovos-persona-server[a2a]>=0.17.2a1"
ovos-persona-server --persona my_persona.json

The OVOSPersonaAgentExecutor wraps the active persona. create_a2a_application() builds the A2A app, with an agent card at /.well-known/agent-card.json (the 0.3.x /.well-known/agent.json path stays as a compat alias) and support for blocking (SendMessage) and streaming (SendStreamingMessage) modes when the persona solver supports streaming.

Start it with --a2a-base-url, which both enables the /a2a endpoint and sets the public base URL that goes into the agent card:

ovos-persona-server --persona my.json --a2a-base-url http://myhost:8337/a2a

The flag needs a2a-sdk installed. See Persona Server.

OVOS as A2A Consumer

OpenVoiceOS/ovos-a2a-agent-plugin (pip: ovos-a2a-solver-plugin) is an A2AChatEngine ChatEngine plugin (OPM group opm.agents.chat, entry point ovos-a2a-solver) that delegates persona reasoning to any external A2A server.

{
  "name": "my-a2a-persona",
  "handlers": ["ovos-a2a-solver"],
  "ovos-a2a-solver": {
    "agent_url": "https://my-a2a-agent.example.com",
    "auth_header": "Bearer <token>",
    "timeout": 60,
    "streaming": false
  }
}

Config keys:

Key Default Description
agent_url Base URL of the A2A server (required)
auth_header Authorization header value, e.g. Bearer <token>
timeout 60 Seconds per call
streaming false Use the SSE streaming endpoint when true

ovos-tool-adapters: Consuming MCP/UTCP from the Agentic Loop

OpenVoiceOS/ovos-tool-adapters bridges external MCP and UTCP servers into the OVOS agentic loop as standard ToolBox plugins.

pip install ovos-tool-adapters[mcp]     # MCP support
pip install ovos-tool-adapters[utcp]    # UTCP support

Add to a persona JSON:

{
  "name": "researcher",
  "handlers": ["ovos-react-loop"],
  "ovos-react-loop": {
    "brain": "ovos-chat-openai-plugin",
    "toolboxes": ["ovos-mcp-toolbox"],
    "ovos-mcp-toolbox": {
      "transport": "stdio",
      "command": "uvx",
      "args": ["mcp-server-fetch"],
      "timeout": 30
    }
  }
}

ovos-persona selects its engine via handlers (see Personas for the legacy solvers alias). The agentic loop names its inner LLM with brain and loads adapters via toolboxes. Neither ovos-persona nor ovos-tool-adapters reads the chat_module key seen in some READMEs.

MCP transports (ovos-mcp-toolbox)

Transport Config
stdio (subprocess) "transport": "stdio", "command": "uvx", "args": [...], optional "env": {...}
SSE "transport": "sse", "url": "http://..."
Streamable HTTP "transport": "http", "url": "http://..."

For stdio, env is an optional dict of extra environment variables passed to StdioServerParameters, letting you inject secrets or PATH into the subprocess MCP server. Both ovos-mcp-toolbox and ovos-utcp-toolbox also accept a per-instance toolbox_id (defaults ovos-mcp-toolbox / ovos-utcp-toolbox) so multiple servers of the same type can run side by side, and a timeout (default 30 seconds per call) to tune slow tools.

UTCP (ovos-utcp-toolbox)

{
  "toolboxes": ["ovos-utcp-toolbox"],
  "ovos-utcp-toolbox": {
    "utcp_config": {
      "tool_providers": [
        {"name": "stt", "provider_type": "http", "url": "http://localhost:8080/utcp"}
      ]
    }
  }
}

A background asyncio event loop keeps sessions alive between tool calls. Each server's JSON Schema is translated to a Pydantic model at discovery time so the LLM receives the actual input schema.

Tool discovery degrades gracefully: if the mcp/utcp extra is missing, or the configured server cannot be reached, list_tools() logs a LOG.warning and returns an empty list rather than crashing the agent loop. A misconfigured toolbox therefore loads zero tools silently. Check the logs when expected tools are absent.

ovos-tool-adapters and the Persona Server's own MCP/UTCP bridge

Both MCPToolBox and UTCPToolBox (from ovos-tool-adapters) and the Persona Server's tool surface (/tools/manual, /mcp) are ToolBox plugins under the same opm.agents.toolbox entry-point group, so installing ovos-tool-adapters alongside ovos-persona-server also exposes the bridged external tools through the Persona Server's own MCP/UTCP endpoints. Every ToolBox implementation (DuckDuckGoToolbox, WikipediaToolbox, MCPToolBox, UTCPToolBox, ...) takes (config=None, bus=None) and passes its own toolbox_id up to the base class, so the Persona Server constructs each one with a single cls(config=cfg, bus=bus) call. See Agent Tool Plugins for the full contract.


Read next: OpenAI-compatible Related: Agent Tool Plugins · GGUF / Local LLM