Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,15 @@ INGESTION__CHUNK_SIZE=5000

# Files ignored by the indexer.
# INGESTION__GITHUB_IGNORED_FILES={'uv.lock', 'poetry.lock', 'package-lock.json', 'Pipfile.lock', 'yarn.lock'}

# ==============================================================================
# MCP (MODEL CONTEXT PROTOCOL) SERVERS
# ==============================================================================
# MCP (Model Context Protocol) servers (JSON string)
# Example (stdio):
# MCP__SERVERS='{"filesystem":{"command":"npx","args":["-y","@modelcontextprotocol/server-filesystem","/path"]}}'

# Example (remote SSE):
# MCP__SERVERS='{"api":{"url":"http://localhost:3000/sse","transport":"sse"}}'

# Optional per server: headers, timeout, tool_filter, enabled, env
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SDK for building **verifiable AI Agents** on Flare using Confidential Space Trus

- **Verifiable execution**: Run logic inside Intel TDX TEEs via [GCP Confidential Space](https://cloud.google.com/confidential-computing/confidential-space/docs/confidential-space-overview).
- **Multi-agent consensus**: Majority/Tournament/[Consensus Learning](https://arxiv.org/abs/2402.16157) via [Google Agent2Agent](https://github.com/a2aproject/A2A) protocol.
- **Agent framework**: Built on [Google ADK](https://google.github.io/adk-docs/) with tool-calling, orchestration and evaluation.
- **Agent framework**: Built on [Google ADK](https://google.github.io/adk-docs/) with tool-calling, orchestration and evaluation. Supports [MCP](https://modelcontextprotocol.io/) for custom tool integration.
- **Flare integration**: [FTSO](https://dev.flare.network/ftso/overview), [FDC](https://dev.flare.network/fdc/overview), [FAssets](https://dev.flare.network/fassets/overview) + ecosystem dApps ([Sceptre](https://sceptre.fi), [SparkDEX](https://sparkdex.ai), ...).
- **Social connectors**: X, Telegram, Farcaster.

Expand All @@ -29,6 +29,7 @@ flowchart TD
subgraph AgentFramework["Agent Framework"]
B["Google ADK"]
B --o LLM["Gemini<br>GPT<br>Grok<br>+200 models"]
B --o MCP["MCP Servers<br>(Custom Tools)"]
end

%% VectorRAG Engine subgraph
Expand Down Expand Up @@ -130,7 +131,7 @@ docker run --rm -it \
fai-script-pdf
```

Available `EXTRAS`: `pdf`, `rag`, `a2a`, `ftso`, `da`, `fassets`, `social`, `tee`, `wallet`, `ingestion`
Available `EXTRAS`: `pdf`, `rag`, `a2a`, `ftso`, `da`, `fassets`, `social`, `tee`, `wallet`, `ingestion`, `mcp`

See [Docker Scripts Guide](docs/docker_scripts_guide.md) for detailed usage instructions.

Expand Down
258 changes: 258 additions & 0 deletions docs/mcp_readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# MCP (Model Context Protocol) Server Integration

This documentation provides a comprehensive guide to the MCP server integration for Flare AI Kit, enabling AI agents to connect to external tools and services via the Model Context Protocol.

## Quick Start

### 1. Installation

The MCP integration requires additional dependencies:

```bash
# Install with MCP support
uv sync --extra mcp

# Or add the mcp extra to your dependencies
uv add "flare-ai-kit[mcp]"
```

### 2. Configuration

Configure MCP servers via the `MCP__SERVERS` environment variable:

```bash
# .env file
MCP__SERVERS='{"filesystem": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]}}'
```

## Server Configuration

### Stdio Servers (Local Processes)

Stdio servers run as local processes and communicate via stdin/stdout

**Environment Variable Format:**

```bash
MCP__SERVERS='{"filesystem": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]}}'
```

### SSE Servers (Remote - Server-Sent Events)

SSE servers connect to remote endpoints using Server-Sent Events

**Environment Variable Format:**

```bash
MCP__SERVERS='{"api": {"url": "http://localhost:3000/sse", "transport": "sse", "headers": {"Authorization": "Bearer token"}}}'
```

### HTTP Servers (Remote - Streamable HTTP)

HTTP servers connect using the streamable HTTP transport

**Environment Variable Format:**

```bash
MCP__SERVERS='{"remote": {"url": "https://api.example.com/mcp", "transport": "http"}}'
```

### Mixed Configuration Example

Configure multiple servers of different types:

```bash
MCP__SERVERS='{
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
},
"git": {
"command": "python",
"args": ["-m", "mcp_git_server"],
"env": {"GIT_AUTHOR_NAME": "AI Agent"}
},
"external-api": {
"url": "https://api.example.com/mcp",
"transport": "http",
"headers": {"X-API-Key": "secret"}
},
"streaming": {
"url": "http://localhost:3000/sse",
"transport": "sse"
}
}'
```

## Configuration Options

### MCPServerConfig Fields

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `command` | `str` | `None` | Command to run (stdio servers) |
| `args` | `list[str]` | `[]` | Arguments for the command |
| `env` | `dict[str, str]` | `{}` | Environment variables for the process |
| `url` | `str` | `None` | URL for remote servers (SSE/HTTP) |
| `transport` | `"stdio"\|"sse"\|"http"` | `"stdio"` | Transport type |
| `headers` | `dict[str, str]` | `{}` | HTTP headers for authentication |
| `timeout` | `float` | `30.0` | Connection timeout in seconds |
| `tool_filter` | `list[str]` | `None` | Tools to expose (`None` = all) |
| `enabled` | `bool` | `True` | Whether the server is enabled |

### Tool Filtering

Limit which tools are exposed from a server:

```python
config = MCPServerConfig(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "/path"],
tool_filter=["read_file", "list_directory"], # Only expose these tools
)
```

```bash
MCP__SERVERS='{"fs": {"command": "npx", "args": ["-y", "server"], "tool_filter": ["read_file", "write_file"]}}'
```

### Disabling Servers

Temporarily disable a server without removing its configuration:

```python
config = MCPServerConfig(
command="npx",
args=["-y", "some-server"],
enabled=False, # Server won't be initialized
)
```

## Using with ADK Agents

The MCP toolsets integrate seamlessly with Google ADK agents:

```python
from flare_ai_kit import FlareAIKit
from google.adk import Agent
from google.genai import types

async def create_agent_with_mcp():
kit = FlareAIKit()

# Get MCP toolsets
mcp_toolsets = kit.mcp_tools

# Combine with other tools
all_tools = [
*mcp_toolsets, # MCP tools
# ... your other ADK tools
]

# Create ADK agent with MCP tools
agent = Agent(
model="gemini-2.5-flash",
name="mcp-enabled-agent",
instruction="You have access to filesystem and other MCP tools.",
tools=all_tools,
)

return agent
```

## MCPManager API

### Getting Toolsets

```python
from flare_ai_kit.mcp.manager import MCPManager
from flare_ai_kit.mcp.settings import MCPSettings

# Create manager
settings = MCPSettings() # Loads from environment
manager = MCPManager(settings)

# Get all toolsets (sync)
toolsets = manager.get_toolsets_sync()

# Get all toolsets (async)
toolsets = await manager.get_toolsets()

# Get specific toolset by name
fs_toolset = manager.get_toolset("filesystem")
```

### Checking Configuration

```python
# Check if any servers are configured
if manager.has_servers:
print("MCP servers configured")

# Get list of server names
print(f"Servers: {manager.server_names}")
```

### Error Handling

```python
# Get toolsets (errors are captured, not raised)
toolsets = manager.get_toolsets_sync()

# Check for initialization errors
errors = manager.get_errors()
for server_name, error in errors.items():
print(f"Server {server_name} failed: {error}")
```

### Cleanup

```python
# Close all MCP connections
await manager.close()
```

## Error Handling

### ImportError for Missing Dependencies

```python
try:
toolsets = manager.get_toolsets_sync()
except ImportError as e:
print("MCP dependencies not installed. Run: pip install flare-ai-kit[mcp]")
```

### Server Configuration Errors

```python
from flare_ai_kit.mcp.settings import MCPServerConfig

# Invalid: both command and url specified
try:
config = MCPServerConfig(command="echo", url="http://localhost:3000")
except ValueError as e:
print(f"Configuration error: {e}")

# Invalid: neither command nor url specified
try:
config = MCPServerConfig()
except ValueError as e:
print(f"Configuration error: {e}")
```

### Connection Errors

```python
manager = MCPManager(settings)
toolsets = manager.get_toolsets_sync()

# Check which servers failed to initialize
errors = manager.get_errors()
if errors:
for name, error in errors.items():
print(f"Server '{name}' failed: {error}")

# Successfully initialized servers still work
print(f"Working servers: {len(toolsets)}")
```
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ wallet = [
"eth-account>=0.13.7",
"pyjwt>=2.10.1",
]
mcp = [
# MCP SDK for Model Context Protocol integration
# Note: google-adk provides McpToolset, but mcp package needed for StdioServerParameters
"mcp>=1.0.0",
]

[build-system]
requires = ["hatchling"]
Expand Down
2 changes: 2 additions & 0 deletions src/flare_ai_kit/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from flare_ai_kit.agent.settings import AgentSettings
from flare_ai_kit.ecosystem.settings import EcosystemSettings
from flare_ai_kit.ingestion.settings import IngestionSettings
from flare_ai_kit.mcp.settings import MCPSettings
from flare_ai_kit.rag.graph.settings import GraphDbSettings
from flare_ai_kit.rag.vector.settings import VectorDbSettings
from flare_ai_kit.social.settings import SocialSettings
Expand Down Expand Up @@ -38,3 +39,4 @@ class AppSettings(BaseSettings):
tee: TeeSettings = Field(default_factory=TeeSettings) # pyright: ignore[reportArgumentType,reportUnknownVariableType]
ingestion: IngestionSettings = Field(default_factory=IngestionSettings) # pyright: ignore[reportArgumentType,reportUnknownVariableType]
a2a: A2ASettings = Field(default_factory=A2ASettings) # pyright: ignore[reportArgumentType,reportUnknownVariableType]
mcp: MCPSettings = Field(default_factory=MCPSettings) # pyright: ignore[reportArgumentType,reportUnknownVariableType]
30 changes: 30 additions & 0 deletions src/flare_ai_kit/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
from .config import AppSettings

if TYPE_CHECKING:
from google.adk.tools.mcp_tool import McpToolset

from .a2a import A2AClient
from .ecosystem.api import BlockExplorer, FAssets, Flare, FtsoV2
from .ingestion.api import GithubIngestor
from .ingestion.pdf_processor import PDFProcessor
from .mcp.manager import MCPManager
from .rag.vector.api import VectorRAGPipeline
from .social.api import TelegramClient, XClient

Expand Down Expand Up @@ -50,6 +53,7 @@ def __init__(self, config: AppSettings | None) -> None:
self._x_client: XClient | None = None
self._pdf_processor: PDFProcessor | None = None
self._a2a_client: A2AClient | None = None
self._mcp_manager: MCPManager | None = None

# Ecosystem Interaction Methods
@property
Expand Down Expand Up @@ -160,6 +164,32 @@ def a2a_client(self) -> A2AClient:
self._a2a_client = A2AClient(settings=self.settings.a2a)
return self._a2a_client

# MCP Methods
@property
def mcp_manager(self) -> MCPManager:
"""Access the MCP manager (configured via `MCP__SERVERS`)."""
from .mcp.manager import MCPManager # noqa: PLC0415

if self._mcp_manager is None:
self._mcp_manager = MCPManager(self.settings.mcp)
return self._mcp_manager

@property
def mcp_tools(self) -> list[McpToolset]:
"""Get MCP toolsets for use with ADK agents (empty if none configured)."""
return self.mcp_manager.get_toolsets_sync()

@property
def has_mcp_tools(self) -> bool:
"""Check if MCP tools are configured and available."""
return self.mcp_manager.has_servers

async def close_mcp(self) -> None:
"""Close all MCP connections. Call during cleanup."""
if self._mcp_manager is not None:
await self._mcp_manager.close()
self._mcp_manager = None


async def core() -> None:
"""Core function to run the Flare AI Kit SDK."""
Expand Down
6 changes: 6 additions & 0 deletions src/flare_ai_kit/mcp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""MCP (Model Context Protocol) integration for Flare AI Kit."""

from .manager import MCPManager
from .settings import MCPServerConfig, MCPSettings

__all__ = ["MCPManager", "MCPServerConfig", "MCPSettings"]
Loading
Loading