MCP Configuration
This guide covers advanced configuration of Sibyl's MCP (Model Context Protocol) server.
Server Architecture
Sibyl's MCP server uses the Python SDK's MCPServer and mounts its streamable HTTP app in the main Starlette application:
flowchart LR
APP{{"Sibyl Combined App<br/>Starlette · port 3334"}}
API["FastAPI REST endpoints"]
MCP["MCP streamable-http endpoint"]
WS["WebSocket · real-time updates"]
BG["Background queue + session management"]
APP -->|"/api/*"| API
APP -->|"/mcp"| MCP
APP -->|"/ws"| WS
APP -->|"Lifespan"| BGTransport Modes
HTTP Mode (Default)
Sibyl runs as an HTTP server, accepting MCP requests at /mcp:
uv run sibyld serve
# Server listening on http://localhost:3334
# MCP endpoint: http://localhost:3334/mcpConfiguration:
{
"mcpServers": {
"sibyl": {
"type": "http",
"url": "http://localhost:3334/mcp"
}
}
}Stdio Mode
Run Sibyl as a subprocess communicating via stdin/stdout:
uv run sibyld serve -t stdioConfiguration:
{
"mcpServers": {
"sibyl": {
"command": "uv",
"args": ["--directory", "/path/to/sibyl/apps/api", "run", "sibyld", "serve", "-t", "stdio"],
"env": {
"SIBYL_OPENAI_API_KEY": "sk-...",
"SIBYL_JWT_SECRET": "your-secret",
"SIBYL_SURREAL_URL": "ws://127.0.0.1:8000/rpc"
}
}
}
}Authentication Modes
Auto Mode (Default)
Authentication is enabled when SIBYL_JWT_SECRET is set:
SIBYL_MCP_AUTH_MODE=auto # Default
SIBYL_JWT_SECRET=your-secret # If set, auth is enabledForced On
Always require authentication:
SIBYL_MCP_AUTH_MODE=onForced Off (Development Only)
Disable authentication:
SIBYL_MCP_AUTH_MODE=offProduction Warning Never disable authentication in production. Use auto or on mode.
OAuth Flow
When auth is enabled, Sibyl implements OAuth 2.0:
OAuth Endpoints
| Endpoint | Purpose |
|---|---|
/_oauth/login | Login form |
/_oauth/org | Organization selection |
/mcp | Token-authenticated MCP endpoint |
Token Acquisition
- User visits
/_oauth/login - Enters credentials
- Selects organization
- Receives access token
- Token used for MCP requests
API Key Authentication
For programmatic access, use API keys:
# Create API key
sibyl auth api-key create --name "MCP Client" --scopes mcp
# Use in configuration
{
"mcpServers": {
"sibyl": {
"type": "http",
"url": "http://localhost:3334/mcp",
"headers": {
"Authorization": "Bearer sk_xxx..."
}
}
}
}Environment Variables
Core Settings
| Variable | Default | Description |
|---|---|---|
SIBYL_SERVER_HOST | localhost | Host to bind to |
SIBYL_SERVER_PORT | 3334 | Port to listen on |
SIBYL_PUBLIC_URL | http://localhost:3337 | Public base URL for OAuth callbacks/redirects |
SIBYL_SERVER_URL | - | Public API and MCP origin behind a proxy |
SIBYL_SERVER_NAME | sibyl | Server name in MCP responses |
Authentication Settings
| Variable | Default | Description |
|---|---|---|
SIBYL_JWT_SECRET | - | JWT signing secret (required for auth) |
SIBYL_ACCESS_TOKEN_EXPIRE_MINUTES | 60 | Access token TTL in minutes |
SIBYL_MCP_AUTH_MODE | auto | Auth mode: auto, on, off |
Sibyl validates MCP Host and Origin headers to prevent DNS rebinding. Set SIBYL_SERVER_URL to the public API origin when a loopback-bound daemon sits behind a Host-preserving proxy (for example, https://sibyl.example.com). The configured frontend origin, server origin, bind address, and loopback origins remain allowed.
GitHub OAuth (Optional)
| Variable | Description |
|---|---|
SIBYL_GITHUB_CLIENT_ID | GitHub OAuth app client ID |
SIBYL_GITHUB_CLIENT_SECRET | GitHub OAuth app secret |
Database Settings
| Variable | Default | Description |
|---|---|---|
SIBYL_SURREAL_URL | - | SurrealDB connection URL (ws:// / http://) |
SIBYL_REDIS_HOST | 127.0.0.1 | Optional Redis/Valkey host |
moon run dev provisions a local SurrealDB automatically. The memory:// URL is a test-only mode and is rejected by the production config validator.
Embedding Settings
| Variable | Default | Description |
|---|---|---|
SIBYL_OPENAI_API_KEY | - | OpenAI API key (required) |
SIBYL_EMBEDDING_MODEL | text-embedding-3-small | Embedding model |
Server Implementation
Tool Registration
The MCP server is constructed in server.py and registers 13 tools: search, context, synthesis_plan, synthesis_draft, synthesis_verify, explore, expand_neighbors, fetch_slice, add, remember, reflect, manage, and logs. See Agents & MCP for what each one does.
mcp = MCPServer(
settings.server_name,
auth=auth_settings,
auth_server_provider=auth_server_provider,
)
mcp_app = mcp.streamable_http_app(host=host, stateless_http=False)
@mcp.tool()
async def search(...) -> dict:
"""Semantic search across knowledge graph."""
org_id = await _require_org_id()
return await _search(..., organization_id=org_id)Organization Context
Every tool extracts organization from the authenticated context:
async def _require_org_id() -> str:
"""Require organization ID from MCP context."""
org_id = await _get_org_id_from_context()
if not org_id:
raise ValueError("Organization context required")
return org_idResource Registration
MCP resources provide read-only data:
@mcp.resource("sibyl://health")
async def health_resource() -> str:
"""Server health status."""
health = await get_health()
return json.dumps(health)
@mcp.resource("sibyl://stats")
async def stats_resource() -> str:
"""Graph statistics."""
stats = await get_stats()
return json.dumps(stats)API Scopes
API keys can have different scopes:
| Scope | Permission |
|---|---|
mcp | Access MCP endpoint |
api:read | REST GET/HEAD/OPTIONS |
api:write | REST writes (implies read) |
Create scoped keys:
# MCP only
sibyl auth api-key create --name "MCP" --scopes mcp
# MCP + read API
sibyl auth api-key create --name "CI/CD" --scopes mcp,api:read
# Full access
sibyl auth api-key create --name "Admin" --scopes mcp,api:writeLoad Balancing
For production deployments with multiple instances:
Sticky Sessions
MCP sessions maintain state. Use sticky sessions if load balancing:
upstream sibyl {
ip_hash; # Sticky sessions
server sibyl1:3334;
server sibyl2:3334;
}Shared State
For stateless scaling:
- Use Redis/Valkey for shared coordination
- Ensure all instances share the same SurrealDB service
- Use sticky sessions for stateful MCP connections
Monitoring
Health Check
curl http://localhost:3334/api/healthMCP Status
Access via MCP resource:
sibyl://health
sibyl://statsMetrics Endpoint
curl http://localhost:3334/api/metricsTroubleshooting
Connection Refused
- Check server is running
- Verify port isn't blocked
- Check firewall settings
Authentication Failed
- Verify
SIBYL_JWT_SECRETis set - Check API key is valid
- Ensure token hasn't expired
Organization Not Found
- Check user belongs to organization
- Verify org_id in token claims
- Check organization exists
Slow Responses
- Check SurrealDB connection and query latency
- Verify embedding API connectivity
- Review query complexity
Example Configurations
Local Development
{
"mcpServers": {
"sibyl": {
"type": "http",
"url": "http://localhost:3334/mcp"
}
}
}Production with Auth
{
"mcpServers": {
"sibyl": {
"type": "http",
"url": "https://sibyl.example.com/mcp",
"headers": {
"Authorization": "Bearer sk_..."
}
}
}
}Subprocess Mode
{
"mcpServers": {
"sibyl": {
"command": "uv",
"args": ["--directory", "/opt/sibyl/apps/api", "run", "sibyld", "serve", "-t", "stdio"],
"env": {
"SIBYL_OPENAI_API_KEY": "sk-...",
"SIBYL_JWT_SECRET": "...",
"SIBYL_SURREAL_URL": "ws://surrealdb.internal:8000/rpc"
}
}
}
}Next Steps
- Agents & MCP - Connect any agent over MCP
- Skills Development - Create custom skills
- Multi-Tenancy - Organization scoping
