Metadata-Version: 2.4
Name: mcp_arena
Version: 0.4.0
Summary: An opinionated Python library for building MCP (Model Context Protocol) servers with presets and a one-line bridge to LangChain agents.
Project-URL: Homepage, https://github.com/SatyamSingh8306/mcp_arena
Project-URL: Repository, https://github.com/SatyamSingh8306/mcp_arena
Project-URL: Issues, https://github.com/SatyamSingh8306/mcp_arena/issues
Author-email: Satyam Singh <satyamsingh7734@gmail.com>
License: MIT
License-File: LICENSE
Keywords: agents,ai,llm,mcp,model-context-protocol
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.12
Requires-Dist: mcp<2.0,>=1.25
Requires-Dist: psutil<8.0,>=7.2
Requires-Dist: pydantic<3.0,>=2.0
Requires-Dist: python-dotenv<2.0,>=1.0
Requires-Dist: rich>=13.0.0
Requires-Dist: typer>=0.9.0
Requires-Dist: typing-extensions<5.0,>=4.8
Provides-Extra: agents
Requires-Dist: langchain-mcp-adapters<1.0,>=0.1; extra == 'agents'
Requires-Dist: langchain<2.0,>=1.0; extra == 'agents'
Provides-Extra: all
Requires-Dist: atlassian-python-api<5.0,>=4.0; extra == 'all'
Requires-Dist: beautifulsoup4>=4.12; extra == 'all'
Requires-Dist: boto3>=1.42; extra == 'all'
Requires-Dist: chromadb<2.0,>=1.3.5; extra == 'all'
Requires-Dist: docker<8.0,>=7.1; extra == 'all'
Requires-Dist: google-api-python-client<3.0,>=2.130; extra == 'all'
Requires-Dist: google-auth-httplib2<1.0,>=0.1.0; extra == 'all'
Requires-Dist: google-auth-oauthlib<2.0,>=1.2; extra == 'all'
Requires-Dist: google-auth<3.0,>=2.29; extra == 'all'
Requires-Dist: google-cloud-storage>=2.16; extra == 'all'
Requires-Dist: httpx>=0.27; extra == 'all'
Requires-Dist: kubernetes<35.0,>=28.1; extra == 'all'
Requires-Dist: langchain-mcp-adapters<1.0,>=0.1; extra == 'all'
Requires-Dist: langchain<2.0,>=1.0; extra == 'all'
Requires-Dist: librosa>=0.10; extra == 'all'
Requires-Dist: moviepy>=1.0.3; extra == 'all'
Requires-Dist: msal<2.0,>=1.28; extra == 'all'
Requires-Dist: numpy>=1.24; extra == 'all'
Requires-Dist: opencv-python>=4.8; extra == 'all'
Requires-Dist: openpyxl>=3.1; extra == 'all'
Requires-Dist: pandas>=2.2; extra == 'all'
Requires-Dist: pdfplumber>=0.10; extra == 'all'
Requires-Dist: pillow>=10.0; extra == 'all'
Requires-Dist: playwright>=1.45; extra == 'all'
Requires-Dist: psutil<8.0,>=7.2; extra == 'all'
Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == 'all'
Requires-Dist: pyautogui<1.0,>=0.9; extra == 'all'
Requires-Dist: pyautogui>=0.9; extra == 'all'
Requires-Dist: pydub>=0.25; extra == 'all'
Requires-Dist: pygithub<3.0,>=2.8; extra == 'all'
Requires-Dist: pymongo<5.0,>=4.6; extra == 'all'
Requires-Dist: pymupdf>=1.24; extra == 'all'
Requires-Dist: pypdf2>=3.0; extra == 'all'
Requires-Dist: python-gitlab<8.0,>=7.0; extra == 'all'
Requires-Dist: qrcode[pil]>=7.4; extra == 'all'
Requires-Dist: redis<8.0,>=5.0; extra == 'all'
Requires-Dist: reportlab>=4.0; extra == 'all'
Requires-Dist: requests>=2.31; extra == 'all'
Requires-Dist: selenium>=4.21; extra == 'all'
Requires-Dist: sentence-transformers<6.0,>=5.2; extra == 'all'
Requires-Dist: slack-sdk<4.0,>=3.27; extra == 'all'
Requires-Dist: twilio<10.0,>=9.0; extra == 'all'
Provides-Extra: audio
Requires-Dist: librosa>=0.10; extra == 'audio'
Requires-Dist: numpy>=1.24; extra == 'audio'
Requires-Dist: pydub>=0.25; extra == 'audio'
Provides-Extra: bitbucket
Requires-Dist: atlassian-python-api<5.0,>=4.0; extra == 'bitbucket'
Provides-Extra: browser
Requires-Dist: opencv-python>=4.8; extra == 'browser'
Requires-Dist: pillow>=10.0; extra == 'browser'
Requires-Dist: playwright>=1.45; extra == 'browser'
Provides-Extra: cloudstorage
Requires-Dist: boto3>=1.42; extra == 'cloudstorage'
Requires-Dist: google-cloud-storage>=2.16; extra == 'cloudstorage'
Provides-Extra: communication
Requires-Dist: google-api-python-client<3.0,>=2.130; extra == 'communication'
Requires-Dist: google-auth-httplib2<1.0,>=0.1.0; extra == 'communication'
Requires-Dist: google-auth-oauthlib<2.0,>=1.2; extra == 'communication'
Requires-Dist: google-auth<3.0,>=2.29; extra == 'communication'
Requires-Dist: msal<2.0,>=1.28; extra == 'communication'
Requires-Dist: slack-sdk<4.0,>=3.27; extra == 'communication'
Requires-Dist: twilio<10.0,>=9.0; extra == 'communication'
Provides-Extra: complete
Requires-Dist: atlassian-python-api<5.0,>=4.0; extra == 'complete'
Requires-Dist: beautifulsoup4>=4.12; extra == 'complete'
Requires-Dist: black<26.0,>=24.0; extra == 'complete'
Requires-Dist: boto3>=1.42; extra == 'complete'
Requires-Dist: chromadb<2.0,>=1.3.5; extra == 'complete'
Requires-Dist: docker<8.0,>=7.1; extra == 'complete'
Requires-Dist: google-api-python-client<3.0,>=2.130; extra == 'complete'
Requires-Dist: google-auth-httplib2<1.0,>=0.1.0; extra == 'complete'
Requires-Dist: google-auth-oauthlib<2.0,>=1.2; extra == 'complete'
Requires-Dist: google-auth<3.0,>=2.29; extra == 'complete'
Requires-Dist: google-cloud-storage>=2.16; extra == 'complete'
Requires-Dist: httpx>=0.27; extra == 'complete'
Requires-Dist: isort<6.0,>=5.12; extra == 'complete'
Requires-Dist: kubernetes<35.0,>=28.1; extra == 'complete'
Requires-Dist: langchain-mcp-adapters<1.0,>=0.1; extra == 'complete'
Requires-Dist: langchain<2.0,>=1.0; extra == 'complete'
Requires-Dist: librosa>=0.10; extra == 'complete'
Requires-Dist: moviepy>=1.0.3; extra == 'complete'
Requires-Dist: msal<2.0,>=1.28; extra == 'complete'
Requires-Dist: mypy<2.0,>=1.7; extra == 'complete'
Requires-Dist: numpy>=1.24; extra == 'complete'
Requires-Dist: opencv-python>=4.8; extra == 'complete'
Requires-Dist: openpyxl>=3.1; extra == 'complete'
Requires-Dist: pandas>=2.2; extra == 'complete'
Requires-Dist: pdfplumber>=0.10; extra == 'complete'
Requires-Dist: pillow>=10.0; extra == 'complete'
Requires-Dist: playwright>=1.45; extra == 'complete'
Requires-Dist: pre-commit<4.0,>=3.5; extra == 'complete'
Requires-Dist: psutil<8.0,>=7.2; extra == 'complete'
Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == 'complete'
Requires-Dist: pyautogui<1.0,>=0.9; extra == 'complete'
Requires-Dist: pyautogui>=0.9; extra == 'complete'
Requires-Dist: pydub>=0.25; extra == 'complete'
Requires-Dist: pygithub<3.0,>=2.8; extra == 'complete'
Requires-Dist: pymongo<5.0,>=4.6; extra == 'complete'
Requires-Dist: pymupdf>=1.24; extra == 'complete'
Requires-Dist: pypdf2>=3.0; extra == 'complete'
Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == 'complete'
Requires-Dist: pytest<9.0,>=8.0; extra == 'complete'
Requires-Dist: python-gitlab<8.0,>=7.0; extra == 'complete'
Requires-Dist: qrcode[pil]>=7.4; extra == 'complete'
Requires-Dist: redis<8.0,>=5.0; extra == 'complete'
Requires-Dist: reportlab>=4.0; extra == 'complete'
Requires-Dist: requests>=2.31; extra == 'complete'
Requires-Dist: ruff<1.0,>=0.12; extra == 'complete'
Requires-Dist: selenium>=4.21; extra == 'complete'
Requires-Dist: sentence-transformers<6.0,>=5.2; extra == 'complete'
Requires-Dist: slack-sdk<4.0,>=3.27; extra == 'complete'
Requires-Dist: twilio<10.0,>=9.0; extra == 'complete'
Provides-Extra: dev
Requires-Dist: black<26.0,>=24.0; extra == 'dev'
Requires-Dist: isort<6.0,>=5.12; extra == 'dev'
Requires-Dist: mypy<2.0,>=1.7; extra == 'dev'
Requires-Dist: pre-commit<4.0,>=3.5; extra == 'dev'
Requires-Dist: pytest-asyncio<1.0,>=0.23; extra == 'dev'
Requires-Dist: pytest<9.0,>=8.0; extra == 'dev'
Requires-Dist: ruff<1.0,>=0.12; extra == 'dev'
Provides-Extra: docker
Requires-Dist: docker<8.0,>=7.1; extra == 'docker'
Provides-Extra: email
Requires-Dist: google-api-python-client<3.0,>=2.130; extra == 'email'
Requires-Dist: google-auth-httplib2<1.0,>=0.1.0; extra == 'email'
Requires-Dist: google-auth-oauthlib<2.0,>=1.2; extra == 'email'
Requires-Dist: google-auth<3.0,>=2.29; extra == 'email'
Requires-Dist: msal<2.0,>=1.28; extra == 'email'
Provides-Extra: generic-api
Requires-Dist: httpx>=0.27; extra == 'generic-api'
Provides-Extra: github
Requires-Dist: pygithub<3.0,>=2.8; extra == 'github'
Provides-Extra: gitlab
Requires-Dist: python-gitlab<8.0,>=7.0; extra == 'gitlab'
Provides-Extra: gmail
Requires-Dist: google-api-python-client<3.0,>=2.130; extra == 'gmail'
Requires-Dist: google-auth-httplib2<1.0,>=0.1.0; extra == 'gmail'
Requires-Dist: google-auth-oauthlib<2.0,>=1.2; extra == 'gmail'
Requires-Dist: google-auth<3.0,>=2.29; extra == 'gmail'
Provides-Extra: image
Requires-Dist: opencv-python>=4.8; extra == 'image'
Requires-Dist: pillow>=10.0; extra == 'image'
Provides-Extra: kubernetes
Requires-Dist: kubernetes<35.0,>=28.1; extra == 'kubernetes'
Provides-Extra: local-operation
Requires-Dist: psutil<8.0,>=7.2; extra == 'local-operation'
Requires-Dist: pyautogui<1.0,>=0.9; extra == 'local-operation'
Provides-Extra: mail
Requires-Dist: google-api-python-client<3.0,>=2.130; extra == 'mail'
Requires-Dist: google-auth-httplib2<1.0,>=0.1.0; extra == 'mail'
Requires-Dist: google-auth-oauthlib<2.0,>=1.2; extra == 'mail'
Requires-Dist: google-auth<3.0,>=2.29; extra == 'mail'
Requires-Dist: msal<2.0,>=1.28; extra == 'mail'
Provides-Extra: messaging
Requires-Dist: slack-sdk<4.0,>=3.27; extra == 'messaging'
Requires-Dist: twilio<10.0,>=9.0; extra == 'messaging'
Provides-Extra: mongodb
Requires-Dist: pymongo<5.0,>=4.6; extra == 'mongodb'
Provides-Extra: notification
Requires-Dist: google-api-python-client<3.0,>=2.130; extra == 'notification'
Requires-Dist: google-auth-httplib2<1.0,>=0.1.0; extra == 'notification'
Requires-Dist: google-auth-oauthlib<2.0,>=1.2; extra == 'notification'
Requires-Dist: google-auth<3.0,>=2.29; extra == 'notification'
Requires-Dist: msal<2.0,>=1.28; extra == 'notification'
Requires-Dist: slack-sdk<4.0,>=3.27; extra == 'notification'
Requires-Dist: twilio<10.0,>=9.0; extra == 'notification'
Provides-Extra: outlook
Requires-Dist: msal<2.0,>=1.28; extra == 'outlook'
Provides-Extra: pdf
Requires-Dist: pdfplumber>=0.10; extra == 'pdf'
Requires-Dist: pymupdf>=1.24; extra == 'pdf'
Requires-Dist: pypdf2>=3.0; extra == 'pdf'
Requires-Dist: reportlab>=4.0; extra == 'pdf'
Provides-Extra: postgres
Requires-Dist: psycopg2-binary<3.0,>=2.9; extra == 'postgres'
Provides-Extra: qrcode
Requires-Dist: pillow>=10.0; extra == 'qrcode'
Requires-Dist: qrcode[pil]>=7.4; extra == 'qrcode'
Provides-Extra: redis
Requires-Dist: redis<8.0,>=5.0; extra == 'redis'
Provides-Extra: screencapture
Requires-Dist: pyautogui>=0.9; extra == 'screencapture'
Provides-Extra: slack
Requires-Dist: slack-sdk<4.0,>=3.27; extra == 'slack'
Provides-Extra: spreadsheet
Requires-Dist: openpyxl>=3.1; extra == 'spreadsheet'
Requires-Dist: pandas>=2.2; extra == 'spreadsheet'
Provides-Extra: vectordb
Requires-Dist: chromadb<2.0,>=1.3.5; extra == 'vectordb'
Requires-Dist: sentence-transformers<6.0,>=5.2; extra == 'vectordb'
Provides-Extra: video
Requires-Dist: moviepy>=1.0.3; extra == 'video'
Requires-Dist: numpy>=1.24; extra == 'video'
Provides-Extra: webscraping
Requires-Dist: beautifulsoup4>=4.12; extra == 'webscraping'
Requires-Dist: requests>=2.31; extra == 'webscraping'
Requires-Dist: selenium>=4.21; extra == 'webscraping'
Provides-Extra: whatsapp
Requires-Dist: twilio<10.0,>=9.0; extra == 'whatsapp'
Description-Content-Type: text/markdown

