Pantheon ships five local Python stdio MCP servers. They auto-start with OpenCode and cover project memory, persistence, resources, confined script execution, and vision. This page owns MCP setup, entrypoints, allowlists, and pins. Tool signatures live in MCP Tools; memory policy lives in Memory.
The packaged runtime pins the MCP Python SDK to mcp==2.2.0 and the standalone
FastMCP server framework to fastmcp==4.1.2. Server code imports FastMCP
from fastmcp; MCP SDK v2 removed the old mcp.server.fastmcp re-export.
Installation creates the isolated Python environment from the matching manifest
in src/mcp/.
The installer declares the five servers in scripts/install-mcp.mjs:74-78 and
registers them at :196-301. Each entrypoint is a real script, not a shared
server.py:
| Server | Entrypoint | Tools | Resources |
|---|---|---|---|
pantheon-resources |
scripts/mcp_resources.py |
— | 4 static + 6 templates |
pantheon-code-mode |
scripts/code_mode.py |
2 | 1 static + 1 template |
pantheon-memory |
scripts/memory_mcp.py |
9 | — |
pantheon-persistence |
scripts/mcp_persistence.py |
6 | — |
pantheon-vision |
src/mcp/pantheon_vision.py |
3 | — |
The entrypoints were renamed away from the shared *_server.py token. The
installer heals stale paths with the mapping in
scripts/install/config-migration.mjs:700-706:
| Old | New |
|---|---|
mcp_resources_server.py |
mcp_resources.py |
code_mode_server.py |
code_mode.py |
memory_mcp_server.py |
memory_mcp.py |
mcp_persistence_server.py |
mcp_persistence.py |
pantheon_vision_server.py |
pantheon_vision.py |
Installation writes absolute paths for the venv interpreter and the server
script. pantheon-memory uses src/mcp/memory_mcp.py as its canonical runtime
source; scripts/memory_mcp.py is a source-tree compatibility entrypoint that
delegates to it. pantheon-vision is deployed from the canonical source to
scripts/pantheon_vision.py; do not maintain a second source copy.
The installer writes this shape. Add the same shape by hand only for a custom server.
{
"mcp": {
"pantheon-resources": {
"type": "local",
"command": ["<venv-python>", "<installed>/scripts/mcp_resources.py"],
"enabled": true
},
"pantheon-code-mode": {
"type": "local",
"command": ["<venv-python>", "<installed>/scripts/code_mode.py"],
"cwd": ".",
"enabled": true
}
}
}Restart the client after changing MCP configuration. Servers are separate OS processes launched by the host.
The installer reads mcp_tools from each canonical src/agents/*.md file and
generates native per-agent permissions. For each Pantheon server it denies the
wildcard first, then allows the declared tools. Undeclared Pantheon servers
default to deny; unrelated user MCP servers are untouched.
| Agent | Resources | Code-mode | Memory | Persistence | Vision |
|---|---|---|---|---|---|
| zeus | all | — | search | context_save, context_get, goal_create, goal_get, goal_update, goal_done | — |
| athena | all | — | search, code_query, code_neighbors | — | — |
| apollo | all | — | search, code_query, code_neighbors | — | — |
| hermes | all | execute script | search | — | — |
| aphrodite | all | execute script | search | — | describe/OCR/analyze |
| demeter | all | execute script | search | — | — |
| themis | all | execute script | search | — | — |
| prometheus | all | execute script | search | — | — |
| hephaestus | all | execute script | search | — | — |
| nyx | all | execute script | search | — | — |
| gaia | all | — | recall | — | describe/OCR/analyze |
| iris | all | — | recall | — | — |
| mnemosyne | all | execute script | explicit memory tools | — | — |
| talos | all | execute script | recall | — | — |
Rules:
allallows every tool from that named Pantheon server.- A list allows only those tool names; an empty list denies every tool there.
- A server omitted from an agent's metadata is denied for that agent.
- Rules are generated into V1
permissionobjects and V2permissionsarrays. - V1
permission.taskrules translate to V2's nativesubagentaction. - Third-party MCP permissions remain the user's configuration.
On OpenCode 2.x the host evaluates a permissions rule whose action is
<server>_* (or <server>_<tool>) with effect deny/allow. The V1-shaped
permission.mcp.<server> key is not an action the host evaluates; the installer
translates allow/deny into the former. ask is not expressible for MCP on
that host: it hides the tool instead of prompting, so the installer emits no
rule and warns. In V2, per-agent rules can hide tools from that agent without
disconnecting the server.
The Apollo/Athena code_query and code_neighbors grants are the approved
read-only code-map choice; code_index and per-project binding were not
selected. Checkpoints are limited to context_save and context_get on Zeus;
they are session-qualified temporary persistence, not durable memory writes.
Mnemosyne's canonical allowlist includes durable-memory write tools; always
check the active tool list. These are installed per-agent allowlists, not a
guarantee that the root runtime exposes the same tools.
Read-only resource server exposing Pantheon framework metadata. No tools, only resources and templates.
| URI | Description |
|---|---|
pantheon://routing |
Canonical delegation rules and handoff contracts |
pantheon://agents |
All 14 agents with roles from frontmatter |
pantheon://skills |
All skills with descriptions |
pantheon://eval |
Latest certification scores from the plugin_eval namespace |
pantheon://agents/{agent_name} |
One agent file by name (case-insensitive) |
pantheon://deepwork/{slug} |
PLAN.md for a deepwork task |
pantheon://deepwork/{slug}/status |
STATUS.md for a deepwork task |
pantheon://memory-bank/{path} |
One file under .pantheon/memory-bank/ (path traversal blocked) |
pantheon://skills/{name} |
One skill's SKILL.md |
pantheon://eval/{plugin} |
One certification report |
pantheon://memory-bank/{path} reads project documentation on demand; those
files are not automatically loaded. The evaluation resources read the global
Memory SQLite database in the plugin_eval namespace, which is an
organizational filter, not an access-control boundary.
Confined script execution from .pantheon/code-mode/, with a 30-second
timeout. It exposes two tools: execute_code_script(script_name) runs an
approved script, and approve_code_script(script_name) records or refreshes its
SHA-256 in the manifest. Resources list the available scripts and show one
script's content.
Scripts run only when explicitly approved and recorded in the manifest with their SHA-256. See Code Mode for the approval contract and status codes.
Persistent SQLite memory with FTS5/BM25 lexical search. It registers six
memory_* tools plus three code_* codemap tools; the canonical source is
src/mcp/memory_mcp.py. The database defaults to
~/.config/opencode/memory/memory.db, with PANTHEON_HOME and
XDG_CONFIG_HOME overrides.
Tool signatures are in MCP Tools; the size cap, TTL, search policy, and error contract are in Memory.
Session checkpoints plus manual session goals. The surface is exactly six
tools: context_save, context_get, goal_create, goal_get, goal_update,
and goal_done. The KV table is internal checkpoint storage; former KV
management, context list/statistics, rehydration, and summary operations are not
registered.
Goals are Zeus-only and partitioned by OpenCode session id; the session id is a correlation key, not authentication. See Memory for permissions, TTL defaults, size bounds, and migration of an existing database.
Three tools: vision_describe(path, prompt?, session_id?),
vision_ocr(path, session_id?), and vision_analyze(path, session_id?).
session_id is the caller's OpenCode session id. The MCP runs in a separate
process the host hands no session id to, so the plugin forwards it; the server
sends it to a Zen endpoint as the required x-opencode-session header (never to
a non-Zen host, and never logged).
The server resolves PANTHEON_OPENCODE_API_KEY or OPENCODE_API_KEY, then the
standard OpenCode auth store. It always talks to the OpenCode Zen endpoints.
Images degrade through native model → this MCP server → deterministic local
extraction; the tool never fabricates content. Bifrost remains opt-in only.
Adding a server to config is only half the work: agents do not auto-discover MCP tools. Declare them in the agent's canonical file.
1. Add the server to opencode.json (OpenCode shape):
{
"mcp": {
"my-tools": {
"type": "local",
"command": ["node", "my-mcp-server.js"],
"enabled": true
}
}
}2. Declare tools in the agent's YAML frontmatter:
---
name: hermes
mcp_tools:
my-tools:
- analyze_dependency
---3. Document them in the agent body so the agent knows when to use them:
## Custom MCP Tools
| Server | Tool | When to use |
|---|---|---|
| **my-tools** | `analyze_dependency(package, depth?)` | Check a dependency for known vulnerabilities |4. Set access control. V1 uses permission.mcp.<server>; on V2 use the
native <server>_* rule described above. Start with ask for a new server and
downgrade to allow only after verifying read-only safety.
The installer's own servers use the local shape shown above: type, command
as an array, optional environment, and enabled. A hand-added third-party
server takes the same keys, with the provider's documented command:
{
"mcp": {
"github": {
"type": "local",
"command": [
"docker",
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"environment": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "{env:GITHUB_PERSONAL_ACCESS_TOKEN}"
},
"enabled": true
}
}
}The GitHub server's documented stdio invocation is:
docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server-i keeps stdin open for JSON-RPC, and the token reaches the container through
the environment entry rather than being written into opencode.json. If the
image or command differs in your setup, use whatever the provider documents —
only the type/command/environment/enabled shape is Pantheon's. Note that
the installer's own catalog configures GitHub as a remote server
(https://api.githubcopilot.com/mcp/) with OAuth, so this stdio entry is for the
cases where a local process is preferred; do not declare both under one name.
Best practices: short lowercase server names (they become the tool prefix);
declare only the tools the agent needs; keep the mcp_tools key identical to
the server name; interpolate secrets as {env:VAR} instead of inlining them;
and prefer three core plus up to four custom servers, because accuracy degrades
beyond seven.
MCP servers are separate OS processes. Never terminate them with a bare
filename substring. A broad idiom such as pkill -f server.py matches every
process whose command line contains that token. This was observed once as
collateral damage: an external SIGTERM on a server.py pattern took down 20
processes across four workspaces within 91 ms.
Kill by PID or by port. Find the PID with a full path
(pgrep -f '/absolute/path/to/memory_mcp.py') and kill <pid>, or stop the
client that owns it. The entrypoint rename away from *_server.py is defense in
depth; the PID/port rule still governs.
| Symptom | Likely cause | Fix |
|---|---|---|
| Server not found | Not in MCP config | Add it under mcp in opencode.json, then restart |
| Connection refused | Python environment issue | Run npm run setup; verify fastmcp is installed |
memory_recall empty |
No entries stored | Call memory_store first |
| Code-mode script not found | Wrong path | Script must be in .pantheon/code-mode/ |
| Vision returns metadata only | No gateway credential | Set PANTHEON_OPENCODE_API_KEY / OPENCODE_API_KEY or run opencode auth login |
| Path traversal error | Invalid URI segment | Use flat filenames for pantheon://memory-bank/{path} |
| Agent says it lacks a tool | MCP not declared in frontmatter | Add an mcp_tools: entry and reinstall |