Skip to main content

Core agent framework with MCP toolkit support

Project description

Cyclops

Build LLM agents in Python. Any model. Any tool. No magic.


Quick Start | Examples | Docs | Why Cyclops


PyPI Python 3.10+ License: MIT Tests Stars


Cyclops is a thin wrapper around LiteLLM that gives you agents, tool calling, streaming, structured output, memory, and MCP in one clean API. It works with every model LiteLLM supports. It doesn't hide the underlying calls from you.

Install

pip install cyclops-ai
uv add cyclops-ai

Quick Start

from cyclops import Agent, AgentConfig

agent = Agent(AgentConfig(model="gpt-4o-mini"))
print(agent.run("What is the capital of Japan?"))

Add tools:

from cyclops import Agent, AgentConfig
from cyclops.toolkit import tool

@tool
def get_price(ticker: str) -> str:
    """Get stock price for a ticker symbol"""
    return f"{ticker}: $142.50"

agent = Agent(AgentConfig(model="gpt-4o-mini"), tools=[get_price])
print(agent.run("What is Apple's stock price?"))
# The agent calls get_price("AAPL") automatically

What's included

Tool loop Calls tools in a loop until the model stops asking for them, not just one round
Streaming agent.stream() and agent.astream() for token-by-token output
Structured output agent.run(..., response_model=MyModel) returns a Pydantic instance
Cost tracking agent.run_with_response() returns tokens used and estimated cost
Memory InMemoryStorage and FileStorage for persistent key-value context
MCP Connect to any MCP server as a tool source, or expose your tools as an MCP server
Plugins Install cyclops-toolkit-* packages and tools are discovered automatically
Any LLM OpenAI, Anthropic, Groq, Gemini, Ollama, Together AI, Bedrock, and 100+ more via LiteLLM
Fallback routing Pass a LiteLLM Router for automatic failover and load balancing
Naive mode Prompt-based tool calling for models without native function calling support

Streaming

agent = Agent(AgentConfig(model="gpt-4o-mini"))

for chunk in agent.stream("Explain the water cycle"):
    print(chunk, end="", flush=True)

Async:

async for chunk in agent.astream("Write a haiku about Python"):
    print(chunk, end="", flush=True)

Structured Output

from pydantic import BaseModel
from cyclops import Agent, AgentConfig

class Summary(BaseModel):
    title: str
    key_points: list[str]
    sentiment: str

agent = Agent(AgentConfig(model="gpt-4o-mini"))
result = agent.run("Summarize the French Revolution", response_model=Summary)

print(result.title)       # "The French Revolution"
print(result.key_points)  # ["Storming of the Bastille", ...]

Cost and Token Tracking

response = agent.run_with_response("Write a product description for noise-cancelling headphones")

print(f"Model:      {response.model}")
print(f"Tokens:     {response.tokens_used}")
print(f"Cost:       ${response.cost:.6f}")
print(f"Answer:     {response.content}")

Multi-Turn Conversations

History is kept automatically. Call reset() to start fresh.

agent = Agent(AgentConfig(model="gpt-4o-mini"))

agent.run("My name is Alice and I work in Tokyo")
print(agent.run("Where do I work?"))  # "You work in Tokyo"

agent.reset()
print(agent.run("What's my name?"))   # no memory of Alice

Memory

import asyncio
from cyclops import Agent, AgentConfig, FileStorage

memory = FileStorage("./memory.json")  # persists across restarts

async def main():
    await memory.store("user_name", "Alice")
    await memory.store("language", "Python")

    name = await memory.retrieve("user_name")
    print(f"Hello, {name}")

asyncio.run(main())

MCP

Connect to any MCP server:

from cyclops.mcp import MCPClient

client = MCPClient()
await client.connect_stdio(["npx", "-y", "@modelcontextprotocol/server-filesystem", "."])

tools = await client.list_tools()
result = await client.call_tool("read_file", {"path": "README.md"})
await client.disconnect()

Expose your tools as an MCP server:

from cyclops.mcp import MCPServer
from cyclops.toolkit import tool

