Skip to content

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 connects to an external MCP server over stdio and lets you list and call its tools programmatically.

Pass a command list ([executable, *args]) and an optional dict of environment variables:

import asyncio
from cyclops import MCPClient
async def main():
client = MCPClient()
await client.connect_stdio(["python", "my_mcp_server.py"])
# ...
await client.disconnect()
asyncio.run(main())

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"])

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"

Always disconnect when done to release the subprocess:

await client.disconnect()
import asyncio
from 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())

The MCP filesystem server is a widely used MCP server that exposes file-system operations. Connect to it with npx:

import asyncio
from 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 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.

Register a Cyclops tool with the server:

import asyncio
from cyclops import MCPServer
from cyclops.toolkit import tool
@tool
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b
@tool
def 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())

Starts the MCP server and blocks until the client disconnects. Run this script as a subprocess from your MCP host configuration.

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 default
await server.run_stdio()

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 asyncio
from cyclops import Agent, AgentConfig, MCPClient
from cyclops.toolkit.tool import BaseTool
from 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())
examples/mcp_server.py
"""MCP Server example - exposing tools via Model Context Protocol"""
import asyncio
from cyclops.mcp import MCPServer
from cyclops.toolkit import tool
@tool
def add(a: float, b: float) -> float:
"""Add two numbers"""
return a + b
@tool
def multiply(a: float, b: float) -> float:
"""Multiply two numbers"""
return a * b
@tool
def 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())