MCP Configuration
MCP (Model Context Protocol) servers provide tool access to agents. Each war-room gets its own MCP server instances, creating isolated tool boundaries.
Config files
MCP configuration lives in .agents/mcp/:
| File | Purpose |
|---|---|
config.json | User/project config (highest priority) |
mcp-builtin.json | Built-in servers shipped with OSTwin |
mcp-catalog.json | Available but inactive servers |
extensions.json | Third-party extension configs |
config_resolver.py | Resolution engine |
vault.py | Secret management |
Config format
{ "mcp": { "server-name": { "type": "local", "command": ["python", "path/to/server.py"], "environment": { "API_KEY": "{env:MY_API_KEY}" } } }}Server types
Runs as a child process:
{"channel": {"type": "local", "command": ["python", "{env:HOME}/.ostwin/.agents/mcp/channel-server.py"], "environment": {"AGENT_OS_ROOT": "."}}}Connects via HTTP:
{"stitch": {"type": "remote", "url": "https://stitch.googleapis.com/mcp", "headers": {"X-Goog-Api-Key": "{env:MCP_STITCH_API_KEY}"}}}4-tier priority
Configs merge in priority order (highest wins):
| Priority | Source | File |
|---|---|---|
| 1 | Per-room | war-rooms/room-001/mcp.json |
| 2 | Project | .agents/mcp/config.json |
| 3 | User | ~/.ostwin/.agents/mcp/config.json |
| 4 | Built-in | .agents/mcp/mcp-builtin.json |
Higher-priority sources override lower ones per server name. A server set to null in a higher tier disables it.
Variable resolution
Environment variables use {env:VAR} syntax with optional defaults:
{ "environment": { "API_KEY": "{env:ANTHROPIC_API_KEY}", "PORT": "{env:MCP_PORT:-8080}", "LOG_LEVEL": "{env:MCP_LOG_LEVEL:-info}" }}Vault secrets
For sensitive values, use vault references instead of env vars:
{"environment": {"API_KEY": "${vault:github/token}", "DB_PASSWORD": "${vault:database/password}"}}-
Add a secret:
python dashboard/scripts/vault_get.py set github token "ghp_your_token" -
Reference it in MCP config using
${vault:server/key}syntax. -
Verify. The resolver validates all vault refs at startup and errors on missing secrets.
Per-room MCP
Override servers for specific war-rooms with mcp.json in the room directory:
{ "mcp": { "database": { "type": "local", "command": ["python", "tools/db-server.py"], "environment": {"DB_URL": "postgresql://localhost/room001_db"} } }}This gives room-001 a database server no other room can access.
Adding custom servers
-
Write the server following MCP protocol:
from mcp.server import Serverserver = Server("my-tools")@server.tool()async def my_tool(param: str) -> str:"""What this tool does."""return f"Result for {param}"if __name__ == "__main__":server.run() -
Add to config.json:
{"mcp": {"my-tools": {"type": "local", "command": ["python", "tools/my-server.py"], "environment": {"AGENT_OS_ROOT": "."}}}} -
Validate:
python .agents/mcp/validate_mcp.py
Built-in servers
| Server | File | Tools |
|---|---|---|
channel | channel-server.py | post_message, read_messages, get_latest |
warroom | warroom-server.py | update_status, report_progress, list_artifacts |
memory | memory-core.py | publish, query, search, get_context |
Audit logging
Tool calls are logged to .agents/mcp/logs/. Watch with tail -f .agents/mcp/logs/channel-server.log. Entries include timestamp, tool name, parameters, and result status.
Token optimization
MCP tool definitions consume context tokens. Minimize overhead:
{"mcp": {"playwright": null, "chrome-devtools": null}}Setting a server to null removes it from resolution.
Give each room only the servers it needs. A database epic does not need browser tools.
Troubleshooting
| Symptom | Fix |
|---|---|
| ”Vault reference not found” | Add the secret via vault script |
| Server fails to start | Verify path uses {env:HOME} correctly |
| Tools not visible | Add server to config.json |
| Env variable empty | Add to ~/.ostwin/.env |
| Resolver error | Validate JSON: python -m json.tool < config.json |