ractogateway.mcp.agent

MCPAgent — agentic tool-execution loop for OpenAI, Google, and Anthropic kits.

MCPAgent bridges the gap between an LLM developer kit and a ToolRegistry (populated from one or more MCP servers) by running the full agentic loop automatically:

LLM call
   │
   ├─ finish_reason == "tool_call"  ──►  execute all tool calls
   │                                         │
   │                                         └──► append results as
   │                                              user follow-up
   │
   └─ finish_reason != "tool_call"  ──►  return final LLMResponse

The loop repeats up to max_turns times to prevent infinite recursion.

Works with all three provider developer kits — the kit is duck-typed via a lightweight _ChatKitProtocol so no provider package is needed at import time.

Usage

from ractogateway.openai_developer_kit import OpenAIDeveloperKit
from ractogateway.mcp import MCPAgent, MCPClientConfig, RactoMCPClient
from ractogateway._models.chat import ChatConfig

# Build a ToolRegistry from an MCP server
config = MCPClientConfig(transport="stdio", command="python",
                         args=["-m", "my_server"])
registry = RactoMCPClient(config).list_tools_sync()   # one-shot fetch

# Or build the registry async:
# async with RactoMCPClient(config) as c:
#     registry = await c.to_registry()

kit   = OpenAIDeveloperKit(model="gpt-4o")
agent = MCPAgent(kit, registry, max_turns=8)

response = agent.run(
    ChatConfig(user_message="What is the weather in Tokyo and London?")
)
print(response.content)

Same code works for Google and Anthropic:

from ractogateway.google_developer_kit import GoogleDeveloperKit
kit = GoogleDeveloperKit(model="gemini-2.0-flash")
agent = MCPAgent(kit, registry)

from ractogateway.anthropic_developer_kit import AnthropicDeveloperKit
kit = AnthropicDeveloperKit(model="claude-opus-4-6")
agent = MCPAgent(kit, registry)
class ractogateway.mcp.agent.MCPAgent(kit, registry, *, max_turns=10)[source]

Bases: object

Agentic tool-execution loop compatible with all three developer kits.

Runs the LLM → tool-call → execute → continue loop automatically, returning the final LLMResponse once the LLM produces a non-tool response or max_turns is reached.

Parameters:
  • kit (Any) – Any developer kit with chat() / achat() methods: OpenAIDeveloperKit, GoogleDeveloperKit, or AnthropicDeveloperKit.

  • registry (ToolRegistry) – Tool registry containing callables for each tool the LLM can call. Typically populated via RactoMCPClient.to_registry() or MCPMultiClient.to_registry().

  • max_turns (int) – Maximum number of tool-call rounds before the loop stops and returns the last response. Prevents infinite recursion.

Example

from ractogateway.openai_developer_kit import OpenAIDeveloperKit
from ractogateway.mcp import MCPAgent, RactoMCPClient, MCPClientConfig
from ractogateway._models.chat import ChatConfig

cfg    = MCPClientConfig(transport="stdio", command="python",
                         args=["-m", "my_server"])
reg    = RactoMCPClient(cfg).list_tools_sync()
kit    = OpenAIDeveloperKit(model="gpt-4o")
agent  = MCPAgent(kit, reg, max_turns=6)
result = agent.run(ChatConfig(user_message="Search for recent AI papers"))
print(result.content)
classmethod from_mcp(kit, configs, *, max_turns=10)[source]

Build an agent by fetching tools from one or more MCP servers.

Opens a one-shot connection per config, fetches tools, closes the connection, and constructs the agent with the merged registry.

Note

This is a sync classmethod; it uses asyncio.run() and therefore cannot be called from within a running event loop. In async code, build the registry yourself:

async with MCPMultiClient(configs) as multi:
    registry = await multi.to_registry()
agent = MCPAgent(kit, registry)
Parameters:
  • kit (Any) – Any RactoGateway developer kit.

  • configs (list[MCPClientConfig]) – MCP server connection configs.

  • max_turns (int) – Maximum tool-call rounds.

Return type:

MCPAgent

Returns:

MCPAgent – Ready to call run() or arun().

run(config)[source]

Run the agentic loop synchronously.

Injects the tool registry from this agent into config (overriding config.tools if already set).

Parameters:

config (ChatConfig) – Initial chat config. prompt must be set here or on the kit.

Return type:

LLMResponse

Returns:

LLMResponse – Final response after tool calls are resolved.

async arun(config)[source]

Run the agentic loop asynchronously.

Supports async tool callables (async def); sync callables are called directly.

Parameters:

config (ChatConfig) – Initial chat config.

Return type:

LLMResponse

Returns:

LLMResponse – Final response after tool calls are resolved.

property registry: ToolRegistry

The ToolRegistry used by this agent.

property max_turns: int

Maximum number of tool-call rounds per run() call.