Skip to content

github: templates never render .mcp.json.template — declared MCP servers are silently absent #2007

Description

@AndriiPasternak31

Summary

docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md:90-92 states the contract:

3. .mcp.json.template (Required if using MCP servers)

MCP server configuration with credential placeholders. Trinity replaces ${VAR} with actual values from the credential store.

For a github: template, Trinity does not. Nothing renders the file, so a template that follows the published guide ships with no MCP servers configured at all — silently, with no warning and no error.

Why nothing renders it

Grepping every reference to .mcp.json.template across src/ and docker/, there is exactly one renderer: docker/base-image/agent_server/routers/credentials.py:119, behind POST /api/credentials/update — which has zero callers repo-wide (#2008).

The other paths don't cover it:

  • template_service.generate_credential_files reads <template_dir>/.mcp.json, not .mcp.json.template (template_service.py:1814) — and is local:-only anyway (crud.py:1145 gates on template_data, which only the local: branch populates)
  • startup.sh:381 copies /generated-creds/.mcp.json only when it exists — empty on the github: path
  • No platform system prompt instructs the agent to render it itself (platform_prompt_service.py has no .mcp.json reference)

So the only writer of /home/developer/.mcp.json on a github: agent is inject_trinity_mcp_if_configured() (trinity_mcp.py:66-77), which creates the file from scratch when absent and adds only the trinity entry.

Observed on the seeded default agent

Abilityai/cornelius is auto-provisioned on every fresh install (trinity-enterprise#107, cornelius_agent_service.py). It ships .mcp.json.template and no .mcp.json (HTTP 404 on the latter, confirmed against main), declaring three servers:

"mermaid-diagram": { "command": "npx", "args": ["-y", "@peng-shawn/mermaid-mcp-server"] },
"aistudio":        { "command": "npx", "args": ["-y", "aistudio-mcp-server"],
                     "env": { "GEMINI_API_KEY": "${GEMINI_API_KEY}" } },
"ebook-mcp":       { "command": "${UV_PATH:-uv}",
                     "args": ["--directory", "${EBOOK_MCP_PATH:-/opt/mcp/ebook-mcp}", "run", "ebook-mcp"] }

Its .trinity/setup.sh doesn't render the template either (Brain Orb seed + search daemon). So a freshly-seeded Cornelius gets {"mcpServers":{"trinity":{...}}} and all three are absent.

Two things that need fixing alongside

1. uv is not a legal Trinity MCP command. mcp_validator.COMMAND_ALLOWLIST (mcp_validator.py:132) is {npx, uvx, python, python3, node, bun, deno, docker}. Executed:

REJECTED  perfectly substituted (uv + real path)
          -> Server 'ebook-mcp': command 'uv' not in allowlist

So ebook-mcp stays illegal even with rendering fixed. Cornelius's own MCP-SETUP.md documents uvx ebook-mcp, which would pass — the template is simply wrong. That half is an upstream fix in Abilityai/cornelius, not here.

2. The base image ships no uv/uvx and no /opt/mcp (docker/base-image/Dockerfile — the only uv match is the uvicorn Python package). A rendered ebook-mcp would still fail to exec. Cornelius's MCP-SETUP.md calls these servers optional, so "declare it and let it fail" may be acceptable — but it should be a decision, not an accident.

The decision this issue needs

Rendering ${VAR} into args or command collides with validate_mcp_config, which rejects ${VAR} in args outright (bare $ is a shell metachar; args are never ref-stripped) and requires command to be a literal allowlist entry. Executed:

REJECTED  plain ${VAR} in args   -> args[1] contains shell metacharacters
ACCEPTED  plain ${VAR} in env    <- the only form the validator accepts

So the honest options are:

  • (a) render ${VAR} in env only — matches the validator, matches the guide's own example (which only shows env placeholders), and covers aistudio; or
  • (b) widen the validator to accept refs in args, which is a security-contract change and needs its own review.

I'd take (a) and update the guide to say env only.

Acceptance criteria

  • A github: template's .mcp.json.template is rendered into .mcp.json at agent creation, with the credential store's values
  • Rendered output passes validate_mcp_config (or the substitution is confined to the fields the validator accepts)
  • Placeholder forms the validator rejects are refused with a named error, never silently blanked or emitted (shares the contract with generate_credential_files: .mcp.json placeholder handling contradicts the platform validator (${VAR:-default} blanked, command unsubstituted, output never validated) #1929)
  • TRINITY_COMPATIBLE_AGENT_GUIDE.md:90-92 matches what the code actually does, in both directions
  • A freshly-seeded Cornelius shows its declared servers in ~/.mcp.json, or a documented reason why a given server is withheld
  • Upstream: Abilityai/cornelius .mcp.json.template uses uvx instead of uvnot yet filed in that repo; needs an issue there before this box can be ticked

Related

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions