MCP Catalog Specification

Formal specification of the MCP (Model Context Protocol) server catalog used by @aidokit/mcp-catalog. Defines the data shape, trigger grammar, role-scoping rules, security model, and the full v0.1 catalog.

Field Value
Spec name aidokit MCP Catalog
Spec version 1.0 (draft)
Status Pre-alpha — surface frozen, entries grow over time
Implements @aidokit/mcp-catalog package
Sibling specs adapter-contract.md, stack-pack-contract.md
Last reviewed Pre-publication

Table of contents

  1. Purpose and audience
  2. Conventions
  3. Concepts
  4. Catalog structure
  5. MCPDef type
  6. Supporting types
  7. Trigger grammar
  8. Install spec format
  9. Role scoping rules
  10. Security model
  11. The v0.1 catalog
  12. Custom (non-catalog) MCPs
  13. Catalog evolution
  14. Versioning
  15. Worked example: lookup → suggest → install
  16. Open questions
  17. Appendix A: Trigger evaluation reference
  18. Appendix B: Adding a new catalog entry

1. Purpose and audience

1.1 Purpose

This specification defines:

@aidokit/mcp-catalog is built directly from this spec. Engineers implementing the package use this document as the source of truth for both schema and data.

1.2 Audience

1.3 Non-purpose

This document does NOT specify:


2. Conventions

2.1 RFC 2119 keywords

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, and REQUIRED are interpreted as described in RFC 2119.

2.2 Type syntax

TypeScript syntax is normative for all types.

2.3 ID conventions


3. Concepts

Term Definition
MCP server A Model Context Protocol server providing tools to AI agents
Catalog entry A single MCPDef describing one MCP server
Trigger A predicate against ProjectContext determining whether to suggest
Suggested-for role A role the MCP is appropriate for (used for default scoping)
Security-sensitive An MCP with elevated privileges requiring explicit opt-in
Install spec Per-adapter instructions for registering the MCP with the target CLI
Custom MCP An MCP not in the catalog, added via --custom-url

4. Catalog structure

4.1 The catalog is data

The catalog is a TypeScript const array exported from @aidokit/mcp-catalog:

export const MCP_CATALOG: MCPDef[] = [
  {
    /* entry 1 */
  },
  {
    /* entry 2 */
  },
  // ...
];

Adding an MCP is a one-file edit. There is no plugin discovery, no runtime registration, no dynamic loading. The catalog at runtime equals the catalog at build time.

4.2 Catalog is per-aidokit-version

The catalog ships with @aidokit/mcp-catalog and is versioned with that package. Users on different aidokit versions may see different catalog contents.

4.3 No deprecation, only addition

Catalog entries MUST NOT be removed once published. Entries MAY be marked deprecated: true (see §13). Removing an entry would silently break projects depending on it.


5. MCPDef type

The normative TypeScript type:

import type { RoleName } from '@aidokit/core';

export interface MCPDef {
  /** Globally unique kebab-case identifier. */
  id: string;

  /** Human-readable display name. */
  name: string;

  /** One-line purpose description. */
  purpose: string;

  /** Roles for which this MCP is appropriate by default. */
  suggestedFor: RoleName[];

  /** Predicate expressions determining when to suggest. */
  triggers: string[];

  /** Whether explicit user confirmation is required even on add. */
  securitySensitive: boolean;

  /**
   * Whether this server returns content sourced from untrusted third
   * parties (web pages, search results, rendered DOM, fetched
   * documentation). Agents must quarantine such output — treat as
   * data, never instructions. See `security-model.md` §T18 / §7.12.
   * Defaults to `false`/absent.
   */
  untrustedOutput?: boolean;

  /** Per-adapter installation instructions. */
  install: Record<AdapterName, MCPInstallSpec>;

  /** Whether this entry is deprecated. Suggestion lists exclude deprecated. */
  deprecated?: boolean;

