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
Related
Summary
docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md:90-92states the contract: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.templateacrosssrc/anddocker/, there is exactly one renderer:docker/base-image/agent_server/routers/credentials.py:119, behindPOST /api/credentials/update— which has zero callers repo-wide (#2008).The other paths don't cover it:
template_service.generate_credential_filesreads<template_dir>/.mcp.json, not.mcp.json.template(template_service.py:1814) — and islocal:-only anyway (crud.py:1145gates ontemplate_data, which only thelocal:branch populates)startup.sh:381copies/generated-creds/.mcp.jsononly when it exists — empty on thegithub:pathplatform_prompt_service.pyhas no.mcp.jsonreference)So the only writer of
/home/developer/.mcp.jsonon agithub:agent isinject_trinity_mcp_if_configured()(trinity_mcp.py:66-77), which creates the file from scratch when absent and adds only thetrinityentry.Observed on the seeded default agent
Abilityai/corneliusis auto-provisioned on every fresh install (trinity-enterprise#107,cornelius_agent_service.py). It ships.mcp.json.templateand no.mcp.json(HTTP 404 on the latter, confirmed againstmain), declaring three servers:Its
.trinity/setup.shdoesn'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.
uvis not a legal Trinity MCP command.mcp_validator.COMMAND_ALLOWLIST(mcp_validator.py:132) is{npx, uvx, python, python3, node, bun, deno, docker}. Executed:So
ebook-mcpstays illegal even with rendering fixed. Cornelius's ownMCP-SETUP.mddocumentsuvx ebook-mcp, which would pass — the template is simply wrong. That half is an upstream fix inAbilityai/cornelius, not here.2. The base image ships no
uv/uvxand no/opt/mcp(docker/base-image/Dockerfile— the onlyuvmatch is theuvicornPython package). A renderedebook-mcpwould still fail to exec. Cornelius'sMCP-SETUP.mdcalls 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}intoargsorcommandcollides withvalidate_mcp_config, which rejects${VAR}inargsoutright (bare$is a shell metachar; args are never ref-stripped) and requirescommandto be a literal allowlist entry. Executed:So the honest options are:
${VAR}inenvonly — matches the validator, matches the guide's own example (which only showsenvplaceholders), and coversaistudio; orargs, which is a security-contract change and needs its own review.I'd take (a) and update the guide to say
envonly.Acceptance criteria
github:template's.mcp.json.templateis rendered into.mcp.jsonat agent creation, with the credential store's valuesvalidate_mcp_config(or the substitution is confined to the fields the validator accepts).mcp.jsonplaceholder handling contradicts the platform validator (${VAR:-default}blanked,commandunsubstituted, output never validated) #1929)TRINITY_COMPATIBLE_AGENT_GUIDE.md:90-92matches what the code actually does, in both directions~/.mcp.json, or a documented reason why a given server is withheldAbilityai/cornelius.mcp.json.templateusesuvxinstead ofuv— not yet filed in that repo; needs an issue there before this box can be tickedRelated
.mcp.jsonplaceholder handling contradicts the platform validator (${VAR:-default}blanked,commandunsubstituted, output never validated) #1929 — the sibling engine,local:-only, its own contract problemPOST /api/credentials/updatehas no callers but is named as the sanctioned MCP-config path #2008 —/api/credentials/update, the only code that implements this contract today, and it is unreachable.mcp.jsonfailed validation, and the create path consumes it #2006 — deploy-local residue, the third.mcp.jsonownership gap