# mcp_arena

[![PyPI version](https://badge.fury.io/py/mcp-arena.svg)](https://badge.fury.io/py/mcp-arena)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**`mcp_arena`** is an opinionated Python library for building **MCP (Model Context Protocol) servers**: 30+ ready-to-use presets plus a one-line bridge into a LangChain agent.

```python
import asyncio
from langchain_openai import ChatOpenAI
from mcp_arena.agent import make_mcp_agent
from mcp_arena.presents.github import GithubMCPServer

async def main():
    agent = await make_mcp_agent(
        ChatOpenAI(model="gpt-4o"),
        [GithubMCPServer(token="ghp_…")],
        system_prompt="You can search GitHub.",
    )

asyncio.run(main())
```

> **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 in [`CHANGELOG.md`](CHANGELOG.md).

## Why mcp_arena?

- **30+ presets** covering Slack, GitHub, Notion, Gmail, PostgreSQL, Mongo, Redis, S3, browsers, video, audio, PDFs, QR codes, webscraping, and more — drop the file you need, install the matching extra, go.
- **One function to an agent.** Pass any combination of `BaseMCPServer` instances to `make_mcp_agent(llm, servers, ...)` and you get the exact same shape `langchain.agents.create_agent` returns — a compiled LangGraph. Forward any `create_agent` kwarg through `**kwargs`.
- **Optional tool filtering.** Don't overload the model with 40 tools — `ToolRegistry.register_server(s).keep("a", "b")` then pass `names=reg.names()`.
- **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 `*Server` subclass in `mcp_arena/presents/<name>.py`; it's auto-discovered.

## Install

```bash
pip install mcp-arena                       # core
pip install "mcp-arena[github,slack]"       # specific presets
pip install "mcp-arena[all]"                # all presets
pip install "mcp-arena[agents]"             # + langchain + MCP adapter
```

Python 3.12+. See [INSTALLATION.md](docs/INSTALLATION.md) for the full extras table.

## Use a preset

```python
from mcp_arena.presents.audio import AudioMCPServer

server = AudioMCPServer()              # reads credentials from env if needed
server.run()                           # stdio by default
```

Switch transports:

```python
server = AudioMCPServer(transport="sse", host="0.0.0.0", port=8001)
server.run()
```

## Build an agent from your servers

```python
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())
```

## Filter tools before they reach the model

```python
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

```python
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()],
)
```

## Available presets

### 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`](docs/MCP_SERVERS_GUIDE.md) for the full table, kwargs, and transport notes.