  /** Replacement MCP id, if deprecated. */
  replacedBy?: string;

  /** Project URL for the MCP server (informational). */
  homepage?: string;

  /** Tags for marketplace browsing (informational). */
  tags?: string[];
}

export type AdapterName = 'claude-code' | 'codex' | string;

5.1 Field semantics

Field Required Notes
id yes Permanent; MUST NOT be renamed once published
name yes MAY be updated for clarity
purpose yes Plain prose; under 100 characters
suggestedFor yes MAY be empty for 'never'-triggered MCPs
triggers yes At least one trigger; see §7 for grammar
securitySensitive yes Defaults to false; see §10
untrustedOutput no Defaults to false; see §5.2
install yes MUST include at least one adapter
deprecated no Defaults to false
replacedBy no Required if deprecated: true
homepage no Informational; appears in aido mcp suggest --verbose
tags no Informational; used for filtering

5.2 untrustedOutput — prompt-injection quarantine flag

When true, this server returns content from untrusted third parties (web pages, search results, rendered DOM, fetched documentation). Such content can carry instructions targeted at the consuming agent (prompt-injection). Agents MUST quarantine the output — treat it as data, never as instructions. See security-model.md §T18 / §7.12 for the threat model and declared mitigation.

When aidokit doctor runs against a project that enables an untrustedOutput: true server, it requires the quarantining-untrusted-output skill to be present in the emitted skill set; otherwise it emits an MCP_QUARANTINE_SKILL_MISSING warn finding. The skill is emitted by every first-party adapter by default, so the failure mode is an enabled untrusted server combined with a hand-edited / Starter-minimal skill set.

Currently flagged servers in the catalog: context7, playwright, chrome-devtools. New entries that fetch external content MUST set the flag; new entries that operate only on local data (e.g. beads-mcp, filesystem, postgres) leave it absent.

This is a documentary mitigation; the agent runtime must obey the skill. Strict-tier hook-enforced quarantine is post-v1.0 (see ADR-0019).


6. Supporting types

6.1 MCPInstallSpec

export interface MCPInstallSpec {
  /** Shell command for adapters using CLI-based registration. */
  command?: string;

  /** Configuration block for adapters using config-file registration. */
  configBlock?: {
    /** Path of the config file relative to project root or user home. */
    target: string;
    /** Snippet to merge or insert. */
    content: string;
    /** How to integrate: append, merge, or replace section. */
    mode: 'append' | 'merge' | 'replace-section';
  };

  /** Fallback instructions when neither command nor configBlock applies. */
  manualInstructions?: string;

  /** Whether the install operation requires network access. */
  requiresNetwork: boolean;

  /** Minimum target-CLI version required for this install method. */
  minCliVersion?: string;
}

Rules:

6.2 RoleName

Imported from @aidokit/core. The seven roles defined in adapter-contract.md.

6.3 InstalledMCP

Defined in adapter-contract.md.


7. Trigger grammar

Triggers are strings interpreted by a small predicate evaluator. They are NOT a full expression language.

7.1 Supported triggers

Trigger Evaluates to true when
always Always (every project)
never Never auto-suggested; explicit user add only
beadsEnabled ctx.beadsEnabled === true
brownfield ctx.brownfield === true
stack.has(<id>) ctx.selectedStackPacks.includes(<id>)
stack.hasFrontend Any selected pack declares languages including a frontend lang OR pack id matches known-frontend set
stack.hasBackend Symmetric to stack.hasFrontend
stack.hasDatabase Any selected pack declares a database in extras.databases
stack.language(<lang>) Any selected pack declares <lang> in manifest.languages
detect.githubRemote git remote -v shows a github.com origin
detect.gitlabRemote git remote -v shows a gitlab.com origin
detect.bitbucketRemote git remote -v shows a bitbucket.org origin
os.darwin ctx.os === 'darwin'
os.linux ctx.os === 'linux'
os.win32 ctx.os === 'win32'
conformance.minimum ctx.conformance === 'minimum'
conformance.standard ctx.conformance === 'standard'
conformance.strict ctx.conformance === 'strict'

