Skip to content

MCP Client Integration

Victor's MCP client launches a server subprocess and communicates over stdio. Pass a
command list to connect; the first argument to MCPClient is a client name, not an
HTTP endpoint URL.

Connect and discover tools

This example starts Victor's own MCP server as a subprocess. Use an absolute path to
the executable if it is not on the child process's PATH.

import asyncio
from victor.integrations.mcp import MCPClient

async def main():
    client = MCPClient()
    try:
        if not await client.connect(["victor", "mcp"]):
            raise RuntimeError("MCP server connection failed")
        for tool in await client.refresh_tools():
            print(tool.name, tool.description)
    finally:
        await client.close()

asyncio.run(main())

Call a tool

After checking the server's advertised schema, call
await client.call_tool(tool_name, **arguments). Arguments are keyword arguments;
there is no positional argument dictionary after the tool name. Tool availability
depends on the connected server and installed dependencies.

Server configuration

MCPServerConfig in victor.integrations.mcp.registry describes a registry-managed
server process. It is not an HTTP MCPServer(host=..., port=...) configuration.
For Victor's server command and client configuration, see the
MCP server reference.

Observability and lifecycle

Close clients to terminate their subprocess and background health monitoring. Runtime
instrumentation uses topic subscriptions. The stdio
connection alone does not sandbox tools or grant remote HTTP access.

Requests are serialized and responses must match their request ID. A timeout,
cancelled request, malformed response or EOF retires that process; Victor never
automatically replays the tool call. A lost response can follow a successful
external write: reconcile through the tool's operation receipt before deciding
whether another action is appropriate.

Retirement detaches the captured process and sandbox owner before awaiting cleanup,
so delayed cleanup cannot terminate a replacement. An owned daemon worker keeps
blocking pipe I/O off the event loop and its default executor. On POSIX, Victor
launches each server in a dedicated process group and terminates that group during
retirement, including descendants that ignore the graceful signal. If a descendant
escapes the group and retains a pipe, get_status()["transport_cleanup_pending"]
remains true and this client refuses reconnection until cleanup settles. This bounds
stranded workers per client. Prefer await client.close() for orderly shutdown.

A stdio bridge can connect to a separately managed application service. Its exit
must not be interpreted as closing every shared application session. Persistent
sessions, page generations, grants and write receipts belong to that service,
independently of the MCP connection.

The earlier HTTP-style examples are preserved in page history.