Prism
Prism
Multi-level web search MCP server. Wraps Claude, Gemini, Perplexity, and Tavily behind a unified interface.
Search Levels
Level 0: Instant - direct worker call (default: claude_search), supports multi-provider selection
Level 1: Quick - 4 workers, parallel dispatch (~3 min)
Level 2: Standard - 6 workers, comprehensive (~5 min)
Level 3: Deep - 8 workers, exhaustive research (~10-15 min)
All 4 worker types (claude_search, tavily_search, perplexity_search, gemini_search) are available at every level. L0 supports explicit provider selection via the providers parameter. Levels 1-3 use a search manager that plans tasks, dispatches parallel workers, and synthesizes results.
Quick Start
Prerequisites
Podman with
podman composeAPI keys: copy
.dev.env.exampleto.dev.envand fill in values. Keys already in your OS environment (e.g., via~/.bashrc) flow through automatically -- only add entries for keys not in your shell.
Development
cp .dev.env.example .dev.env # fill in missing API keys
make dev # start PostgreSQL + Prism with hot-reload
make dev-logs # view logs
make dev-down # stopData lives in /tmp for easy cleanup: /tmp/prism-postgres, /tmp/prism-claude.
Production
cp .prod.env.example .prod.env # fill in secrets
# Create postgres password
openssl rand -base64 32 > ~/.config/prism/postgres_password
chmod 600 ~/.config/prism/postgres_password
make prod # startData persists at ~/.local/share/prism/postgres and ~/.local/share/prism/claude.
Configuration
All settings with defaults and comments live in config/config.yaml -- this file IS the config documentation.
Loading chain (highest priority wins):
PRISM_SECTION_KEYenvironment variablesCustom override YAML (
config-custom/, sparse -- only values that differ)config/config.yaml(defaults, always present in image)
Env var naming: YAML paths joined with underscores, prefixed PRISM_:
server.port-->PRISM_SERVER_PORTretry.max_transient_retries-->PRISM_RETRY_MAX_TRANSIENT_RETRIES
Secrets use environment variables injected via --env-file into compose. See .prod.env.example for required variables. Custom config overrides go in config-custom/ (gitignored).
MCP Registration
Add to your MCP client config (e.g., ~/.claude.json for Claude Code):
{
"mcpServers": {
"prism": {
"type": "http",
"url": "http://localhost:8765/mcp",
"headers": {
"X-User-Id": "your-username"
}
}
}
}The X-User-Id header identifies the user for session scoping. Each user sees only their own sessions. Omitting the header defaults to "default".
API
Tools:
search(query, level=0, providers=None)- Execute search at specified depthproviders(L0 only):["claude_search"],["tavily_search"],["gemini_search"],["perplexity_search"], any combination, or["mix"]for all 4 in parallel. Default (None): claude_search only.
cancel_all()- Cancel all running searches for the current userget_session(session_id)- Retrieve session detailslist_sessions(limit=20, offset=0, search=None)- List recent sessionsresume(session_id, follow_up)- Resume L1-L3 session with follow-up
The session_id a search returns is the id every other tool accepts — pass it
straight to get_session or resume.
Development
UV for Python
All Python commands through UV (never python or pip directly):
uv run pytest tests/unit/ -v
uv run python -m prism
uv run ruff check src/Testing
# Unit tests (fast, mocked, no API keys)
uv run pytest tests/unit/ -v
# E2E tests (manages full container lifecycle + requires API keys)
uv run python tests/e2e/run_e2e.py # all tests
uv run python tests/e2e/run_e2e.py --only l0_default,l1 # specific testsDatabase Migrations
uv run alembic revision --autogenerate -m "Description"
uv run alembic upgrade headArchitecture
MCP Client
|
[FastMCP Server]
|
+---------------+---------------+
| | |
Level 0 Level 1-3 Session
(multi-provider) (orchestrated) Management
| |
[Worker Factory] [Search Manager]
| |
+------+------+ [Worker Dispatcher]
| | | |
[1-4 workers] +-------+-------+-------+
in parallel | | | |
[Claude] [Gemini] [Tavily] [Perplexity]
| | | |
+-------+-------+-------+
|
[Synthesizer]
|
ResponseKey patterns:
Dual CLI executors:
core/executor.py(Claude),core/gemini.py(Gemini)Unified worker factory: same 4 worker types available at all levels
Two-tier retry: transient errors + schema validation with
--resume(Claude only)Time-aware hooks for both Claude and Gemini CLI agents
JSON-lines structured logging
DI throughout, no global state
Multi-tenancy via user_id scoping