7.2 Multiple triggers

The triggers array is treated as logical OR. An MCP is suggested if any trigger evaluates to true.

For logical AND, multiple catalog entries with overlapping concerns are NOT the right model. Instead, define triggers conservatively and let users opt out.

7.3 never semantics

A trigger array of ['never'] means: do not auto-suggest under any condition. The MCP can still be installed via aido mcp add <id> if the user explicitly requests it (typically with a confirmation prompt due to securitySensitive: true).

7.4 Frontend / backend stack sets

The CLI maintains internal sets for stack.hasFrontend and stack.hasBackend:

const FRONTEND_STACKS = new Set([
  'react',
  'vue',
  'svelte',
  'angular',
  'next-js',
  'nuxt',
  'remix',
  'sveltekit',
  'solid',
  'qwik',
  'astro',
]);

const BACKEND_STACKS = new Set([
  'express',
  'fastify',
  'nest-js',
  'koa',
  'django',
  'fastapi',
  'flask',
  'rails',
  'sinatra',
  'spring',
  'go-gin',
  'phoenix',
]);

These sets MAY grow as new stack packs ship.

7.5 Forbidden patterns

The trigger grammar MUST NOT support:

If a more complex condition is needed, it indicates the catalog entry should be split into multiple entries.


8. Install spec format

8.1 Command-based install (Claude Code)

install: {
  'claude-code': {
    command: 'claude mcp add context7 -- npx -y @upstash/context7-mcp',
    requiresNetwork: true,
    minCliVersion: '2.1.32',
  },
}

The adapter wraps this in a ShellCommand:

{
  command: 'claude mcp add context7 -- npx -y @upstash/context7-mcp',
  description: 'Register Context7 MCP with Claude Code',
  requiresConfirmation: false,   // false because it's a CLI-side registration, not arbitrary shell
  abortOnFailure: true,
}

8.2 Config-block install (Codex)

install: {
  'codex': {
    configBlock: {
      target: '~/.codex/config.toml',
      content: `
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
`.trim(),
      mode: 'merge',
    },
    requiresNetwork: true,
  },
}

The adapter merges this block into the user's Codex config, idempotently.

8.3 Manual-only install (rare)

install: {
  'some-adapter': {
    manualInstructions: 'Visit https://example.com/setup for installation steps.',
    requiresNetwork: false,
  },
}

The CLI displays the instructions and skips automatic install. Used only when neither command nor config-block applies.

8.4 Adapter-not-supported

If an adapter has no entry in the install record, the CLI MUST refuse to install the MCP on that adapter and report:

✘ MCP 'context7' has no install spec for adapter 'some-adapter'
  Suggest opening an issue against the MCP catalog or the adapter.

9. Role scoping rules

9.1 Default scoping

When a user installs an MCP without specifying roles, the CLI MUST scope it to mcp.suggestedFor exactly.

9.2 User override

aido mcp add <id> --roles <list> overrides the default. The user MAY scope to any subset of valid roles, including roles outside suggestedFor (with a confirmation prompt).

9.3 Empty suggestedFor

For 'never'-triggered MCPs, suggestedFor MAY be empty. In that case, aido mcp add MUST prompt for roles; there is no default.

9.4 No "all roles" auto-suggestion

The CLI MUST NOT default-scope an MCP to all roles. Per-role MCP loading is a core design principle (every role getting every MCP causes context bloat and capability creep).

9.5 Adapter responsibility

The adapter implements the actual scoping (writing mcpServers: into agent frontmatter, for example). The catalog only declares which roles are appropriate; the adapter does the work.


10. Security model

10.1 The securitySensitive flag

An MCP MUST be marked securitySensitive: true when ANY of the following is true:

10.2 Consequences of securitySensitive: true

