Skip to content

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.

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
{
"mcp": {
"server-name": {
"type": "local",
"command": ["python", "path/to/server.py"],
"environment": {
"API_KEY": "{env:MY_API_KEY}"
}
}
}
}

Runs as a child process:

{"channel": {"type": "local", "command": ["python", "{env:HOME}/.ostwin/.agents/mcp/channel-server.py"], "environment": {"AGENT_OS_ROOT": "."}}}

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.

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}"
}
}

For sensitive values, use vault references instead of env vars:

{"environment": {"API_KEY": "${vault:github/token}", "DB_PASSWORD": "${vault:database/password}"}}
  1. Add a secret: python dashboard/scripts/vault_get.py set github token "ghp_your_token"

  2. Reference it in MCP config using ${vault:server/key} syntax.

  3. Verify. The resolver validates all vault refs at startup and errors on missing secrets.

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.

  1. Write the server following MCP protocol:

    from mcp.server import Server
    server = 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()
  2. Add to config.json:

    {"mcp": {"my-tools": {"type": "local", "command": ["python", "tools/my-server.py"], "environment": {"AGENT_OS_ROOT": "."}}}}
  3. Validate: python .agents/mcp/validate_mcp.py

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
ostwin-manager dashboard /api/ostwin-manager/mcp Plan/role/skill discovery plus five authoring mutations

ostwin-manager is built in but denied to roles by default. In the dashboard Role Editor, append ostwin-manager to the selected role’s MCP servers, or add it to the role definition while preserving the existing entries:

{
"name": "manager",
"mcp_refs": ["global-memory", "global-knowledge", "ostwin-manager"]
}

Then regenerate the OpenCode role permissions:

Terminal window
ostwin mcp sync

ostwin mcp sync reads the deployed $OSTWIN_HOME/.agents/mcp/mcp-builtin.json. If you edited a separate checkout, deploy/build that checkout before syncing the installed runtime.

The remote endpoint uses Streamable HTTP and the dashboard authentication header from mcp-builtin.json. It accepts only platform-admin actors. A role without the ostwin-manager ref receives an OpenCode client-side deny, but that policy is not a server-side isolation boundary: the bearer credential and the endpoint’s platform-admin authorization are the actual boundary.

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.

MCP tool definitions consume context tokens. Minimize overhead:

{"mcp": {"playwright": null, "chrome-devtools": null}}

Setting a server to null removes it from resolution.

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