## Write your own preset

```python
# 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.

## Architecture

```
┌─────────────────────────────────────────────────────────┐
│                 mcp_arena.presents                      │
│  ~30 *MCPServer subclasses (auto-discovered)           │
│  Browser · Slack · GH · Postgres · AWS · ...            │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                   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…) │
└─────────────────────────────────────────────────────────┘
```

## Documents

- [**AGENT_GUIDE.md**](docs/AGENT_GUIDE.md) — `make_mcp_agent` reference, forwarded `create_agent` params, `ToolRegistry`
- [**LANGCHAIN_INTEGRATION.md**](docs/LANGCHAIN_INTEGRATION.md) — multi-server, transport choices, sync wrapper
- [**MCP_SERVERS_GUIDE.md**](docs/MCP_SERVERS_GUIDE.md) — every preset + custom-server instructions
- [**QUICKSTART.md**](docs/QUICKSTART.md) — 10-step walkthrough
- [**INSTALLATION.md**](docs/INSTALLATION.md) — extras reference
- [**TOOLS_GUIDE.md**](docs/TOOLS_GUIDE.md) — `ToolRegistry` / `BaseTool` / custom presets
- [**tutorial.md**](docs/tutorial.md) — end-to-end "Jarvis" build
- [**CHANGELOG.md**](CHANGELOG.md) — version history & migration guide

## CLI

```bash
mcp-arena list                 # every preset
mcp-arena run github --help    # preset-specific options
mcp-arena run github --token "$GITHUB_TOKEN"
```

## Contributing

```bash
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_agent` to wire one into LangChain)
- Optional: your LLM provider's `langchain-*` adapter for the agent flow

## License

MIT — see [LICENSE](LICENSE).

## Links

- [GitHub repository](https://github.com/SatyamSingh8306/mcp_arena)
- [Issue tracker](https://github.com/SatyamSingh8306/mcp_arena/issues)
- [PyPI](https://pypi.org/project/mcp-arena/)
- [CHANGELOG](CHANGELOG.md)