Consequence Description
Not auto-suggested Even if triggers match, sensitive MCPs are excluded from automatic suggestions during aidokit init
Confirmation on add aido mcp add <id> MUST prompt for explicit confirmation, even with --yes (the --yes exception does not apply to security-sensitive MCPs)
Capability disclosure The confirmation prompt MUST disclose what the MCP can do
Documentation requirement The catalog entry's purpose field MUST mention the elevated capability

10.3 Stack pack MUST NOT suggest sensitive MCPs

Per stack-pack-contract.md §12.3, suggestMCPs() MUST NOT return ids of MCPs marked securitySensitive: true.

10.4 No credential storage in catalog

The catalog MUST NOT include credentials, tokens, or environment-variable values in install specs. Any required credentials MUST be sourced from the user's environment at install time.

10.5 Audit log

Every MCP install MUST be recorded in <projectRoot>/.aido/state.json with:

{
  "installedMCPs": [
    {
      "id": "context7",
      "installedAt": "2026-05-12T14:30:00Z",
      "scopedToRoles": ["researcher", "architect"],
      "installCommand": "claude mcp add context7 -- npx -y @upstash/context7-mcp",
      "userConfirmed": false
    }
  ]
}

userConfirmed: true for securitySensitive installs; false otherwise.


11. The v1.0 catalog

The complete catalog shipping in @aidokit/mcp-catalog. The authoritative source is packages/mcp-catalog/src/catalog.ts; the entries below mirror it.

11.1 context7

{
  id: 'context7',
  name: 'Context7',
  purpose: 'Up-to-date library documentation lookup for agents.',
  suggestedFor: ['researcher', 'architect'],
  triggers: ['always'],
  securitySensitive: false,
  install: {
    'claude-code': {
      command: 'claude mcp add context7 -- npx -y @upstash/context7-mcp',
      requiresNetwork: true,
      minCliVersion: '2.1.32',
    },
    'codex': {
      configBlock: {
        target: '~/.codex/config.toml',
        content: `
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
        `.trim(),
        mode: 'merge',
      },
      requiresNetwork: true,
    },
  },
  homepage: 'https://github.com/upstash/context7',
  tags: ['docs', 'research', 'libraries'],
}

11.2 beads-mcp

{
  id: 'beads-mcp',
  name: 'Beads MCP (cgb)',
  purpose: 'Query the Beads task graph and decision memory from inside agent sessions.',
  suggestedFor: ['planner', 'maintainer'],
  triggers: ['beadsEnabled'],
  securitySensitive: false,
  install: {
    'claude-code': {
      command: 'claude mcp add beads -- bd mcp serve',
      requiresNetwork: false,
      minCliVersion: '2.1.32',
    },
    'codex': {
      configBlock: {
        target: '~/.codex/config.toml',
        content: `
[mcp_servers.beads]
command = "bd"
args = ["mcp", "serve"]
        `.trim(),
        mode: 'merge',
      },
      requiresNetwork: false,
    },
  },
  homepage: 'https://github.com/steveyegge/beads',
  tags: ['tasks', 'memory', 'graph'],
}

11.3 playwright

{
  id: 'playwright',
  name: 'Playwright',
  purpose: 'Browser automation for frontend test review and exploratory testing.',
  suggestedFor: ['tester-reviewer', 'frontend-browser-tester'],
  triggers: ['stack.hasFrontend'],
  securitySensitive: false,
  install: {
    'claude-code': {
      command: 'claude mcp add playwright -- npx -y @playwright/mcp@latest',
      requiresNetwork: true,
      minCliVersion: '2.1.32',
    },
    'codex': {
      configBlock: {
        target: '~/.codex/config.toml',
        content: `
[mcp_servers.playwright]
command = "npx"
args = ["-y", "@playwright/mcp@latest"]
        `.trim(),
        mode: 'merge',
      },
      requiresNetwork: true,
    },
  },
  homepage: 'https://github.com/microsoft/playwright-mcp',
  tags: ['testing', 'browser', 'frontend'],
}

