Expand description
Starter MCP Servers catalog seed: preloads a small set of curated global,
credential-free MCP servers (db_mcp_servers, the v1 standalone catalog)
on fresh install.
Mirrors skill_seed.rs exactly, for the same reasons documented there:
the actual “run exactly once, ever” gating lives in
migrations::m0016_seed_starter_mcp_servers, tracked in the channel’s
db_migrations table — NOT in this module, and NOT gated on “is the
catalog currently empty” (that gate can’t distinguish “never seeded” from
“seeded then the user deleted every starter server on purpose”, which
would silently resurrect the defaults on the next restart after a full
deletion — see m0015_seed_starter_skills.rs’s history, reagent P2 on
PR #2141 round 2, for why this shape was chosen over a simpler one). This
module exposes only the pure insert logic; the migration owns invocation.
Only credential-free, fully local servers belong in this manifest — see
docs/specs/SPEC_ARMORY_MCP_SERVER_DEFAULT_SEED_CATALOG_2026_07_13.md §2:
every is_global MCP server is auto-injected into every agent’s
.mcp.json at launch with no per-agent opt-in, so a seeded row needing an
API key or OAuth token would break every agent’s launch by default. The
Filesystem reference server is deliberately NOT included despite being
credential-free — it requires an allowlisted directory as a CLI arg with
no environment-agnostic default (spec §9 open question 3); it can be
added once that’s resolved, either by computing a per-agent default at
config-build time or shipping it with an explicit prereq the user fills
in via the existing catalog-picker mechanism instead.
Ids are deterministic, not randomly minted — same reasoning as
skill_seed.rs::starter_skill_id, mirrored here for MCP servers via
entry.name (there is no separate slug field for a server the way a
skill has trigger; name already plays that role — it’s the catalog
key mcp_server_upsert_unique_global enforces uniqueness on). See Phase 1
of SPEC_DURABLE_BINDINGS_2026_09_10.md.
Structs§
- Starter
McpServer 🔒 - One entry in the embedded starter-mcp-servers manifest.
configis a raw JSON object here (command/args/env) and gets re-serialized to a string to matchMcpServer.config’s storage shape.
Constants§
- STARTER_
MCP_ 🔒SERVERS_ JSON - The embedded starter-mcp-servers manifest JSON. Content is authored
externally and must not be edited here — see
crates/srv/src/config/starter-mcp-servers.json.
Functions§
- any_
starter_ 🔒mcp_ server_ name_ exists - True if any global MCP server whose name matches a starter entry’s name
already exists — i.e. this channel already effectively has the starter
set (or a name collision with it). The caller
(
migrations::m0016_seed_starter_mcp_servers) uses this to skip seeding entirely rather than attempting an insert that would collide onmcp_server_upsert_unique_global’s name-uniqueness check and permanently fail the migration on every subsequent boot — same self-healskill_seed.rs::any_starter_skill_name_existsprovides (reagent P1, PR #2144). - reject_
duplicate_ 🔒names - Guard against a manifest-authoring mistake: two entries sharing a
name. Mirrorsskill_seed::reject_duplicate_triggersexactly — see its doc comment for the full failure mode this closes (reagent P2, PR #3175).namehere plays the roletriggerplays for skills: it is both the stable keystarter_mcp_server_idderives from AND the fieldmcp_server_upsert_unique_global’s own duplicate check is keyed on, which is exactly the combination that turned “id collision” into “duplicate-check bypass” for skills. - seed_
starter_ 🔒mcp_ servers - Parse the embedded manifest and insert every entry as a global MCP server
via the validated
mcp_server_upsert_unique_globalpath. Does NOT check whether the catalog is already populated — the caller (migrations::m0016_seed_starter_mcp_servers) owns run-once gating viadb_migrationstracking, not catalog contents. Exposed atpub(crate)so the migration and tests can call it directly. - starter_
mcp_ 🔒server_ id - Deterministic row id for a starter MCP server, derived from its
name. Seeskill_seed::starter_skill_id’s doc comment for the full reasoning — this is the identical derivation keyed on the server’s catalog name instead of a skill’s trigger, in its own, distinct namespace so a skill and an MCP server that happened to share a stable-key string could never collide on id.