Metadata-Version: 2.4
Name: isage-mcp
Version: 0.1.0.0
Summary: SAGE MCP Aggregator — unified MCP server for all SAGE Zoo packages
Author-email: IntelliStream Team <shuhao_zhang@hust.edu.cn>
License-Expression: MIT
Project-URL: Homepage, https://github.com/intellistream/sage-mcp
Project-URL: Repository, https://github.com/intellistream/sage-mcp
Project-URL: Issues, https://github.com/intellistream/sage-mcp/issues
Keywords: ai,sage,mcp,model-context-protocol,agents,tools,claude,copilot
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: ==3.12.*
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: mcp>=1.0.0
Provides-Extra: tools
Requires-Dist: isage-tools[mcp]>=0.1.0; extra == "tools"
Provides-Extra: rag
Requires-Dist: isage-rag[mcp]>=0.1.0; extra == "rag"
Provides-Extra: agentic
Requires-Dist: isage-agentic[mcp]>=0.1.0; extra == "agentic"
Provides-Extra: all
Requires-Dist: isage-mcp[tools]; extra == "all"
Provides-Extra: dev
Requires-Dist: isage-mcp[all]; extra == "dev"
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: ruff==0.15.4; extra == "dev"
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
Requires-Dist: isage-pypi-publisher>=0.2.1.0; extra == "dev"
Dynamic: license-file

# isage-mcp — SAGE Unified MCP Server

[![PyPI](https://img.shields.io/pypi/v/isage-mcp)](https://pypi.org/project/isage-mcp/)
[![Python](https://img.shields.io/pypi/pyversions/isage-mcp)](https://pypi.org/project/isage-mcp/)

One MCP server for all SAGE Zoo packages.  Install once, configure once — get
web search, RAG, agentic tools, and more in any MCP-compatible AI client.

## Quick Start

```bash
# Install with all available zoo packages
pip install 'isage-mcp[all]'

# Start the server (stdio — for Claude Desktop)
sage-mcp

# Or HTTP/SSE — for VS Code Copilot, Cursor, etc.
sage-mcp --transport sse --port 9000
```

See which zoo packages are loaded:

```bash
sage-mcp --list-plugins
# Installed SAGE MCP plugins (1):
#   • sage_tools
```

## Client Configuration

### Claude Desktop

```json
{
  "mcpServers": {
    "sage": {
      "command": "sage-mcp"
    }
  }
}
```

### VS Code Copilot (settings.json)

```json
"mcp": {
  "servers": {
    "sage": {
      "type": "sse",
      "url": "http://localhost:9000/sse"
    }
  }
}
```

### Cursor / OpenHands / other MCP clients

Same pattern — use `sage-mcp` as the command (stdio) or point at the SSE URL.

## Available Zoo Packages

| Package | Install | Tools exposed |
|---------|---------|---------------|
| `isage-tools` | `pip install 'isage-tools[mcp]'` | `duckduckgo_search`, `arxiv_search`, `arxiv_paper_search`, `url_text_extract`, `nature_news_fetch` |
| `isage-rag` | `pip install 'isage-rag[mcp]'` | `rag_search`, `index_document` *(coming soon)* |
| `isage-agentic` | `pip install 'isage-agentic[mcp]'` | `run_agent`, `run_react_loop` *(coming soon)* |

## How the Plugin System Works

`sage-mcp` supports **two registration modes**.  New packages should use Mode 1.

### Mode 1 — Auto (recommended, zero MCP code needed)

Add ONE line to `pyproject.toml` pointing at your tools module:

```toml
[project.entry-points."sage.mcp.modules"]
my_package = "my_package.tools"   # ← that's it
```

`sage-mcp` scans the module for all `BaseTool` subclasses and auto-wraps each
one using the existing `tool_name`, `tool_description`, and `execute()` signature.
**No MCP-specific code is needed in the package at all.**

### Mode 2 — Explicit (for hand-crafted descriptions / advanced control)

Write a `register_tools(mcp)` function and declare it:

```toml
[project.entry-points."sage.mcp.tools"]
my_package = "my_package.mcp_server:register_tools"
```

```python
def register_tools(mcp):
    @mcp.tool()
    async def my_tool(query: str, max_results: int = 5) -> list:
        """Custom hand-written description shown to the AI."""
        ...
```

If a package appears in both groups, explicit takes precedence (no double-registration).

### What auto-wrapping does

For each `BaseTool` subclass found:
- `tool_name` → MCP tool name (normalised to `snake_case`)
- `tool_description` → MCP tool description shown to the AI
- `execute(query: str, max_results: int = 5)` → MCP parameter schema (type hints + defaults preserved)
- Async `execute` → async MCP tool; sync → sync tool

## Architecture

```
sage-mcp (aggregator)
  │
  ├── sage.mcp.tools  (explicit — package writes register_tools)
  │      └── sage_tools → sage.tools.mcp_server:register_tools
  │
  └── sage.mcp.modules  (auto — no MCP code in package)
         └── sage_rag    → scan "sage.rag" for BaseTool subclasses
             sage_agentic → scan "sage.agentic" for BaseTool subclasses
             ...
```

If a package appears in **both** groups, the explicit path wins (no double-registration).

## License

MIT — see [LICENSE](LICENSE).
