Skip to content

feat(cli): substitute ${COMMONLY_AGENT_TOKEN} / ${COMMONLY_API_URL} in MCP config - #238

Merged
samxu01 merged 1 commit into
mainfrom
feat/cli-mcp-env-substitution
Apr 27, 2026
Merged

feat(cli): substitute ${COMMONLY_AGENT_TOKEN} / ${COMMONLY_API_URL} in MCP config#238
samxu01 merged 1 commit into
mainfrom
feat/cli-mcp-env-substitution

Conversation

@samxu01

@samxu01 samxu01 commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Lets users keep their checked-in env files free of secrets. The wrapper substitutes the agent's runtime token + instance URL into the generated MCP config at spawn time, from values already on hand (the saved token record).

Why this is needed. Surfaced during the 2026-04-17 cross-agent demo validation: every env spec referencing commonly-mcp had to be hand-rewritten with the agent's cm_agent_* token after attach, because the token is minted at attach time and only known to the wrapper. Without substitution, a shared/checked-in env file is unusable across agents.

Recognised placeholders (substituted everywhere a string appears in the MCP config — env values, command args, and url fields):

Placeholder Substituted with
${COMMONLY_AGENT_TOKEN} per-(agent, pod) cm_agent_* runtime token
${COMMONLY_API_URL} instance URL the agent is attached to
${COMMONLY_INSTANCE_URL} alias for ${COMMONLY_API_URL}

Properties:

  • One-pass, literal substitution. No nested expansion, no shell quoting.
  • Unknown ${COMMONLY_*} placeholders are left intact so typos surface as runtime MCP errors, not silent empty strings.
  • Falsy ctx values are also no-ops (placeholder preserved) so users can diagnose missing context.

Plumbing: performRun now passes runtimeToken + instanceUrl into the adapter.spawn ctx; claude adapter passes them through to writeMcpConfig.

Example

// env.json — checked into source control, no secrets
{
  "mcp": [{
    "name": "commonly",
    "transport": "stdio",
    "command": ["commonly-mcp"],
    "env": {
      "COMMONLY_API_URL":     "${COMMONLY_API_URL}",
      "COMMONLY_AGENT_TOKEN": "${COMMONLY_AGENT_TOKEN}",
      "COMMONLY_DEFAULT_POD": "<your-pod-id>"
    }
  }]
}

After commonly agent attach claude --env env.json --pod <id>, the same file works for every attached agent without manual editing.

Test plan

  • cd cli && npm test131/133 passing (6 new: 5 substitution + 1 ctx plumbing; 2 skipped Linux-only)
  • Self-review against docs/REVIEW.md
  • Live-validated end-to-end on commonly-dev with placeholder env (no hardcoded tokens)

Out of scope (deferred)

🤖 Generated with Claude Code

… in MCP config

Lets users keep their checked-in env files free of secrets — the
wrapper substitutes the runtime token + instance URL at spawn time
from values it already has on hand (the saved token record).

Surfaced during the 2026-04-17 cross-agent demo: every spec referencing
commonly-mcp had to be hand-rewritten with the agent's runtime token
after attach, because the token is minted at attach time and only known
to the wrapper.

Recognised placeholders (substituted everywhere a string appears in the
MCP config — env values, command args, and url fields):
  \${COMMONLY_AGENT_TOKEN}   — per-(agent, pod) cm_agent_* runtime token
  \${COMMONLY_API_URL}       — instance URL the agent is attached to
  \${COMMONLY_INSTANCE_URL}  — alias for COMMONLY_API_URL

One-pass + literal substitution; no nested expansion, no shell quoting.
Unknown \${COMMONLY_*} placeholders are left intact so typos surface as
runtime MCP errors, not silent empty strings. Falsy ctx values are also
no-ops (placeholder preserved) so users can diagnose missing context.

Plumbing: performRun now passes runtimeToken + instanceUrl into the
adapter.spawn ctx; claude adapter passes them through to writeMcpConfig.

131/133 cli tests pass (6 new: 5 substitution + 1 ctx plumbing assertion;
2 skipped Linux-only paths).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@samxu01
samxu01 merged commit be90aaa into main Apr 27, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant