mcp_arena
mcp_arena is an opinionated Python library for building MCP (Model Context Protocol) servers: 30+ ready-to-use presets you can stand up in one call, plus a thin bridge into a LangChain agent.
The headline feature is the MCP server — drop one in, run it, talk to it over stdio / SSE / HTTP:
# server.py
from mcp_arena.presents.github import GithubMCPServer
server = GithubMCPServer(
token="ghp_…", # or pull from $GITHUB_TOKEN
host="127.0.0.1",
port=8000,
transport="stdio", # stdio (default) | sse | http
debug=False,
)
if __name__ == "__main__":
server.run()
Any MCP client can now talk to it. The full preset list, constructor kwargs, and BaseMCPServer surface are in MCP_SERVERS_GUIDE.md. The LangChain-agent bridge is at the bottom of this README — read after you've understood the server side.
0.4.0 release: the old
ReflectionAgent/ReactAgent/PlanningAgent/ policies / memory / router stack is gone. The agent subsystem is now one function:make_mcp_agent. Migration guide inCHANGELOG.md.
Why mcp_arena?
- 30+ ready-to-run MCP server presets. Slack, GitHub, Notion, Gmail, PostgreSQL, Mongo, Redis, S3, browsers, video, audio, PDFs, QR codes, webscraping, and more — install one extra, import one class, call
server.run(). Any MCP-compatible client can talk to it. - Each preset is a real
BaseMCPServer. Tools register at construction, are exposed on_registered_toolsfor inspection, and the server can be started over stdio / SSE / HTTP in one call. - Lazy-loaded presets.
mcp_arena.presents.__init__AST-scans the directory; importing one preset doesn't pull in unrelated deps. - Drop-in extension. New MCP server? Write a
*Serversubclass inmcp_arena/presents/<name>.py; it's auto-discovered. - Optional LangChain bridge.
make_mcp_agent(llm, servers, ...)is the only function that wires the same server objects into a LangGraph agent. Forward anycreate_agentkwarg through**kwargs.
Install
⚠️
pip install mcp-arenaships three general-purpose presets in core —LocalOperationsMCPServer,GenericAPIMCPServer, andSMTPServer— so you can run a real MCP server with zero extra setup. Every other preset is gated behind an extra so you only pay for the third-party packages you actually need.
pip install mcp-arena # 3 core presets work out of the box
pip install "mcp-arena[github]" # + GitHub preset (PyGithub)
pip install "mcp-arena[github,slack]" # + several presets
pip install "mcp-arena[all]" # + every preset (~30 packages)
pip install "mcp-arena[agents]" # + LangChain bridge (langchain + MCP adapter)
What pip install mcp-arena does give you out of the box:
mcp_arena.mcp.server.BaseMCPServer— the base classmcp_arena.presentslazy loader — every preset class is importableLocalOperationsMCPServer— file / system / process tools (usespsutil+pyautogui)GenericAPIMCPServer— make any HTTP API call (useshttpx)SMTPServer— send email via any SMTP server (pure stdlib)mcp_arena.agent.make_mcp_agent/ToolRegistry/BaseToolmcp-arenaCLI (mcp-arena list,mcp-arena run <preset>)
What it does not install: anything else. If you try to instantiate a preset whose required dep isn't installed, you get a clear ImportError pointing at the exact install command — for example:
PyPDF2, fitz, pdfplumber and reportlab are required for this MCP server but are not installed.
Install it with: pip install "mcp-arena[pdf]"
Pick the right extra from INSTALLATION.md or MCP_SERVERS.md.
Python 3.12+. See INSTALLATION.md for the full extras table.
Run an MCP server
Every preset is a BaseMCPServer subclass. After construction, call server.run() to start serving.
Stdio (default — works with any local MCP client)
from mcp_arena.presents.github import GithubMCPServer
server = GithubMCPServer(token="ghp_…")
server.run() # transport="stdio"
Now point any MCP-compatible client at the process (e.g. Claude Desktop, Cursor, the mcp-arena CLI).
HTTP / SSE (for remote clients)
server = GithubMCPServer(token="ghp_…", transport="sse", host="0.0.0.0", port=8001)
server.run()
# -> listening on http://0.0.0.0:8001/sse
# or streamable-http:
server = GithubMCPServer(token="ghp_…", transport="http", port=8001)
server.run()
# -> listening on http://0.0.0.0:8001/mcp
| Transport | Endpoint | When to use |
|---|---|---|
stdio (default) |
in-process via stdin/stdout | local clients, the make_mcp_agent flow |
sse |
http://<host>:<port>/sse |
browser clients, streaming |
http |
http://<host>:<port>/mcp |
multi-process / networked setups |
streamable-http |
alias for http |
— |
Credentials: pass them in or pull from os.environ
# Inline:
server = GithubMCPServer(token="ghp_…")
# Env-var fallback (most presets read these for you):
# GITHUB_TOKEN, SLACK_BOT_TOKEN, NOTION_API_KEY, TWILIO_* …
server = GithubMCPServer() # picks up GITHUB_TOKEN
from mcp_arena import … calls python-dotenv.load_dotenv() for you, so a project-root .env is read automatically.
From the CLI
# List every preset mcp_arena knows about
mcp-arena list
# Show options for one preset
mcp-arena run github --help
# Start a server (stdio by default; pass --transport sse|http for network)
mcp-arena run github --token "$GITHUB_TOKEN"
mcp-arena run github --token "$GITHUB_TOKEN" --transport sse --host 0.0.0.0 --port 8001
Use a preset programmatically without the MCP protocol
You don't have to speak MCP — BaseMCPServer exposes the registered tools directly:
server = AudioMCPServer()
for tool_name in server.get_registered_tools():
print(tool_name)
# Or wrap them as plain Python callables:
from mcp_arena.wrapper import MCPAgentWrapper
for tool in MCPAgentWrapper(server).get_tools():
print(tool["function"]["name"])
See MCP_SERVERS_GUIDE.md for the full preset list, the BaseMCPServer constructor surface, and how to write your own.
Available presets
Every preset is one extra. Install what you need; nothing else gets pulled in.
Communication
slack, whatsapp, gmail, outlook, smtp, mail, notification
Dev platforms
github, gitlab, bitbucket
Productivity
notion, confluence, jira
Data & storage
postgres, mongo, redis, vectordb
Cloud / OS
aws (S3), cloudstorage, docker, local_operation, screencapture
Browser / web / media
browser, webscraping, generic_api, image, video, audio, pdf, qrcode, spreadsheet
See docs/MCP_SERVERS_GUIDE.md for the full table, kwargs, and transport notes.
Write your own preset
# mcp_arena/presents/greeter.py
from mcp_arena.mcp.server import BaseMCPServer
class GreeterMCPServer(BaseMCPServer):
def _register_tools(self):
@self.mcp_server.tool()
def greet(name: str) -> str:
"""Say hello."""
return f"Hello, {name}!"
# Now importable:
from mcp_arena.presents import GreeterMCPServer
The lazy loader in mcp_arena.presents AST-discovers every *Server class in the directory. Drop the file, import the class — done.
Architecture
┌─────────────────────────────────────────────────────────┐
│ mcp_arena.presents │
│ ~30 *MCPServer subclasses (auto-discovered) │
│ Browser · Slack · GH · Postgres · AWS · ... │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ BaseMCPServer.run() │
│ stdio / sse / http — talks to any MCP client │
└─────────────────────────────────────────────────────────┘
│
▼ (optional)
┌─────────────────────────────────────────────────────────┐
│ mcp_arena.agent │
│ • make_mcp_agent(llm, servers, ...) → LangGraph agent │
│ • ToolRegistry (register / keep / drop / rename / │
│ to_openai / get_callables) │
│ • BaseTool (subclass-this for non-MCP tools) │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ langchain.agents.create_agent → langgraph runnable │
│ (compiled via langchain-mcp-adapters.MultiServerMCP…) │
└─────────────────────────────────────────────────────────┘
The MCP-server layer is the product. The agent layer is a thin add-on that wraps the same server objects with a LangGraph.
Documents
- MCP Servers — quick reference: every preset, what extra to install, what env vars each reads, ready-to-copy install commands.
- MCP Servers Guide — every preset in detail;
BaseMCPServerconstructor surface; how to write your own. - Quick Start — 10-step walkthrough.
- Installation Guide — full extras table (one entry per preset / per group).
- Tools Guide —
ToolRegistry,BaseTool, custom MCP presets.
Agent & LangChain docs (read after the server-side docs above):
- Agent Guide —
make_mcp_agentreference, forwardedcreate_agentparams, troubleshooting. - LANGCHAIN_INTEGRATION.md — multi-server, transport choices, sync wrapper, migration from 0.3.x.
- tutorial.md — end-to-end "Jarvis" build (local-fs + GitHub agent).
- CHANGELOG.md — version history & migration guide.
Bonus: wire a server to a LangChain agent
If you already have a LangChain workflow and want to give it access to MCP tools, make_mcp_agent is the one-line bridge:
import asyncio, os
from langchain_openai import ChatOpenAI
from mcp_arena.agent import make_mcp_agent
from mcp_arena.presents.github import GithubMCPServer
from mcp_arena.presents.slack import SlackMCPServer
async def main():
agent = await make_mcp_agent(
ChatOpenAI(model="gpt-4o"),
[
GithubMCPServer(token=os.environ["GITHUB_TOKEN"]),
SlackMCPServer(token=os.environ["SLACK_BOT_TOKEN"]),
],
system_prompt="You can search GitHub and post to Slack.",
name="devops_bot",
)
out = await agent.ainvoke({
"messages": [{
"role": "user",
"content": "Find the top-3 starred repos in my org and post links to #general.",
}],
})
print(out["messages"][-1].content)
asyncio.run(main())
make_mcp_agent handles the connection between MCP-server transports and the LangChain MultiServerMCPClient, then forwards to langchain.agents.create_agent. See LANGCHAIN_INTEGRATION.md.
Filter tools before they reach the model
from mcp_arena.agent import ToolRegistry, make_mcp_agent
reg = ToolRegistry().register_server(slack_server)
print("Available:", reg.names()) # ['chat_postMessage', 'list_channels', ...]
reg.keep("chat_postMessage", "list_channels")
agent = await make_mcp_agent(
ChatOpenAI(model="gpt-4o"),
[slack_server],
names=reg.names(), # only these tools become agent tools
)
Add a custom (non-MCP) tool
from mcp_arena.agent import BaseTool, make_mcp_agent
class ShoutTool(BaseTool):
def __init__(self):
super().__init__(name="shout", description="Uppercase a string")
def execute(self, s: str) -> str:
return s.upper()
agent = await make_mcp_agent(
ChatOpenAI(model="gpt-4o"),
[slack_server],
extra_tools=[ShoutTool()],
)
Contributing
git clone https://github.com/SatyamSingh8306/mcp_arena
cd mcp_arena
pip install -e ".[complete]"
pytest
black .
ruff check .
mypy mcp_arena
Priority areas: new presets, bug fixes, doc accuracy.
Requirements
- Python 3.12+
- An MCP-compatible client to actually consume the servers (or use
make_mcp_agentto wire one into LangChain) - Optional: your LLM provider's
langchain-*adapter for the agent flow
License
MIT — see LICENSE.
Links
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_arena-0.4.1.tar.gz.
File metadata
- Download URL: mcp_arena-0.4.1.tar.gz
- Upload date:
- Size: 184.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0f2876a960de2923a3605a715f5daad1f4fdbbb18f69ac8561706742f8635d2
|
|
| MD5 |
8bebac5c1322648023898eed592841c1
|
|
| BLAKE2b-256 |
79ecc2cb6a4a85247789b803aa529a65f81c4a7cfa148b9a230c7f57e8f55634
|
File details
Details for the file mcp_arena-0.4.1-py3-none-any.whl.
File metadata
- Download URL: mcp_arena-0.4.1-py3-none-any.whl
- Upload date:
- Size: 167.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ac2e222e778ca2fd814b307c03d2087d8b58e1a56dbcd039beba1bcb7dacf52
|
|
| MD5 |
d5e46ec4d4241d2bec2a7d31e44e66ed
|
|
| BLAKE2b-256 |
4e3b6bbe17a094017af7383bea4ee30d1561b814f5d482f3a1f9337b6d6552ce
|