11.4 github (v0.5 addition)

{
  id: 'github',
  name: 'GitHub MCP',
  purpose: 'Read-only access to GitHub repos, issues, and PRs. Write access opt-in.',
  suggestedFor: ['researcher', 'planner'],
  triggers: ['detect.githubRemote'],
  securitySensitive: false,    // read-only by default
  install: {
    'claude-code': {
      command: 'claude mcp add github -- npx -y @modelcontextprotocol/server-github',
      requiresNetwork: true,
      minCliVersion: '2.1.32',
    },
    'codex': {
      configBlock: {
        target: '~/.codex/config.toml',
        content: `
[mcp_servers.github]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
        `.trim(),
        mode: 'merge',
      },
      requiresNetwork: true,
    },
  },
  homepage: 'https://github.com/modelcontextprotocol/servers/tree/main/src/github',
  tags: ['repo', 'issues', 'pr'],
}

11.5 chrome-devtools (v0.5 addition)

{
  id: 'chrome-devtools',
  name: 'Chrome DevTools MCP',
  purpose: 'Advanced browser debugging — DOM inspection, network analysis, performance traces.',
  suggestedFor: ['frontend-browser-tester'],
  triggers: ['stack.hasFrontend'],
  securitySensitive: false,
  install: {
    'claude-code': {
      command: 'claude mcp add chrome-devtools -- npx -y @benjaminr/chrome-devtools-mcp',
      requiresNetwork: true,
      minCliVersion: '2.1.32',
    },
  },
  homepage: 'https://github.com/benjaminr/chrome-devtools-mcp',
  tags: ['browser', 'debugging', 'frontend'],
}

11.6 filesystem (v0.5; security-sensitive)

{
  id: 'filesystem',
  name: 'Filesystem MCP',
  purpose: 'Filesystem operations beyond the agent\'s default toolset. ⚠ Can write/delete files.',
  suggestedFor: [],            // empty — never auto-scoped
  triggers: ['never'],         // explicit opt-in only
  securitySensitive: true,
  install: {
    'claude-code': {
      command: 'claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem .',
      requiresNetwork: true,
      minCliVersion: '2.1.32',
    },
  },
  homepage: 'https://github.com/modelcontextprotocol/servers/tree/main/src/filesystem',
  tags: ['filesystem', 'sensitive'],
}

11.7 postgres (v0.5; security-sensitive)

{
  id: 'postgres',
  name: 'Postgres MCP',
  purpose: 'Natural-language SQL queries and schema inspection against a PostgreSQL database.',
  suggestedFor: ['builder', 'architect'],
  triggers: ['never'],            // explicit opt-in only
  securitySensitive: true,
  install: {
    'claude-code': {
      command: 'claude mcp add postgres -- npx -y @modelcontextprotocol/server-postgres <connection-string>',
    },
  },
}

11.8 sentry (v1.0; security-sensitive)

{
  id: 'sentry',
  name: 'Sentry MCP',
  purpose: 'Error tracking lookup, issue triage, and stack-trace inspection via the Sentry API.',
  suggestedFor: ['builder', 'tester-reviewer', 'maintainer'],
  triggers: ['never'],
  securitySensitive: true,
  install: {
    'claude-code': {
      command: 'claude mcp add sentry -e SENTRY_AUTH_TOKEN=<your-token> -- npx -y @sentry/mcp-server',
    },
  },
}

11.9 notion (v1.0; security-sensitive)

{
  id: 'notion',
  name: 'Notion MCP',
  purpose: 'Read and write access to Notion pages and databases.',
  suggestedFor: ['researcher', 'architect', 'planner'],
  triggers: ['never'],
  securitySensitive: true,
  install: {
    'claude-code': {
      command: 'claude mcp add notion -e OPENAPI_MCP_HEADERS=\'{"Authorization":"Bearer <your-token>","Notion-Version":"2022-06-28"}\' -- npx -y @notionhq/notion-mcp-server',
    },
  },
}

