Sanctum Core Module: Model Context Protocol Server
SMCP is a powerful, plugin-based Model Context Protocol (MCP) server for the Sanctum Letta AI framework. This server provides seamless integration between AI clients and external tools through a robust plugin architecture. As a Sanctum Core Module, it represents the official, production-ready implementation maintained by the Sanctum team.
SMCP has been completely rewritten to use the base MCP library instead of FastMCP for full compatibility with Letta's SSE client:
- β Bidirectional SSE: Proper clientβserver communication
- β Letta Compatible: Tools appear in both test and attached modes
- β Production Ready: Robust error handling and graceful shutdown
- β Plugin System: Dynamic discovery and execution
Why the change? FastMCP's SSE implementation is unidirectional (serverβclient only), which breaks compatibility with Letta's bidirectional SSE client requirements.
- Plugin Architecture: Easy-to-write plugins for any external service or tool
- MCP Protocol Compliant: Full support for the Model Context Protocol specification
- SSE Transport: Bidirectional server-sent events for efficient communication with Letta
- JSON-RPC 2.0: Standardized request/response handling
- Auto-Discovery: Automatic plugin detection and tool registration
- Health Monitoring: Built-in health checks and status reporting
- Production Ready: Comprehensive error handling and logging
New to SMCP? Start with our comprehensive documentation:
- π Getting Started Guide - Complete setup in 5 minutes
- π Plugin Development - Build your first plugin
- π Examples - Copy-paste working code
- π¨ Troubleshooting - Solve any problem quickly
- Python 3.8 or higher
- pip package manager
Option 1: Master Sanctum Installer (Recommended) The master Sanctum installer will automatically deploy SMCP to the correct location within your Sanctum environment with all necessary configurations.
Option 2: Standalone Repository SMCP can also function as a standalone repository for development, testing, or custom deployments.
-
Create virtual environment
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies
pip install -r requirements.txt
-
Run the server
python smcp.py
The server will start on http://localhost:8000 by default with localhost-only access for security.
By default, the server binds to localhost only (127.0.0.1) for security. This is the recommended setting.
For localhost-only access (default):
python smcp.py --host 127.0.0.1To allow external connections (use with caution):
python smcp.py --allow-externalCustom port:
python smcp.py --port 9000Custom host binding:
python smcp.py --host 0.0.0.0 --port 8000When deployed via the master Sanctum installer, SMCP is automatically:
- Installed to the correct location within your Sanctum environment
- Configured with appropriate environment variables
- Integrated with the Sanctum plugin management system
- Set up with proper networking and security configurations
Note: The following configuration options apply to standalone deployments. When using the master installer, these are handled automatically.
| Variable | Default | Description |
|---|---|---|
MCP_PORT |
8000 |
Port for the MCP server |
MCP_PLUGINS_DIR |
plugins/ |
Directory containing plugins |
MCP_HOST |
127.0.0.1 |
Host to bind to (default: localhost for security) |
# Default: localhost-only
python smcp.py
# Custom port
export MCP_PORT=9000
python smcp.py
# Localhost-only (default)
python smcp.py --host 127.0.0.1
# Custom plugins directory
export MCP_PLUGINS_DIR=/path/to/custom/plugins
python smcp.pyNote: When deployed via the master Sanctum installer, plugins are automatically discovered and managed. The following applies to standalone deployments and custom plugin development.
For comprehensive plugin development documentation, see docs/dev/plugin-development-guide.md.
Each plugin should follow this directory structure:
plugins/
βββ your_plugin/
β βββ __init__.py
β βββ cli.py # Main plugin interface
β βββ README.md # Plugin documentation
The server supports symbolic links for flexible plugin deployment. You can centralize plugins in a designated location and use symlinks for discovery:
# Central plugin repository
/opt/sanctum/plugins/
βββ botfather/
βββ devops/
βββ custom-plugin/
# MCP server plugin directory with symlinks
plugins/
βββ botfather -> /opt/sanctum/plugins/botfather
βββ devops -> /opt/sanctum/plugins/devops
βββ custom-plugin -> /opt/sanctum/plugins/custom-plugin
- Separation of Concerns: Keep MCP server code separate from plugin implementations
- Centralized Management: Manage plugins in a designated repository
- Dynamic Loading: Add/remove plugins by creating/removing symlinks
- Version Control: Maintain plugins in separate repositories
- Deployment Flexibility: Deploy plugins independently of the MCP server
You can override the plugin directory using the MCP_PLUGINS_DIR environment variable:
# Use custom plugin directory
export MCP_PLUGINS_DIR=/opt/sanctum/plugins
python smcp.py-
Create plugin directory
mkdir -p plugins/my_plugin
-
Create the CLI interface (
plugins/my_plugin/cli.py)#!/usr/bin/env python3 """ My Plugin CLI A sample plugin for the Sanctum Letta MCP Server. """ import argparse import json import sys def main(): parser = argparse.ArgumentParser(description="My Plugin CLI") subparsers = parser.add_subparsers(dest="command", help="Available commands") # Add your command cmd_parser = subparsers.add_parser("my-command", help="Execute my command") cmd_parser.add_argument("--param", required=True, help="Required parameter") cmd_parser.add_argument("--optional", default="default", help="Optional parameter") args = parser.parse_args() if args.command == "my-command": result = execute_my_command(args.param, args.optional) print(json.dumps(result)) else: parser.print_help() sys.exit(1) def execute_my_command(param, optional): """Execute the main command logic.""" # Your plugin logic here return { "status": "success", "param": param, "optional": optional, "message": "Command executed successfully" } if __name__ == "__main__": main()
-
Make it executable
chmod +x plugins/my_plugin/cli.py
-
Test your plugin
python plugins/my_plugin/cli.py my-command --param "test" --optional "value"
- Command Structure: Use descriptive command names with hyphens
- Parameter Validation: Always validate required parameters
- Error Handling: Return meaningful error messages
- JSON Output: Return structured JSON for easy parsing
- Documentation: Include help text for all commands and parameters
- botfather: Telegram Bot API integration
- devops: Deployment and infrastructure management
- SSE Endpoint:
GET /sse- Server-sent events for real-time communication - Message Endpoint:
POST /messages/- JSON-RPC 2.0 message handling
- Connection: Client establishes SSE connection
- Initialization: Client sends
initializerequest - Capability Exchange: Server responds with available tools
- Tool Execution: Client can call registered tools
- Event Streaming: Server sends events via SSE
import httpx
import json
async def connect_to_mcp():
base_url = "http://localhost:8000"
# Initialize connection
init_request = {
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {"tools": {}, "resources": {}, "prompts": {}},
"clientInfo": {"name": "my-client", "version": "1.0.0"}
}
}
async with httpx.AsyncClient() as client:
response = await client.post(f"{base_url}/messages/", json=init_request)
data = response.json()
# List available tools
tools_request = {
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}
response = await client.post(f"{base_url}/messages/", json=tools_request)
tools = response.json()["result"]["tools"]
# Call a tool
call_request = {
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "health",
"arguments": {}
}
}
response = await client.post(f"{base_url}/messages/", json=call_request)
result = response.json()["result"]
return result# Run all tests
python -m pytest tests/ -v
# Run specific test categories
python -m pytest tests/unit/ -v
python -m pytest tests/integration/ -v
python -m pytest tests/e2e/ -v
# Run with coverage
python -m pytest tests/ --cov=smcp --cov-report=html- Unit Tests: Core functionality and plugin system
- Integration Tests: MCP protocol and endpoint testing
- E2E Tests: Complete workflow validation
The server provides a built-in health check tool:
curl -X POST http://localhost:8000/messages/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"health","arguments":{}}}'Logs are written to stdout and, by default, to mcp.log with rotation. Configure behavior via environment variables:
MCP_LOG_LEVEL(defaultINFO)MCP_LOG_JSON(settruefor JSON logs)MCP_LOG_FILE(defaultmcp.log)MCP_LOG_ROTATION(size,time, ornone)MCP_DISABLE_FILE_LOG(settrueto disable file logging)
See docs/api-reference.md for the full matrix.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Install development dependencies
pip install -r requirements-dev.txt
# Run linting
flake8 smcp/ tests/
# Run type checking
mypy smcp/
# Run tests with coverage
python -m pytest tests/ --cov=smcp --cov-report=html- π Getting Started Guide - NEW USERS START HERE! Complete setup and first steps
- π Plugin Development Guide - Create and deploy custom plugins
- π Examples Guide - Practical examples and code samples for all use cases
- π Deployment Guide - Production deployment with systemd, Docker, and reverse proxy
- π§ Configuration Guide - Complete API documentation and configuration options
- ποΈ MCP Reference Architecture - High-level architecture overview
- π Letta MCP Connection Guide - Connect Letta clients to SMCP
- π¨ Troubleshooting Guide - Common issues and solutions for all problems
- π Monitoring & Health Checks - Production monitoring setup
- π Project Plan - Internal project planning and decisions
This project uses dual licensing:
- Code: Licensed under the GNU Affero General Public License v3.0 (AGPLv3) - see the LICENSE file for details.
- Documentation & Data: Licensed under the Creative Commons Attribution-ShareAlike 4.0 International License (CC-BY-SA 4.0) - see the LICENSE-DOCS file for details.
Important: AGPLv3 is a copyleft license that requires any derivative works to also be open source. If you modify and distribute this software, you must make your source code available under the same license.
- Model Context Protocol for the protocol specification
- FastMCP for the server framework
- The Sanctum team for the AI framework integration
- The Letta team for the kernel for SanctumOS
For support, questions, or contributions:
- Author: Mark Rizzn Hopkins
- Repository: https://github.com/sanctumos/smcp
- Issues: https://github.com/sanctumos/smcp/issues
Part of the Sanctum Suite - A comprehensive AI framework for modern applications.