Skip to content

feat: MCP tool profiles + per-profile server instructions + tools/list pagination — ~60 tools shipped to every session #177

Closed

Description

@cdeust

Context

Parity pass against DeusData/codebase-memory-mcp (HEAD 97ce23f, v0.9.0), tracked by cdeust/enterprise-backlog#26. Companion to #170 (tabular response encoding), which reduces bytes per response; this issue reduces bytes per session.

CBM ships three tool profiles (src/mcp/mcp.h:97-103, src/mcp/mcp.c:730-757), selected by CLI flag:

Profile Tools Set
ALL 15 everything
ANALYSIS 11 search_graph, query_graph, trace_path, get_code_snippet, get_graph_schema, get_architecture, search_code, list_projects, index_status, check_index_coverage, detect_changes
SCOUT 7 search_graph, trace_path, get_code_snippet, get_architecture, list_projects, index_status, check_index_coverage

Three things follow from the profile, not just the tool list:

  • initialize returns different instructions per profile (mcp.c:1192-1199) — the server describes itself in the shape it was started in.
  • tools/list is cursor-paginated over the allowed set (mcp.c:821-866, nextCursor, MCP_TOOLS_PAGE_SIZE), with the cursor clamped to the profile's count.
  • Write and HTTP surfaces are gated by profile (cbm_mcp_tool_profile_allows_http), so a read-only profile is enforced, not merely advertised.

The gap

Cortex registers ~60 MCP tools, all of them, to every client, on every session — the largest fixed token cost in the ecosystem, paid before the user types anything. There is no profile mechanism (grep -r "tool_profile\|TOOL_PROFILE" over Cortex/ outside .venv returns nothing), no tools/list pagination, and one set of server instructions regardless of how the server was started.

Most sessions use a small fraction of that surface. A session doing recall/onboarding never calls wiki_migrate, wiki_purge, rebuild_profiles, import_sessions, backfill_memories or forget — but pays for their schemas anyway, and the model must discriminate the one it wants from sixty.

For comparison, cdeust/automatised-pipeline already ships ToolProfile::{Core, Full} (src/tool_profile.rs:44). Cortex has four times AP's tool count and none of the mechanism.

Acceptance criteria

  1. A profile enum with named, documented sets. Derive the membership from measured session usage (the telemetry already exists — get_telemetry), not from intuition; the derivation is quoted in the PR.
  2. Profile selected at server start (CLI flag and/or plugin config), defaulting to the profile that serves the common session. The default is a behaviour change: it goes in the CHANGELOG (§13 H4) and the plugin manifest.
  3. initialize returns profile-specific instructions.
  4. tools/list supports cursor pagination with nextCursor, clamped to the profile's allowed count. Absent cursor returns the full allowed set — CBM's behaviour, and the one that cannot break existing clients (mcp.c:924-932).
  5. Destructive tools are gated, not merely hidden. forget, wiki_purge, wiki_migrate, and delete-class handlers must be rejected when the active profile excludes them, with a test asserting the rejection — hiding a tool from tools/list while still executing it on call is a security hole, not a token optimization.
  6. Measured before/after: tokens in the initialize + tools/list exchange per profile, committed as a benchmark (§3.2 / §8 — no unsourced numbers).
  7. Every arm asserted (§13 A3): tool allowed, tool excluded-and-called, unknown profile name, cursor beyond the end, malformed cursor.

Non-goals

Removing tools. Every current tool stays reachable under full. §1.2 (Open/Closed): adding a tool must not require editing profile membership in more than one place.

Definition of Done

Completion Ledger (§13.2), one row per profile × per arm in criterion 7, plus the measurement from criterion 6. A profile whose membership is asserted by no test is an unmet clause.

Activity

  1. added a commit that references this issue on Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions