MCP
The Model Context Protocol (MCP) is an open standard for exposing tools to LLMs. Cyclops ships a lightweight client and server so you can consume tools from any MCP server or publish your own Cyclops tools as an MCP server.
MCPClient
Section titled “MCPClient”MCPClient connects to an external MCP server over stdio and lets you list and call its tools programmatically.
connect_stdio
Section titled “connect_stdio”Pass a command list ([executable, *args]) and an optional dict of environment variables:
import asynciofrom cyclops import MCPClient
async def main(): client = MCPClient() await client.connect_stdio(["python", "my_mcp_server.py"]) # ... await client.disconnect()
asyncio.run(main())list_tools
Section titled “list_tools”Returns a list of dicts, each with "name", "description", and "input_schema" keys:
tools = await client.list_tools()for t in tools: print(t["name"], "-", t["description"])call_tool
Section titled “call_tool”Calls a named tool with a dict of arguments and returns the result as a string:
result = await client.call_tool("add", {"a": 5, "b": 3})print(result) # "8.0"disconnect
Section titled “disconnect”Always disconnect when done to release the subprocess:
await client.disconnect()Full example
Section titled “Full example”import asynciofrom cyclops import MCPClient
async def main(): client = MCPClient() try: await client.connect_stdio(["python", "mcp_server.py"])
tools = await client.list_tools() print("Available tools:", [t["name"] for t in tools])
result = await client.call_tool("greet", {"name": "World"}) print(result) # "Hello, World!" finally: await client.disconnect()
asyncio.run(main())Connecting to the filesystem MCP server
Section titled “Connecting to the filesystem MCP server”The MCP filesystem server is a widely used MCP server that exposes file-system operations. Connect to it with npx:
import asynciofrom cyclops import MCPClient
async def main(): client = MCPClient() # npx downloads and runs the official filesystem server on demand. await client.connect_stdio( ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/tmp"], )
tools = await client.list_tools() print("Filesystem tools:", [t["name"] for t in tools])
# List files in /tmp. result = await client.call_tool("list_directory", {"path": "/tmp"}) print(result)
await client.disconnect()
asyncio.run(main())MCPServer
Section titled “MCPServer”MCPServer wraps a ToolRegistry and exposes its tools over the stdio MCP protocol. Any MCP-compatible client (Claude Desktop, Cursor, tiny-agents) can connect to it.
add_tool
Section titled “add_tool”Register a Cyclops tool with the server:
import asynciofrom cyclops import MCPServerfrom cyclops.toolkit import tool
@tooldef add(a: float, b: float) -> float: """Add two numbers.""" return a + b
@tooldef greet(name: str) -> str: """Greet someone by name.""" return f"Hello, {name}!"
async def main(): server = MCPServer(name="math-server", load_plugins=False) server.add_tool(add) server.add_tool(greet) await server.run_stdio()
asyncio.run(main())run_stdio
Section titled “run_stdio”Starts the MCP server and blocks until the client disconnects. Run this script as a subprocess from your MCP host configuration.
Plugin auto-discovery
Section titled “Plugin auto-discovery”Set load_plugins=True (the default) to have MCPServer automatically load all installed Cyclops toolkit plugins via entry points. This is the zero-config path to expose a whole ecosystem of tools.
server = MCPServer(name="my-agent-tools") # load_plugins=True by defaultawait server.run_stdio()Using MCP tools with Agent
Section titled “Using MCP tools with Agent”To bridge an MCP server into a Cyclops agent, connect the client, wrap its tools as BaseTool objects, and pass them to the agent.
import asynciofrom cyclops import Agent, AgentConfig, MCPClientfrom cyclops.toolkit.tool import BaseToolfrom typing import Any
class MCPProxyTool(BaseTool): """Wraps a single MCP tool so the agent can call it."""
def __init__(self, client: MCPClient, name: str, description: str): super().__init__(name=name, description=description) self._client = client
async def execute(self, **kwargs: Any) -> str: return await self._client.call_tool(self.name, kwargs)
async def main(): client = MCPClient() await client.connect_stdio(["python", "mcp_server.py"])
# Build proxy tools from the server's tool list. mcp_tools = await client.list_tools() proxy_tools = [ MCPProxyTool(client, t["name"], t["description"] or "") for t in mcp_tools ]
config = AgentConfig(model="groq/llama-3.1-8b-instant") agent = Agent(config, tools=proxy_tools)
response = await agent.arun("Add 17 and 25, then greet Alice.") print(response)
await client.disconnect()
asyncio.run(main())Full example
Section titled “Full example”"""MCP Server example - exposing tools via Model Context Protocol"""
import asynciofrom cyclops.mcp import MCPServerfrom cyclops.toolkit import tool
@tooldef add(a: float, b: float) -> float: """Add two numbers""" return a + b
@tooldef multiply(a: float, b: float) -> float: """Multiply two numbers""" return a * b
@tooldef greet(name: str) -> str: """Greet someone by name""" return f"Hello, {name}!"
async def main(): # Create MCP server with tools server = MCPServer(name="math-toolkit", load_plugins=False)
# Add tools manually server.add_tool(add) server.add_tool(multiply) server.add_tool(greet)
print("Starting MCP server...") print("Tools available: add, multiply, greet") print("Connect via stdio transport\n")
# Run server await server.run_stdio()
if __name__ == "__main__": asyncio.run(main())