11.10 linear (v1.0; security-sensitive)

{
  id: 'linear',
  name: 'Linear MCP',
  purpose: 'Issue tracking, project management, and roadmap inspection via the Linear API.',
  suggestedFor: ['researcher', 'planner', 'maintainer'],
  triggers: ['never'],
  securitySensitive: true,
  install: {
    'claude-code': {
      command: 'claude mcp add --transport sse linear https://mcp.linear.app/sse',
    },
  },
}

11.11 graphify (v1.0-rc2; security-sensitive; ADR-0015 + ADR-0030)

Fills the v4 researcher agent's cgb slot. Code is parsed locally (tree-sitter, no API calls); only non-code content (docs, PDFs, images, video transcripts) is sent to the user's AI model. Requires Python on the host (per-MCP prereqs; ADR-0008's no-auto-install applies).

Install command smoke-tested (ADR-0030 §3, verified 2026-06-09): the real invocation is uvx --from "graphifyy[mcp]" graphify-mcp (equivalent to upstream's python -m graphify.serve). The earlier uvx graphifyy mcp was wrong — graphifyy is not an executable, there is no mcp subcommand, and the server lives in the optional [mcp] extra. It serves over stdio and defaults graph_path to graphify-out/graph.json (no path argument needed), but serves a pre-built graph — the user must build one first (graphify's /graphify skill or graphify .) or the server exits with "Graph file not found".

{
  id: 'graphify',
  name: 'graphify',
  purpose: 'Code-graph / knowledge-graph MCP for dependency and impact analysis (fills the v4 researcher cgb slot). Code parsed locally; non-code content uses your AI model. Serves a pre-built graphify-out/graph.json — build the graph before enabling.',
  suggestedFor: ['researcher', 'architect'],
  triggers: ['never'],
  securitySensitive: true,
  install: {
    'claude-code': {
      command: 'claude mcp add graphify -- uvx --from "graphifyy[mcp]" graphify-mcp',
    },
  },
  prereqs: ['python>=3.10', 'uv or pipx'],
}

11.12 Catalog summary

ID Since Triggers Sensitive Suggested-for default
context7 v0.1 always researcher, architect
beads-mcp v0.1 beadsEnabled planner, maintainer
playwright v0.1 stack.hasFrontend tester-reviewer, frontend-browser-tester
github v0.5 detect.githubRemote researcher, planner, maintainer
chrome-devtools v0.5 stack.hasFrontend frontend-browser-tester, builder
postgres v0.5 never builder, architect
filesystem v0.5 never (empty — manual scoping)
sentry v1.0 never builder, tester-reviewer, maintainer
notion v1.0 never researcher, architect, planner
linear v1.0 never researcher, planner, maintainer
graphify v1.0 never researcher, architect (manual)

github is securitySensitive: true in catalog.ts (write access via PAT); the §11.4 snippet's older securitySensitive: false comment predates that and is superseded by the code. The codex configBlock install is defined only for the v0.1/v0.5 entries; sentry/notion/linear/graphify are claude-code only until the codex MCP surface stabilises.


12. Custom (non-catalog) MCPs

12.1 Why custom MCPs

Not every MCP a user wants will be in the catalog. The CLI MUST support adding arbitrary MCPs via aido mcp add <id> --custom-url <url>.

12.2 How custom MCPs work

When --custom-url <url> is provided:

  1. The CLI MUST prompt for explicit confirmation regardless of --yes (treated as security-sensitive)
  2. The CLI MUST disclose: install command, declared roles, source URL
  3. The CLI MUST mark the install in state.json with userConfirmed: true and source: 'custom'
  4. Custom MCPs are NOT subject to catalog versioning rules
  5. The CLI MAY emit a MCP_NOT_IN_CATALOG warning during aidokit doctor for custom-sourced MCPs

12.3 Custom MCP shape

{
  id: '<user-provided>',
  name: '<user-provided>',
  purpose: '(custom)',
  suggestedFor: [],
  triggers: ['never'],
  securitySensitive: true,        // always treated as sensitive
  install: {
    '<current-adapter>': {
      command: '<derived-from-url>',
      requiresNetwork: true,
    },
  },
}

12.4 Limitations

Custom MCPs MUST NOT be auto-suggested. Custom MCPs MUST NOT be referenced by stack packs (which reference catalog ids only).


13. Catalog evolution

13.1 Adding entries

Adding a new MCP:

  1. Open an issue or PR against @aidokit/mcp-catalog
  2. Provide:
  3. The new MCPDef entry following §5
  4. Justification for inclusion (use case, demand evidence)
  5. Test coverage (install commands work; trigger evaluation correct)
  6. The core team reviews against the checklist in Appendix B
  7. On acceptance, the entry is added in the next minor release of @aidokit/mcp-catalog

13.2 Modifying entries

Modification Allowed Process
Renaming id Forbidden — id is permanent
Updating name Minor patch
Updating purpose Minor patch (significant rewording → minor bump)
Adding to suggestedFor Minor bump
Removing from suggestedFor Minor bump; emit aidokit doctor warning for affected projects
Adding triggers Minor bump
Removing triggers Minor bump; emit warning
Updating install command Patch bump
Adding adapter to install Minor bump
Removing adapter from install Minor bump; emit warning for affected projects
Changing securitySensitive Major bump (security implications)

13.3 Deprecating entries

Entries are NEVER removed. To deprecate:

  1. Set deprecated: true
  2. Set replacedBy: '<new-id>' if a replacement exists
  3. The CLI excludes deprecated entries from aido mcp suggest
  4. aidokit doctor warns on projects with deprecated MCPs installed
  5. Deprecated entries remain in the catalog indefinitely for compatibility

13.4 Removal exception

The ONLY case where an entry MAY be removed is if the upstream MCP server is taken offline AND no migration path exists. Even then, the entry SHOULD be marked deprecated for at least one minor version before removal.


14. Versioning

14.1 Catalog version = package version

@aidokit/mcp-catalog is independently versioned via semver. The catalog version is the package version.

14.2 Semver rules

14.3 Compatibility with aidokit CLI

The CLI declares a compatible catalog version range. Within that range:


15. Worked example: lookup → suggest → install

15.1 Setup

User runs aidokit init in a project with:

15.2 ProjectContext built

{
  selectedStackPacks: ['node-ts', 'react'],
  adapterName: 'claude-code',
  conformance: 'standard',
  beadsEnabled: true,
  os: 'darwin',
  // ... other fields
}

15.3 Trigger evaluation

The CLI evaluates triggers for every catalog entry:

MCP Triggers Eval result Auto-suggested?
context7 always yes
beads-mcp beadsEnabled yes
playwright stack.hasFrontend (react ✅) yes
github detect.githubRemote yes
chrome-devtools stack.hasFrontend (react ✅) yes
filesystem never no (sensitive)

15.4 Suggestion UI

🔌 Suggested MCP servers

? Select MCPs to install:
  ❯ ◉ Context7         → researcher, architect      (docs lookup)
    ◉ Beads MCP        → planner, maintainer         (task graph)
    ◉ Playwright       → tester-reviewer            (frontend testing)
    ◉ GitHub MCP       → researcher, planner         (repo metadata)
    ◯ Chrome DevTools  → frontend-browser-tester    (advanced browser)

User accepts the first four; deselects Chrome DevTools.

15.5 Install

For each selected MCP, the CLI:

  1. Resolves the catalog entry
  2. Looks up entry.install['claude-code']
  3. Calls adapter.installMCP(entry, suggestedFor, ctx)
  4. Executes returned ShellCommands
  5. Updates role frontmatter with mcpServers: [...]
  6. Appends to state.json

15.6 Resulting state

$ aido mcp list

ID            NAME             SCOPED TO                            INSTALLED
context7      Context7         researcher, architect                2026-05-12
beads-mcp     Beads MCP        planner, maintainer                  2026-05-12
playwright    Playwright       tester-reviewer                      2026-05-12
github        GitHub MCP       researcher, planner                  2026-05-12

16. Open questions

Question Resolution target
Whether to add a requiredPrereqs field listing prereqs each MCP needs (e.g., GitHub MCP needs gh CLI? or just a token?) Spec 1.1
Whether to support MCP-specific configuration (e.g., GitHub token via env var) in the catalog vs leave to user Spec 1.0 freeze
Whether to add a tested-against field per install spec (which CLI versions were verified) Spec 1.1
How to surface MCP version compatibility (e.g., MCP server v2.x vs v3.x) in the catalog Spec 1.1
Whether stack packs may include MCPs in tags that the catalog references back Spec 1.1
How to handle MCPs that need user-specific credentials (e.g., AWS keys) Spec 1.1
Whether to support per-OS install variants (some MCPs install differently on Windows) Spec 1.0 freeze

Appendix A: Trigger evaluation reference

A.1 Pseudocode

function evaluateTrigger(trigger: string, ctx: ProjectContext): boolean {
  if (trigger === 'always') return true;
  if (trigger === 'never') return false;
  if (trigger === 'beadsEnabled') return ctx.beadsEnabled;
  if (trigger === 'brownfield') return ctx.brownfield;

  if (trigger === 'stack.hasFrontend') {
    return ctx.selectedStackPacks.some(id => FRONTEND_STACKS.has(id));
  }
  if (trigger === 'stack.hasBackend') {
    return ctx.selectedStackPacks.some(id => BACKEND_STACKS.has(id));
  }
  if (trigger === 'stack.hasDatabase') {
    return ctx.selectedStackPacks.some(id => /* check pack's extras */);
  }

  let m = trigger.match(/^stack\.has\((.+)\)$/);
  if (m) return ctx.selectedStackPacks.includes(m[1]);

  m = trigger.match(/^stack\.language\((.+)\)$/);
  if (m) return ctx.stack.languages.includes(m[1]);

  if (trigger === 'detect.githubRemote') return ctx.gitRemote?.includes('github.com') ?? false;
  if (trigger === 'detect.gitlabRemote') return ctx.gitRemote?.includes('gitlab.com') ?? false;

  if (trigger === 'os.darwin') return ctx.os === 'darwin';
  if (trigger === 'os.linux')  return ctx.os === 'linux';
  if (trigger === 'os.win32')  return ctx.os === 'win32';

  if (trigger.startsWith('conformance.')) {
    return ctx.conformance === trigger.split('.')[1];
  }

  // Unknown trigger — fail closed
  console.warn(`Unknown trigger: ${trigger}`);
  return false;
}

function shouldSuggest(mcp: MCPDef, ctx: ProjectContext): boolean {
  if (mcp.deprecated) return false;
  if (mcp.securitySensitive) return false;
  return mcp.triggers.some(t => evaluateTrigger(t, ctx));
}

A.2 Test cases

Trigger Context Expected
always any true
never any false
stack.has(react) selectedStackPacks: ['react'] true
stack.has(react) selectedStackPacks: ['vue'] false
stack.hasFrontend selectedStackPacks: ['react'] true
stack.hasFrontend selectedStackPacks: ['node-ts'] false
beadsEnabled beadsEnabled: true true
detect.githubRemote gitRemote: 'https://github.com/acme/myapp.git' true
os.darwin os: 'linux' false
conformance.strict conformance: 'standard' false
unknown.trigger any false (warns)

Appendix B: Adding a new catalog entry

Checklist for proposing a new MCP entry:


See also