DEV Community

Cover image for APX MCP Resolution Should Start With Runtime, Not Global Defaults

APX MCP Resolution Should Start With Runtime, Not Global Defaults

APX MCP Resolution Should Start With Runtime, Not Global Defaults

When one MCP name exists in more than one place, APX should not guess.

It should prefer the most local, most operationally specific definition first.

That is why APX resolves MCP servers in this order: runtime, then shared, then foreign IDE configs, then global last.

This is not a small storage detail. It is one of the practical boundaries between APC and APX.

APC is the portable context layer. It keeps committed project context such as AGENTS.md, .apc/agents/, .apc/skills/, and .apc/mcps.json.

APX is the daily-use runtime and tooling layer. It decides what actually runs on one machine: CLI behavior, daemon state, local sessions, message logs, engines, MCP discovery, and runtime files under ~/.apx/.

MCP resolution belongs on the APX side.

Why runtime should win first

The core rule is documented directly in apx/src/core/mcp/sources.js.

That file defines three APX-owned writable scopes:

  • runtime: ~/.apx/projects/<apxId>/mcps.json
  • apc / shared: .apc/mcps.json
  • global: ~/.apx/mcps.json

It also defines the merge priority by name conflict:

  1. runtime
  2. apc
  3. foreign IDE configs such as Claude, Cursor, VS Code, Roo, and Gemini
  4. global

The code comment explains the reason in plain terms: per-project local secrets should win.

That is correct.

If the same MCP server name appears in both .apc/mcps.json and a machine-local runtime file, the runtime copy is usually the one that knows the real endpoint, token, or local command path for this machine right now.

A global fallback should not silently override that.

What APC should keep

APC should keep team-safe, durable MCP definitions.

For example, a repository can commit a shared MCP entry that tells collaborators which server name the project expects, whether it is stdio or HTTP, and which command shape or URL pattern belongs to the project.

That is project context.

It is reviewable, portable, and appropriate for .apc/mcps.json.

But APC should not try to own the last-mile operational truth for each laptop.

A token-bearing HTTP header, a user-specific local path, or a localhost port forwarded by one developer is not portable context. That belongs to APX runtime state.

What APX should keep

APX should keep the effective local override.

The same sources.js file writes runtime MCP state under ~/.apx/projects/<apxId>/mcps.json, and writeRuntimeMcps() protects that file with chmod 0600.

That is a strong signal about intended ownership.

Runtime scope is not just "another place to store MCPs." It is the place for MCP definitions that may carry secrets or machine-local details and must never leak into the repository.

That also matches the repo guidance in apx/AGENTS.md: tokens belong in runtime scope, not in committed APC files.

Why global should lose last

A machine-wide default is useful, but it should be a fallback, not a winner.

Suppose you use a github MCP server across many projects. A global definition in ~/.apx/mcps.json can save setup time.

But if one repository needs a different endpoint, different headers, or a safer project-local override, that repo should not have to fight the machine default.

Putting global last solves that.

The project can keep a shared .apc/mcps.json entry for collaborators, and one developer can still place a runtime override on top without changing committed project truth.

That is the useful split:

  • APC describes shared project intent.
  • APX resolves local operational reality.

The CLI reflects the same rule

The CLI in apx/src/interfaces/cli/commands/mcp.js exposes shared, runtime, global, and all as explicit scopes.

Read operations can inspect them all. Write operations default differently depending on context, but runtime remains first-class because APX expects real setups to need local overrides.

That matters for practical work.

If a team commits a safe shared MCP definition and one operator needs a secret-bearing variant, that operator can add it in runtime scope and APX will resolve that one first. No repo churn. No fake portability. No accidental secret commit.

Bigger lesson

Portable context becomes fragile when it tries to own machine-local execution details.

APC stays useful when committed files remain small, durable, and broadly true for anyone who clones the repo.

APX stays useful when it handles the messy part honestly: merge order, local secrets, active machine paths, and effective runtime resolution.

MCP resolution is where that philosophy becomes concrete.

So the rule should stay simple:

  • keep shared project-safe MCP definitions in APC
  • keep secret or machine-local overrides in APX runtime scope
  • let global act as fallback, not authority
  • resolve runtime first when names conflict

That keeps APC portable.

And it keeps APX trustworthy in daily use.

Top comments (0)