@tool
def lookup(id: str) -> str:
    """Look up a record by ID"""
    return f"Record {id}: active"

server = MCPServer("my-server")
server.add_tool(lookup)
await server.run_stdio()

Providers

Switch models by changing one string. Set the matching API key as an environment variable.

# OpenAI
Agent(AgentConfig(model="gpt-4o-mini"))                        # OPENAI_API_KEY

# Anthropic
Agent(AgentConfig(model="claude-3-5-haiku-20241022"))          # ANTHROPIC_API_KEY

# Groq (fast, free tier)
Agent(AgentConfig(model="groq/llama-3.1-8b-instant"))          # GROQ_API_KEY

# Ollama (local, no API key)
Agent(AgentConfig(model="ollama/qwen3:4b"))

# Google
Agent(AgentConfig(model="gemini/gemini-1.5-flash"))            # GEMINI_API_KEY

Fallback Routing

from litellm import Router
from cyclops import Agent, AgentConfig

router = Router(
    model_list=[
        {"model_name": "primary", "litellm_params": {"model": "gpt-4o-mini"}},
        {"model_name": "primary", "litellm_params": {"model": "groq/llama-3.1-8b-instant"}},
    ],
    fallbacks=[{"primary": ["groq/llama-3.1-8b-instant"]}],
    num_retries=2,
)

agent = Agent(AgentConfig(model="primary", router=router))

Why Cyclops?

Most agent frameworks add heavy abstractions, require specific clouds, or make it hard to see what's actually being sent to the LLM. Cyclops doesn't. The Agent class is ~400 lines. _history is a plain list of dicts in LiteLLM format. Every call goes straight to LiteLLM.

Cyclops LangChain smolagents
Lines to first agent 3 15+ 8
Any LiteLLM model yes partial yes
MCP native yes plugin only no
Streaming yes yes no
Structured output yes yes no
Cost tracking yes partial no
Abstraction thin thick medium

Examples

See the examples/ directory:

File What it shows
basic_agent.py Hello world, multi-turn
agent_with_tools.py Tool calling
streaming_example.py stream() and astream()
structured_output.py response_model with Pydantic
cost_tracking.py Tokens and cost
multi_turn_agent.py Conversation history
tool_loop_demo.py Multi-step tool chains
memory_persistence.py FileStorage
async_agent.py arun() and concurrent calls
different_llms.py Groq, Ollama, OpenAI, Together AI
router_fallback.py Automatic failover
mcp_server.py Expose tools via MCP
plugin_system.py Auto-discover toolkit packages

Development

git clone https://github.com/gopaljigaur/cyclops
cd cyclops
uv sync
uv run pre-commit install
uv run pytest

Contributing

Bug reports, feature requests, and pull requests are welcome. Open an issue first for large changes.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cyclops_ai-0.2.0.tar.gz (302.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cyclops_ai-0.2.0-py3-none-any.whl (22.1 kB view details)

Uploaded Python 3

File details

Details for the file cyclops_ai-0.2.0.tar.gz.

File metadata

  • Download URL: cyclops_ai-0.2.0.tar.gz
  • Upload date:
  • Size: 302.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for cyclops_ai-0.2.0.tar.gz
Algorithm Hash digest
SHA256 0de1c00e3bfcfb31a4dc7742be8bfd1e04f2f198d8b788e92edd7d2339658e71
MD5 312be89aa7c189a455f98a9bd8c143dd
BLAKE2b-256 d767cdab6c8b6cfce576cae6867f7c07fe32fc4b6cbc69f05fbdf55ad6ade6b7

See more details on using hashes here.

File details

Details for the file cyclops_ai-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: cyclops_ai-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 22.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for cyclops_ai-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 22cffbb9d18f0126e53001e26af3326aa8a9205bec0a4bd4c20785968f04a2ce
MD5 e2170bc703f65251bbfe06c174fa6483
BLAKE2b-256 244c43d1936b3b86ec338e4b6ced7ca5077fcd2b5aee7e6c85e93c12f42586ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page