Auto-Registered MCP Servers Should Stay in APX Runtime, Not APC
An integration can expose an MCP server without meaning that server belongs in the repository.
That boundary matters more than it looks.
APC is the portable context layer. It keeps durable project meaning in committed files such as AGENTS.md, .apc/agents/, skills, and .apc/mcps.json. APX is the daily-use runtime and tooling layer. It owns machine-local state, plugin lifecycle, daemon behavior, and the MCP merge order that turns those files into something runnable.
Auto-registered MCP servers belong on the APX side.
Why this is the right boundary
A plugin-generated MCP definition often points at local facts: a vault path, a localhost endpoint, or a token-bearing environment variable. Those are operational details. They help one machine run a tool today, but they are not safe portable project truth.
APX's MCP source model makes that explicit.
In src/core/mcp/sources.js, APX defines three writable scopes:
-
sharedin.apc/mcps.jsonfor project-wide, committable MCP definitions -
runtimein~/.apx/projects/<apxId>/mcps.jsonfor per-project local definitions, protected withchmod 0600 -
globalin~/.apx/mcps.jsonfor machine-wide fallbacks
The same file also documents the merge order: runtime wins first, then project-shared APC entries, then foreign IDE configs, then global last.
That tells you what APC and APX each own.
APC can carry stable, reviewable MCP hints. APX decides which local definition actually runs on this machine.
What APX does with auto-MCP integrations
The clearest example is plugin sync.
In src/core/integrations/mcp-sync.js, APX maps integration scope to MCP scope with one deliberate rule:
- integration
globalmaps to MCPglobal - everything else maps to MCP
runtime
The comment above that function explains why: auto-registered servers point at machine-local paths, so project integrations should become per-project runtime MCPs, not committed APC MCPs.
That same file says it directly: APX deliberately avoids the committed .apc/mcps.json scope for those generated servers.
That is a good design.
If APX wrote plugin-generated MCPs into .apc/mcps.json, one developer could accidentally commit a local vault path, a machine-only endpoint, or a secret-shaped environment contract into the repo. Another clone on another laptop would inherit a definition that looked official but was only true on the first machine.
That would weaken APC.
Practical example: Obsidian
Today the Obsidian integration is the concrete case.
APX documents an optional auto_mcp flow, and reconcilePluginMcp() keeps the MCP server in sync with the plugin lifecycle. When the integration becomes active, APX writes or updates the MCP definition in the runtime or global store, depending on the integration scope. When the integration is removed or disabled, APX removes the generated MCP there too.
That gives you the convenience people want from integrations without moving ownership into the wrong layer.
The repo can still keep a clean shared MCP file for team-safe tools. But a plugin that depends on one operator's local setup does not silently rewrite project truth.
This matches the CLI too
The CLI keeps the same idea.
In src/interfaces/cli/commands/mcp.js, write operations default to shared when you are inside an APC project and global outside one. But runtime is still a first-class explicit scope, and APX's own MCP skill docs say to use it for tokens and machine-specific endpoints.
That is the important nuance.
Human-authored MCPs can be shared when they are genuinely repo-safe. Auto-generated MCPs should be more conservative because they are derived from live runtime state.
So APX uses two different defaults for two different jobs:
- manual project intent can go to APC shared scope
- generated integration state stays runtime-local unless it is truly machine-wide
That split keeps convenience from turning into accidental portability.
Bigger lesson
Agent systems get messy when they commit outputs that were only valid as runtime side effects.
APC works best when committed files stay small, reviewable, and broadly true for everyone who clones the repo. APX works best when it handles the messy local part: plugin activation, machine-local files, tokens, and effective MCP resolution.
Auto-registered MCPs sit exactly on that seam.
So the rule should stay simple:
- keep team-safe MCP definitions in
.apc/mcps.json - keep token-bearing or local-path MCPs in APX runtime scope
- let plugin lifecycle update runtime MCP state automatically
- do not let generated local integrations rewrite committed project context
That is how APC stays portable and APX stays practical.
Portable context should describe the project.
Runtime-generated MCP servers should describe the machine currently running it.
Top comments (0)