vantage-peers-mcp 2.19.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,636 +1,237 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased] — grant-aware mission/mandate visibility + bind JWT audience
3
+ ## [3.0.0] — 2026-10-01
4
4
 
5
- ### Fixed
5
+ Customer-facing summary of every `mcp-server/` change since 2.19.0 (commit `f718dd3`). Earlier releases are listed below.
6
+
7
+ ### Breaking
6
8
 
7
- - **`check_messages` now renders `stuckInProgress` / `peersStuckOnYou` from the envelope (Day-156 reader-first; Eta REVISE PR #1218 dual-shape).** Missing / null / undefined keys default via `asCappedStuckList` so old Convex prod cannot throw `.length`. Accepts a raw `{taskId,title,age}[]` (already-deployed MCP) **or** `{entries,total,truncated}`. Empty unread + a stuck SIGNAL (`entries.length > 0` OR `truncated === true`) surfaces the block, never `"No new messages."` / Vide — a truncated empty list is a signal, not rest. `messages` / `staleInProgress` are unchanged; `pendingOnYou` is not revived.
9
+ - The `components` registry (six tools: `list_components`, `register_component`, `get_component`, `update_component`, `delete_component`, `search_components`) is removed, together with its entry in the `vantage-peers-mcp/api` type exports. These tools were not advertised to clients in 2.19.0.
10
+ - Two legacy credential types are no longer accepted: tokens from the retired dynamic-registration token store, and legacy internal tenant bearers. A request presenting either is refused with HTTP 401. OAuth access tokens issued by `/token` and Clerk session tokens are unaffected.
8
11
 
9
12
  ### Added
10
13
 
11
- - **`fail_task` tool — the third task terminal state (`failed`), distinct from `done`/`cancelled` (mission `k576mw0smxeqsg9wp7957njfsn8crey4`, commit `8c70e18`).** New tool, mandatory `failureNote`, output schema `{taskId, status: "failed"}`. `update_task`'s `updateTaskStatusSchema` now excludes both `"blocked"` and `"failed"` (client refused at the tool-input layer, mirroring the server-side `FAILED_VIA_UPDATE_REFUSED` gate). `taskStatusValues`/`taskStatusFilterSchema` gained `"failed"`. `createTaskOutputSchema.status` now reuses the canonical `taskStatusValues` array (was hand-typed and missing `"cancelled"`/`"failed"`). A blocker task reaching `failed` does NOT auto-release its waiters — see `convex`-side CHANGELOG for the reciprocal-unblock fix.
12
- - **`block_task` gained an optional `blockedCause` arg** (`"peer_task" | "human" | "authorisation" | "other"`) naming WHAT the task is waiting on. Backward-compatible: optional, defaults server-side to `"other"`. `block_task`'s output JSON now always carries `blockedCause`.
14
+ - `correct_task_segment`: narrow a recorded work span to its real boundaries, once, with a mandatory reason. The original span is kept for audit.
15
+ - Now available to clients: `whoami` (returns the identity attached to your own credential: agent name, scope profile, namespaces) and `generate_upload_url` (an upload URL for your own organisation's storage, used before `store_document_chunked`).
16
+ - Now available to clients: `fail_task` (a third terminal state, distinct from done and cancelled), `pause_task` and `resume_task` (stop and restart a task's work clock without ending it).
17
+ - Now available to clients: the fix-pattern tools `create_fix_pattern`, `get_fix_pattern`, `list_fix_patterns`, `search_fix_patterns`, `add_fix_attempt`, `validate_fix` and `link_issue_to_pattern`.
18
+ - `check_messages` reports how many in-progress tasks are stuck past the configured threshold on an open work segment, alongside the stuck list.
19
+ - `/health` publishes the agent-identity mode, where that mode comes from, and how many calls were served on a typed agent name without a credential.
13
20
 
14
- ### Security
21
+ ### Security and fixes
15
22
 
16
- - **Consult per-row grants on missions, mandates, and tasks (task `k174y9ra7pp8zed3bcczk6xaed8cpynp`, `@vantageos/cloud-identity` 0.5.0).** The shared scope filter was structurally blind to every per-row grant: a scoped identity named on a mission (`pilot`/`agents`), a mandate (`requestedBy`/`fulfilledBy`), or a task (`assignedTo`) could not read the row it was named on — the multi-org separation failing at exactly what it is sold for. Upgraded the dependency `^0.3.0` → `^0.5.0` (the old caret stopped at the 0.3 minor and never admitted 0.4.0) and passed `grantFields` at the read sites: `get_mission` → `["pilot","agents"]`; `list_mandates`/`get_mandate` → `["requestedBy","fulfilledBy"]`; `get_task`/`list_tasks_by_mission`/`search_tasks_by_keyword` → `["assignedTo"]` (mirrors `convex/tasks.ts` L88-89's `createdBy===caller || assignedTo===caller` OR), replacing the two-sided `createdBy`-remap workaround (the local-variant pattern the shared filter now subsumes). Fail-closed unchanged: a table declaring no grant fields behaves byte-identically to before. Eta REVISE on the first pass of PR #1204 (the original test suite called the package predicate directly instead of the real handlers — litmus test false); rewritten to drive `registerTools()` end-to-end via the same duck-typed McpServer/Convex harness `test/scope-aware-filter-wave-c1.test.ts` uses, RED→GREEN reproduced against the real `get_task`/`search_tasks_by_keyword` call sites. `briefingNotes.participants` stays deferred (task `k175ga65p654z200ydj7s8qv5s8cnxfc`); `recurringTasks.assignedTo`, `missionTemplates.steps[].assignedTo`, `businessUnits.coreTeam.agents`, and `diaries.orchestrator` remain unwired (out of this PR's scope — see PR #1204 `CLASS:` block). TDD strict — GREEN 13/13 under scoped non-creator identity `alice`; full mcp-server suite 1087 passed / 12 skipped, build clean + boot-check 4/4.
23
+ - Agents act under the credential they present (`x-vantage-agent-credential`), not under a name typed into a tool argument. Names are compared after case and Unicode normalisation; accented and unaccented names stay distinct.
24
+ - A message's sender is checked against the verified caller: a caller from another organisation can no longer sign as one of your agents.
25
+ - `list_peers` surfaces a backend refusal as an explicit error instead of an empty list.
26
+ - A signed-in user with no organisation yet receives a typed refusal instead of the "invalid token" answer. An agent credential that does not resolve is refused as `AGENT_CREDENTIAL_INVALID` (HTTP 401), distinct from a lookup failure.
27
+ - Every refresh now returns a new refresh token, so a seat that keeps refreshing no longer expires at 30 days.
28
+ - Seat names are canonical and unique across organisations.
29
+ - The server no longer passes a privileged secret to the backend as a function argument; the backend authorises it by identity.
17
30
 
31
+ ## Changes between 2.18.0 and 3.0.0 (some shipped in 2.19.0)
18
32
 
33
+ ### Added
19
34
 
20
- - **Bind the `audience` claim where the Clerk session JWT is verified (MCP server standard Critical Rule 14, element 5).** `tryVerifyClerkJwt` (`src/auth.ts`) verified the token with `issuer` bound but not `audience`, so a token minted for one audience/client was accepted on another — cross-tenant / cross-resource replay (the single exploitable finding of the mcp-doctor conformance audit, `projects/vantage-peers/audits/mcp-server-conformance-audit.md`). Fix binds `audience: CLERK_JWT_AUDIENCE` (env, default `"convex"`) at the single `jwtVerify` site — the value mirrors `convex/auth.config.ts` `applicationID: "convex"` and the `CLERK_JWT_TEMPLATE` default, and the verified token is forwarded verbatim to Convex which already requires `aud === "convex"`, so no correctly-minted production token is rejected. Minimal by design: only the one verification site; the auth-layer/DCR/PRM flow and the three other (non-exploitable) audit findings are untouched. TDD strict — RED both poles (wrong-audience refused / correct-audience accepted / no-`aud` refused) reproduced firsthand, GREEN 3/3; full suite 1074 passed / 0 failed, `tsc --noEmit` exit 0.
35
+ - `fail_task`: a third terminal task state, `failed`, distinct from `done` and `cancelled`, with a mandatory failure note. `update_task` cannot set `failed` or `blocked`; use `fail_task` and `block_task`.
36
+ - `block_task` accepts an optional `blockedCause` (`peer_task`, `human`, `authorisation` or `other`, default `other`) naming what the task is waiting on, and always returns it.
21
37
 
22
38
  ### Fixed
23
39
 
24
- - **Regenerate `mcp-server/bun.lock` so the grant-aware read actually reaches the customer-facing server (task `k170n5az8xt95gg0b6thrzgej98crnw3`).** PR #1204 (`f51bd709`) bumped `mcp-server/package.json` `@vantageos/cloud-identity` `^0.3.0` → `^0.5.0` and the root `bun.lock`, but never regenerated `mcp-server/bun.lock` — which stayed pinned at `@vantageos/cloud-identity@0.3.0`. The Railway build runs `bun install --frozen-lockfile`, which refuses a lockfile that would have to change (`error: lockfile had changes, but lockfile is frozen`), so the deploy failed **silently**: the previous container kept serving and nothing disagreed. Result: the grant-aware filter was ACTIVE on Convex but INACTIVE on the MCP server — the path a customer actually uses. Repair regenerates the lockfile **in an isolated tree** (never in the workspace, which would resolve against the workspace and reproduce the locally-passing / Railway-failing file), touching `mcp-server/bun.lock` only; the manifest is untouched (dependency scope did not move). The drift named: `@vantageos/cloud-identity` `0.3.0` → `0.5.0`. Proven pair, both poles firsthand: RED = stale lockfile + `^0.5.0` manifest under `--frozen-lockfile` → exit 1 (the exact Railway message); GREEN = repaired lockfile under `--frozen-lockfile` → exit 0. Activation (separate from merge) is a successful Railway deploy read back from the platform, then a scoped-identity probe of the grant filter — never the master credential, which bypasses the very check.
40
+ - `list_peers` and `list_mandates` no longer turn a backend refusal into an empty list. A refusal is returned as an error result that starts with `REFUSED (RBAC_DENIED)` and names the tool; a genuinely empty result is still `[]`.
41
+ - `check_messages` shows how many in-progress tasks are stuck past the configured threshold, and renders the stuck lists correctly against both older and newer backends.
42
+
43
+ ### Security
44
+
45
+ - An identity named on a mission (pilot or agent), a mandate (requester or fulfiller) or a task (assignee) can read that record, while still being unable to read records it is not named on.
46
+ - Clerk session tokens are checked for the expected audience (`CLERK_JWT_AUDIENCE`, default `convex`), so a token minted for another audience is refused.
25
47
 
26
48
  ## [2.18.0] — 2026-08-11
27
49
 
28
50
  ### Changed
29
- - **Expose only the CORE tool surface (mission `vp-mcp-alias-cleanup-v1`, S8).** A data-driven allowlist (`mcp-server/tool-exposure.json`, `{"core":[...]}`) masks every tool whose `T2_verdict` is not `CORE` in `analysis/vantagepeers/vp-restructuring/vp-by-tool-day158.csv`. Masking ≠ deletion: non-CORE tools stay registered + handler-wired and are `disable()`d so `tools/list` does not advertise them; reverting = removing a line from the data file. Exposed = CORE ∩ registered = **66** tools; masked = **43** (registered 109). The exposure list is derived from the CSV, never typed; a name in the file matching no registered tool makes the server refuse to start, naming it. Applied at the single shared `registerTools` surface, so both stdio and HTTP transports (online clients) inherit the reduced surface. 5 CORE names from the day158 CSV are #1169-removed aliases whose CORE survivors stay exposed (zero capability lost). Tests: `test/tool-exposure.test.ts` 2/2, full suite 1071 passed / 0 failed, tsc 0.
51
+
52
+ - The server advertises only its core tool set, listed in `tool-exposure.json`. The other tools stay in the code but are disabled: a client can neither list nor call them. The server refuses to start if that file names a tool that does not exist.
30
53
 
31
54
  ## [2.17.0] — 2026-08-11
32
55
 
33
56
  ### Removed
34
- - 14 duplicate alias tools removed (mission `vp-mcp-alias-cleanup-v1`, S2, merged in #1169), keeping the fleet-used survivor of each pair — decided by call-site usage, never the code's `DEPRECATED ALIAS` label. Registered tool count 123→109. Context-token saving 1347 (11.1%) of the tool-list surface. Full list + arbitration in the root `CHANGELOG.md` and `elpi-corp/.../S1-arbitrated-pairs-day159.md`.
35
57
 
36
- ## [Unreleased] — final refus-total sweep (8 tools) → remaining: 0
37
-
38
- ### Security
58
+ - 14 duplicate alias tools were removed; the canonical tool of each pair remains.
39
59
 
40
- - **Close the last 8 same-class refus-total instances on the client MCP surface.** `get_profile`, `list_peers`, `list_repo_mappings`, `get_repo_mapping`, `get_message` fed `scopeFilterList`/`scopeFilterGet` rows lacking `createdBy`/`namespace` → named remap of the real ownership field (`profiles.orchestratorId`, `githubRepoMapping.orchestrator`, `messages.from`) → `createdBy` before the filter, synthetic field stripped (the `list_broadcast_status` precedent). `list_issues`, `get_issue`, `issue_stats` have no client-owner field (fleet routing/aggregate data; sibling mutations already master-only) → `defineTool` scope `{ kind: "master" }`, structural removal from the client surface. Per tool RED→GREEN with four independent poles; 37 new tests (4 files) + updated `scope-aware-filter-wave-c2`/`c3` (stale fixtures that asserted the old leak as acceptable, aligned to the merged `list_errors` template). RED without fix: 18 owner-pole failures; full CI-scoped suite 2679/2679 green; tsc + scope-typecheck exit 0. **Final class sweep: `remaining: 0`** — every remaining `scopeFilterList`/`scopeFilterGet` site operates on a table with native `createdBy`/`namespace` or already remaps its non-native owner; `check_messages`/`mark_as_read`/`list_tasks`/`list_missions`/`list_diaries` use dedicated non-`scopeFilterList` gates (out of this defect class). Closes VP `k1759mg282aqy6t7c91gnk10598bn4sv`; completes mission `vp-multitenant-zero-hole-v1`.
60
+ ## Changes between 2.12.0 and 2.17.0
41
61
 
42
- ## [Unreleased] — list_bus / list_mandates / list_errors refus-total close
43
-
44
- ### Security
45
-
46
- - **Scope `list_bus`/`get_bu`, `list_mandates`/`get_mandate` to their owner; move `list_errors`/`get_error` to master-only.** These six handlers fed `scopeFilterList`/`scopeFilterGet` rows whose shape carried neither `createdBy` nor `namespace`, so the guard refused **every** non-master caller including the owner (the refus-total form measured in the S0 campaign). Per-table remedy, decided by measurement: `businessUnits` is owned by `orchestratorId` → named remap to `createdBy` before the filter (the `list_broadcast_status` precedent); `mandates` has two owners `requestedBy`/`fulfilledBy` → dual remap unioned by `_id` (a single remap would hide one party's own mandates); `errorLogs` has no client owner (fleet-ops monitoring) → its `defineTool` scope becomes `{ kind: "master" }`, a structural removal from the client surface (non-master now gets an explicit Forbidden instead of a silent empty list). Per tool: RED (owner refused) → GREEN with owner/deny/master poles moving independently; 28 new tests + updated `scope-aware-filter-wave-c3`; full CI-scoped suite green, tsc + scope-typecheck exit 0. Class sweep found 8 further same-class instances (`get_profile`, `list_peers`, `list_issues`, `get_issue`, `issue_stats`, `list_repo_mappings`, `get_repo_mapping`, `get_message`) — tracked as a follow-up, out of this PR's named scope. Closes VP `k177617dqg6z5c099p1rdp5rqn8b2rp0`.
62
+ ### Added
47
63
 
48
- ## [Unreleased] — content-search multi-tenant scope (refus-total close)
64
+ - Knowledge-base ingest: `store_document_chunked` (chunk and index a file previously uploaded to storage; returns `{ docId, chunkCount, storageId }`) and `soft_delete_document`. Both require an organisation-scoped Clerk session.
65
+ - Clerk session tokens carrying an organisation claim are verified against Clerk's published keys and scoped to that organisation's `team/<orgId>` namespace for reads and writes. A token for an organisation that is not registered is refused.
49
66
 
50
67
  ### Security
51
68
 
52
- - **Scope three content-rendering MCP tools to their caller.** `list_messages`, `search_messages_by_keyword`, and `search_tasks_by_keyword` fed `scopeFilterList` rows whose rendered shape carried neither `createdBy` nor `namespace`, so the naive guard wrap would have refused **every** caller including the owner (the refus-total defect PR #1122 deliberately avoided for the two search tools; `list_messages` already exhibited it). Fix: message-shaped tools (`from` field) get a named `from`→`createdBy` remap before `scopeFilterList` with the synthetic field stripped on output (the `list_broadcast_status` precedent); `search_tasks_by_keyword` requests `fields=full` internally, filters against the real `createdBy`, then reprojects to the public `lite` shape (avoids changing the public tool shape). Per-tool RED→GREEN with four independent poles (cross-tenant reproduction, owner-only, deny-only, master-all): RED 8-fail without fix → GREEN 17/17. tsc exit 0. Unremapped-shape audit: all 22 `scopeFilterList` sites checked, only the two message sites needed the remap. Closes VP `k175j2jems5deccegp4p0fy4x98b4ypn` + `k1780azk7n8fdb7bpnx5n91sx18b5vjf`.
69
+ - `list_messages`, `search_messages_by_keyword`, `search_tasks_by_keyword`, `get_profile`, `list_peers`, `get_message`, `list_mandates` and `get_mandate` return only rows the caller owns or is a party to. Previously some of them refused every scoped caller, including the owner.
70
+ - Operations tools with no customer owner (error logs, issue tracking, repository mappings) are restricted to the service operator; other callers receive an explicit refusal instead of an empty list.
71
+ - Cross-organisation reads and writes in another team's namespace are refused.
53
72
 
54
73
  ## 2.14.2 — 2026-06-30
55
74
 
56
- - fix(oauth): DCR `/register` rejects empty/missing/malformed `redirect_uris` (RFC 7591 §3.2.2 `invalid_redirect_uri`). Closes zombie-client class — clients with empty `redirectUris` arrays can no longer be created. Defense-in-depth: same guard at Convex `registerPublicClient`. TDD-strict RED-then-GREEN.
57
-
58
- ## [Unreleased]
59
-
60
- ### Added
61
-
62
- - **B5 KB ingest MCP tools** — `store_document_chunked` and `soft_delete_document` registered via `mcp-server/src/tools/kbIngest.ts`. `store_document_chunked` accepts `storageId` + `mimeType` + `filename` (+ optional `docId`) and proxies to `kb:storeDocumentChunked`; returns `{ docId, chunkCount, storageId }`. `soft_delete_document` accepts `docId` and proxies to `kb:softDeleteDocument`; returns `{ docId, markedCount }`. Both tools require Clerk JWT with `org_id` — no anonymous access. Exported: `STORE_DOCUMENT_CHUNKED_TOOL_DESCRIPTION`, `storeDocumentChunkedArgsSchema`, `SOFT_DELETE_DOCUMENT_TOOL_DESCRIPTION`, `softDeleteDocumentArgsSchema`. Mission `k5779qbxhwrfjmj02t31yvehns8911jp`, task `k17bdmhr2hffhz2t96p65j70nh891wcp`.
63
-
64
- ## [Unreleased] — B4 RAG namespace team/<orgId> tenant enforcement
65
-
66
- ### Added
67
-
68
- - **`team-member` scope profile** in `bearerAuthMiddleware` (layer 2.5): Clerk JWTs carrying an `org_id` claim are now verified against the Clerk JWKS (`CLERK_DOMAIN/.well-known/jwks.json`, cached 10 min) and resolve to `scopeProfile="team-member"` with `namespaceReadPrefixes=["team/<orgId>"]` and `namespaceWritePrefixes=["team/<orgId>"]`. Cross-tenant reads/writes are rejected by the existing `checkNamespaceRead` / `checkNamespaceWrite` predicates before any Convex call.
69
- - **`convex/memoriesScoped.ts`**: new `listMemoriesScoped` (query) and `storeMemoryScoped` (mutation) Convex functions that enforce `team/<orgId>` namespace isolation at the Convex layer using `ctx.auth.getUserIdentity()`. Clerk callers with `org_A` cannot read or write `team/org_B/*`.
70
- - **`jose`** (transitive, already present via `@modelcontextprotocol/sdk`) used for JWKS fetch and JWT verification. No new npm dep.
71
- - **`CLERK_DOMAIN` env var**: override the Clerk instance domain (default `https://sharp-sponge-67.clerk.accounts.dev`).
72
-
73
- ### Security
74
-
75
- - Architectural choice: **Option A** (direct Clerk JWT verification in bearer middleware) over Option B (DCR→Clerk join via Convex query). Rationale: Clerk JWTs are self-contained — no extra Convex round-trip needed. Option B would be required only if DCR clients were the sole entry point.
76
- - Cross-tenant deny preserved for DCR `client-generic` (empty prefixes, unchanged) and unregistered orgs (fail-closed: `AUTH_NAMESPACE_DENIED`).
77
-
78
- ### Tests
75
+ ### Fixed
79
76
 
80
- - `mcp-server/test/team-namespace-cross-tenant.test.ts` — 16 predicate tests on `checkNamespaceRead/Write/isMasterScope` with team-member, master, and DCR-generic fixtures.
81
- - `convex/__tests__/auth-namespace-deny.test.ts` — 9 convex-test tests verifying `AUTH_NAMESPACE_DENIED` for cross-tenant access at the Convex layer.
77
+ - OAuth dynamic client registration (`/register`) rejects a missing, empty or malformed `redirect_uris` with `invalid_redirect_uri` (RFC 7591).
82
78
 
83
79
  ## [2.12.0] — 2026-06-14
84
80
 
85
81
  ### Changed
86
- - `check_messages` now calls `messages:checkNewMessagesEnvelope` (Convex PR #759 mergeCommit `c03023fc85463fe16fc53948d3002420bc1c4547`) for bounded tool-response size. New optional `limit` arg (1-50, default 20). When the call is truncated, the text payload appends `— truncated. Resume with check_messages since=<nextSince>` so the orchestrator can page the backlog cleanly without busting Claude Code's tool-response cap.
87
- - `since` arg description amended with a "pair with `nextSince` from a previous truncated reply" hint.
88
-
89
- ### Notes
90
- - Closes Pi BLOCKER VP task `k1702xaahb` (Day 102 — sigma-vps cron crash on a 36-message / 53 KB backlog).
91
- - Legacy `messages:checkNewMessages` Convex query left intact for vp-mcp <2.12.0 callers (no break).
92
-
93
- ## [2.11.0] — 2026-06-14 — Day 102 CRUD baseline PR-C-bis option B: 3-entity Convex searchIndex (mission k575kc1ryps0n8br95jw3q7d0x88m2v9)
94
-
95
- Mission `mcp-crud-baseline-standard` PR-C-bis under T2. Pi-sequenced follow-up after PR-C (rename-only safe subset) — implements **option B SCOPED** per Pi arbitrage msg `jn7abynmghy5qdr9ga0b914wmh88n99w` ("GO option B SCOPED — démarre PR-C avec 3 entités prioritaires"): tasks + messages + briefingNotes get native Convex BM25 search via `.searchIndex()` schema additions + per-entity Convex queries + MCP tool wrappers.
96
-
97
- Backend choice (B over A): Convex native `.searchIndex()` is BM25-only, no embeddings, no RAG per-entity pipeline. Sub-linear scan stays in the same backend without spinning up an embedding pipeline per table. Hybrid/semantic per entity remains a future RFC.
98
-
99
- ### Added — Convex schema searchIndex (3 tables)
100
-
101
- - `tasks` → `searchIndex("search_title", { searchField: "title", filterFields: ["assignedTo", "status", "project", "missionId", "orgId"] })`
102
- - `messages` → `searchIndex("search_content", { searchField: "content", filterFields: ["from", "channel", "sessionDay", "tenantId"] })`
103
- - `briefingNotes` → `searchIndex("search_content", { searchField: "content", filterFields: ["topic", "createdBy", "orgId"] })`
104
-
105
- ### Added — Convex query functions
106
-
107
- - `tasks:searchTasksByKeyword` — BM25 over title with assignedTo/status/project/missionId filters + scope gate via `withOrgScope` + `filterByOrgScope` + `requireScope("view-own-tasks")`. Lite/full projection.
108
- - `messages:searchMessagesByKeyword` — BM25 over content with from/channel/sessionDay/tenantId filters.
109
- - `briefingNotes:searchBriefingNotesByKeyword` — BM25 over content with topic/createdBy filters.
110
-
111
- All three: 20-item default limit, 200 cap, lite projection on demand.
112
-
113
- ### Added — MCP tool wrappers (3 canonical)
114
-
115
- - **`search_tasks_by_keyword`** — wires to `tasks:searchTasksByKeyword`. `readOnlyHint=true`.
116
- - **`search_messages_by_keyword`** — wires to `messages:searchMessagesByKeyword`. `readOnlyHint=true`.
117
- - **`search_briefing_notes_by_keyword`** — wires to `briefingNotes:searchBriefingNotesByKeyword`. `readOnlyHint=true`.
118
-
119
- ### Why option B (and why scoped to 3)
120
-
121
- `grep searchIndex convex/schema.ts` previously returned zero hits; only `memories` had search infrastructure (via `@convex-dev/rag`). The original "13-entity cluster" full scope was deferred via PR-C (rename-only) after arbitrage timeout. Pi's arbitrage landed shortly after: **option B SCOPED to 3 priority entities** is the right blend of doctrine progress + bounded scope:
122
- - `tasks` — largest fleet audience (Eta T13 close-issue scan, dispatch-task-find, etc.).
123
- - `messages` — post-incident audit + messages-history skill demand.
124
- - `briefingNotes` — daily snapshot recall narrative.
125
-
126
- The remaining 10 entities (mission/mandate/fix_pattern/component/repo_mapping/bu/profile/deployment/diary/error/issue/recurring_task/summary) go to a per-entity RFC (mission walk-through scheduled Wed 17 June 15h with Laurent) — each entity decides B (searchIndex), A (RAG if semantic justified, e.g. episodes/diary), or N/A semantic documented (deployment/repo_mapping).
127
-
128
- ### Version sync
129
-
130
- - `mcp-server/server.ts:115` SERVER_VERSION 2.10.0 → 2.11.0
131
- - `mcp-server/package.json` → 2.11.0
132
- - README + 4 cloud docs bumped to 2.11.0 markers (`enforce-release-sync` v1.0.1 gate).
133
-
134
- ### Test fixture catch-up
135
-
136
- - `READ_ONLY_TOOLS` set in `mcp-server/src/__tests__/chatgpt-tool-annotations.test.ts` extended with the 3 new canonical tool names.
137
-
138
- ### Refs
139
-
140
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9`.
141
- - Pi sequencing dispatch: msg `jn76360ckrrkwpqbfwa6tst7k588mpsh` ("(1) T2 PR-C-bis option B SCOPED 3 entities").
142
- - Pi arbitrage that selected option B: msg `jn7abynmghy5qdr9ga0b914wmh88n99w`.
143
- - Audit T1: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` rows 1 (task), 3 (message), 4 (briefing_note).
144
- - Doctrine memory: `j57dhrmkzjerjtssnr0z9ba57n88n7q7` (5 ops per entity).
145
- - Predecessors: PR-A 2.8.0 (memories canonical), PR-B 2.9.0 (episode 5-op), PR-C 2.10.0 (rename-only safe subset).
146
-
147
- ## [2.10.0] — 2026-06-14 — Day 102 CRUD baseline PR-C: rename-only safe subset (mission k575kc1ryps0n8br95jw3q7d0x88m2v9)
148
-
149
- Mission `mcp-crud-baseline-standard` PR-C under T2. Third of 4 sub-PRs aligning the MCP surface with the Day 101 doctrine `j57dhrmkzjerjtssnr0z9ba57n88n7q7`. Sigma autonomous default after arbitrage timeout on the original "13-entity search_by_keyword cluster" scope — that fuller scope requires a backend search-infrastructure decision (RAG-index per entity vs Convex `.searchIndex()` per table) that is NOT a thin-wrapper PR. PR-C ships the rename-only safe subset now to keep doctrine velocity; the full cluster is deferred to a backend-RFC mission.
150
-
151
- ### Added (2 canonical search tools)
152
-
153
- - **`search_components_by_keyword`** — BM25 / substring search over components by name or team. Wire-identical to `search_components` (same Convex query `components:search` 1:1, same scope filter, same defaults). `readOnlyHint=true`.
154
- - **`search_fix_patterns_by_semantic`** — semantic embedding-similarity search over fix patterns. Wire-identical to `search_fix_patterns` (same Convex action `search:searchFixPatterns` 1:1, same scope filter, same defaults). `readOnlyHint=true`. Note: the canonical suffix is `_by_semantic` (NOT `_by_keyword`) because the underlying ranker is embedding-cosine, not BM25 — naming follows behavior, not entity convention.
155
-
156
- ### Deprecated (alias-only, removal target 2.11.0)
157
-
158
- - **`search_components`** — alias of `search_components_by_keyword`. Description leads with `DEPRECATED ALIAS …`.
159
- - **`search_fix_patterns`** — alias of `search_fix_patterns_by_semantic`. Description leads with `DEPRECATED ALIAS …`.
160
-
161
- ### Re-targeted deprecations (FOLLOW-UP from Eta PR #750 review)
162
-
163
- - **`text_search`** — 2.8.0 originally targeted removal at 2.9.0; episode-only PR-B did not include the removal. Source comments + this entry re-target removal to **2.11.0**.
164
- - **`recall`** — same re-target rationale, removal now **2.11.0**.
165
-
166
- Both `text_search` and `recall` remain wire-identical to their canonical successors (`search_memories_by_keyword` / `search_memories_by_semantic`). Closes FOLLOW-UP task `k1754apqtcjpre2vd5ghbkcmzn88mhwf`.
167
-
168
- ### Scope NOT in this PR (deferred)
169
-
170
- The original PR-C "13-entity search_by_keyword cluster" required adding BM25 / search infrastructure to 10+ entities that currently have NO backend search index (`grep searchIndex convex/schema.ts` → zero hits; only `memories` is indexed, via `@convex-dev/rag`). Two backend paths exist:
171
-
172
- - **Path A** — extend RAG indexing to each entity (heavy: per-table embedding pipeline, RAG namespace per entity, vector cost; gets hybrid search for free).
173
- - **Path B** — Convex native `.searchIndex()` per table (lightweight: schema migration + one query per entity, BM25-only, no embeddings).
174
-
175
- Either path is a multi-day backend RFC, NOT a thin-wrapper PR. Sigma sent the arbitrage to Pi (msg `jn75zy4g7bhj95bhyz2zvv6n8d88na6s`) and defaulted to PR-C path C (rename-only) after 2 cron ticks of no reply. A follow-up mission to scope the backend search infrastructure is the next mission proposal.
176
-
177
- ### Version sync
178
-
179
- - `mcp-server/server.ts:115` SERVER_VERSION 2.9.0 → 2.10.0
180
- - `mcp-server/package.json` → 2.10.0
181
- - README + 4 cloud docs bumped to 2.10.0 markers (`enforce-release-sync` v1.0.1 gate).
182
-
183
- ### Test fixture catch-up
184
-
185
- - `READ_ONLY_TOOLS` set in `mcp-server/src/__tests__/chatgpt-tool-annotations.test.ts` extended with the 2 new canonical names.
186
-
187
- ### Refs
188
-
189
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9` (MCP CRUD Baseline Standard).
190
- - Pi authorization msg `jn74q7twhr3s1s8dvqxbzvky9588msdd` ("next: T2-PR-C 13-entity search_by_keyword cluster post #750 merge").
191
- - Sigma arbitrage msg to Pi: `jn75zy4g7bhj95bhyz2zvv6n8d88na6s` (3 paths A/B/C).
192
- - FOLLOW-UP task: `k1754apqtcjpre2vd5ghbkcmzn88mhwf` (text_search/recall deprecation slipped).
193
- - Audit T1: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` § 4.
194
-
195
- ## [2.9.0] — 2026-06-14 — Day 102 CRUD baseline PR-B: episode entity 5-op surface (mission k575kc1ryps0n8br95jw3q7d0x88m2v9)
196
-
197
- Mission `mcp-crud-baseline-standard` PR-B under T2. Second of 4 sub-PRs aligning the MCP surface with the Day 101 doctrine `j57dhrmkzjerjtssnr0z9ba57n88n7q7` ("5 ops per entity"). PR-B adds the missing read/list/search facades for the `episode` entity, completing the 5-op surface (the write side `store_episode` already existed since the 8-Sins doctrine).
198
-
199
- Architectural note: episodes are NOT a separate Convex table — per hotfix `7f958d0`, episodes are stored as memories with `type='episode'` (context/goal/action/outcome/insight + severity). The 4 new tools are thin wrappers that force `type='episode'` on the existing `memories:*` / `search:*` actions, so callers get an ergonomic episode-scoped surface without introducing a new backend table or duplicating index logic.
200
-
201
- ### Added (4 canonical episode tools)
202
-
203
- - **`get_episode`** — fetch a single episode by memory ID. Calls `memories:getMemory` then asserts the returned row has `type='episode'`; otherwise returns a non-leaky "Episode not found" so wrong-type IDs do not leak existence of non-episode memories. Scope-aware via `scopeFilterGet`. Annotations: `readOnlyHint=true`, `openWorldHint=false`, `destructiveHint=false`.
204
- - **`list_episodes`** — list episodes ordered newest first. Calls `memories:listMemories` with `type='episode'` forced. Accepts `namespace?`, `createdBy?`, `limit?`, `fields?`, `cursor?` — same paging semantics as `list_memories`. Scope-aware via `scopeFilterList`. Envelope-capped via `capListResponseBytes("list_episodes")`.
205
- - **`search_episodes_by_keyword`** — BM25 search restricted to episodes. Calls `search:textSearch` with `type='episode'` forced. Same `guardRead` namespace gate, same 20-default / 200-cap limits.
206
- - **`search_episodes_by_semantic`** — semantic vector cosine search restricted to episodes. Calls `search:recall` with `type='episode'` forced. Same gate, same limits.
207
-
208
- All four are pure MCP-layer additions: no Convex schema change, no new index, no new action. tsc clean.
209
-
210
- ### Why
211
-
212
- Episode = the 8-Sins / orchestrator-introspection memory type (severity + context/goal/action/outcome/insight). Until 2.9.0, recalling past episodes required `recall query='...' type='episode'` — discoverable only to callers who already knew the memory-side filter trick. Surfacing dedicated wrappers makes the episode lifecycle (write via `store_episode`, read via `get_episode`, browse via `list_episodes`, recall via the two search ops) consistent with the doctrine and self-documenting in any MCP client's tool list.
213
82
 
214
- `hybrid_search` remains entity-agnostic and is NOT mirrored for episodes (cross-cutting RRF tool per audit § 4).
83
+ - `check_messages` returns a bounded page of messages. New optional `limit` (1–50, default 20). When more messages are waiting, the reply ends with the `since` value to pass on the next call.
215
84
 
216
- ### Test fixture catch-up
85
+ ## [2.11.0] — 2026-06-14
217
86
 
218
- - `READ_ONLY_TOOLS` set in `mcp-server/src/__tests__/chatgpt-tool-annotations.test.ts` extended with the 4 new tool names.
219
-
220
- ### Refs
221
-
222
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9` (MCP CRUD Baseline Standard, pilot Sigma + agents Sigma + Eta).
223
- - Pi authorization msg `jn74v2pkfz08agex4nfm2yfvfd88nzdw` — "chain T2 PR-B episode entity en autonomie scope mission".
224
- - Audit T1 deliverable: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` row 7 (episode entity recommendation: add façade wrappers).
225
- - Architecture: hotfix `7f958d0` — episodes are memories with metadata, not a separate table.
226
-
227
- ## [2.8.0] — 2026-06-14 — Day 101 CRUD baseline PR-A: search_memories_by_keyword + search_memories_by_semantic (mission k575kc1ryps0n8br95jw3q7d0x88m2v9, task k1735qk9kx6agjjyt3e38rdvvh88mk0p)
228
-
229
- Mission `mcp-crud-baseline-standard` PR-A under T2 `[CRUD-T2] Implémentation gaps VP MCP`. First of 4 sub-PRs aligning the MCP surface with the Day 101 doctrine `j57dhrmkzjerjtssnr0z9ba57n88n7q7` ("5 ops per entity: get / list / search_by_keyword / search_by_semantic / create-or-upsert"). PR-A handles the convention drift on the `memories` entity — the only entity that already had both keyword + semantic search wired, but under non-canonical names.
230
-
231
- ### Added (canonical names)
232
-
233
- - **`search_memories_by_keyword`** — BM25 full-text search over memories, identical wire to `text_search`. Calls `search:textSearch` Convex action 1:1, same params (`query`, `namespace?`, `type?`, `limit?`, `fields?`), same `guardRead` namespace gate, same 20-item default limit + 200 cap, same `mcpConvexError` error surface (2.7.1 sweep). Annotations: `readOnlyHint=true`, `openWorldHint=false`, `destructiveHint=false`, title `"Search memories by keyword (BM25)"`.
234
- - **`search_memories_by_semantic`** — semantic vector cosine search over memories, identical wire to `recall`. Calls `search:recall` Convex action 1:1, same params, same gate, same defaults. Annotations: `readOnlyHint=true`, `openWorldHint=false`, `destructiveHint=false`, title `"Search memories by semantic (vector cosine)"`.
235
-
236
- ### Deprecated (alias-only, one minor window)
237
-
238
- - **`text_search`** — alias of `search_memories_by_keyword`. Description now leads with `DEPRECATED ALIAS`, source comment marks it for removal in `2.9.0`. Wire unchanged — existing callers continue to work for one minor.
239
- - **`recall`** — alias of `search_memories_by_semantic`. Description now leads with `DEPRECATED ALIAS`, source comment marks it for removal in `2.9.0`. Wire unchanged.
240
-
241
- ### Why
242
-
243
- Per mission `k575kc1r` brief + Pi arbitrage `jn77rpx2msfy2v174sdqyjzp6n88m9bw` Q4 (RENAME CLEAN, optional one-minor dual-emit buffer if Sigma judges useful): the legacy `text_search` / `recall` pair predates the Day 101 CRUD baseline naming convention. Other entities will gain `search_<entity>s_by_keyword` / `search_<entity>s_by_semantic` in PR-C (cluster of 13) and PR-D (vectorIndex add for briefing_notes + diary). Aligning the `memories` entity FIRST means PR-C/D ship into a fleet that already understands the new naming, and skill / plugin / docs propagation (T-SKILLS, T-PLUGIN, T-DOC) has a single canonical truth to follow.
244
-
245
- `hybrid_search` is intentionally NOT renamed — it remains a cross-cutting RRF-fusion tool, not entity-scoped, per the audit `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` § 4.
246
-
247
- ### Refs
248
-
249
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9` (MCP CRUD Baseline Standard, pilot Sigma + agents Sigma + Eta).
250
- - Task T2 `k1735qk9kx6agjjyt3e38rdvvh88mk0p`.
251
- - Audit T1 deliverable: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` (140 lines, 53 table rows).
252
- - Doctrine memory: `j57dhrmkzjerjtssnr0z9ba57n88n7q7` (5 ops per entity).
253
- - Pi Q4 arbitrage: msg `jn77rpx2msfy2v174sdqyjzp6n88m9bw`.
254
-
255
- ## [2.7.1] — 2026-06-14 — Day 101 FIX-B mcpError() → mcpConvexError() sweep (task k1744wk2gfgqt2gdqh41d4r91h88n410)
256
-
257
- Patch-level fix to make every tool wrapper surface structured ConvexError
258
- diagnostics instead of opaque `"Server Error [Request ID: ...]"` strings.
259
-
260
- **Problem (Day 101):** when a Convex mutation/query threw a `ConvexError`
261
- (e.g. `TASK_START_BLOCKED`, `COMPLETION_NOTE_REQUIRED`) or an
262
- `ArgumentValidationError`, the tool wrapper called
263
- `mcpError(error.message ?? String(error))` which returned a plain
264
- `Error: <message>` text payload. The MCP client (Claude Code) then often
265
- re-displayed this as a generic `Server Error [Request ID:...]`, masking the
266
- actual root cause and triggering misdiagnosis sprees (Pi msg
267
- `jn7c5tfj0347vaenyqgrezehk188mr11` mistakenly attributed the symptoms to
268
- a backend regression that did not exist — see Sigma report msg
269
- `jn773p8qnfp6ycb1f7gajhs8vn88m11a`).
270
-
271
- **Fix:** sweep all 99 occurrences of
272
- `return mcpError(error.message ?? String(error))` →
273
- `return mcpConvexError(error)`. The `mcpConvexError` helper (already
274
- present at `src/tools.ts:535`, shipped 2.4.x) parses ConvexError messages
275
- into a structured JSON `{ code, message, path, hint }` payload that
276
- surfaces the actual error code (`ArgumentValidationError`,
277
- `ConvexError`, `AuthorizationError`, `SchemaValidationError`, etc.)
278
- along with a path and a concise hint for ID-table mismatches.
279
-
280
- Total counts post-sweep: `grep mcpConvexError(` → 102 ; `grep
281
- mcpError(error.message` → 0.
282
-
283
- Type check: `npx tsc --noEmit` exits 0.
284
-
285
- Mission/refs: `k575kc1ryps0n8br95jw3q7d0x88m2v9` MCP CRUD Baseline Standard,
286
- task FIX-B `k1744wk2gfgqt2gdqh41d4r91h88n410`. Co-shipped with hook
287
- `enforce-friction-field.py` v1.1.0 STDERR clarification (Day 101 task
288
- FIX-A `k17ads7kh7qk7yxgfe0dh73ggx88ny9f`).
289
-
290
- ## [2.7.0] — 2026-06-13 — Day 100 get_by_id surface Phase 2b (task k172735brsw6bc3j2dkkkfxqrx88kkjq)
291
-
292
- Phase 2b wires 2 MCP wrappers calling the Phase 2a Convex queries deployed
293
- in commit 2ebdaba (PR #735 + hotfix 7f958d0):
294
-
295
- - **get_message** — `messages:getById` plumbing. Fetch full message row by
296
- Convex doc ID (channel, sender, sessionDay, tenant scope) for read-receipt
297
- audit, delete confirmation, or fix-pattern referencing.
298
- - **get_recurring_task** — `recurringTasks:getById` plumbing. Fetch
299
- recurring task definition (cron schedule, prompt, assignee, last-fire
300
- metadata) before pause/update/delete.
301
-
302
- Both follow the existing `get_memory` / `get_briefing_note` pattern:
303
- `scopeFilterGet(oauthCtx, row)` for scope-aware cross-tenant collapse,
304
- read-only annotations.
305
-
306
- **get_episode** was DROPPED from Phase 2b scope: episodes are stored as
307
- memories with episode metadata (no separate `episodes` table in
308
- `convex/schema.ts`). Use existing `get_memory` to fetch episode rows by
309
- their memory document ID. Hotfix 7f958d0 removed the invalid
310
- `episodes:getById` query that broke `convex deploy` typecheck.
311
-
312
- Phase 2a CHANGELOG entry deferred — Convex changes shipped in main repo
313
- CHANGELOG, not mcp-server.
314
-
315
- Total MCP `get_*` tools after Phase 2b: 16 (was 14 after Phase 1, 10 before
316
- Day 100 task).
317
-
318
- ## [2.6.0] — 2026-06-13 — Day 100 get_by_id surface Phase 1 (task k172735brsw6bc3j2dkkkfxqrx88kkjq)
319
-
320
- Pi reported get_<entity>_by_id MCP surface gaps observed during Day 100 fleet ops.
321
- Phase 1 adds 4 plumbing-only read tools mapping to pre-existing Convex queries:
322
-
323
- - **get_task** — `tasks:getById` plumbing. Fetch full task record (description, dependsOn,
324
- missionId, completionNote, claimedByInstance, startedAt) by Convex doc ID.
325
- - **get_fix_pattern** — `fixPatterns:get` plumbing. Fetch fix pattern with full linked
326
- fix attempts history.
327
- - **get_mandate** — `mandates:get` plumbing. Fetch spending mandate with limits, current
328
- spend, approver chain for validateSpending/settleMandate pre-checks.
329
- - **get_repo_mapping** — `githubRepoMapping:getByRepo` plumbing. Fetch GitHub repo→VP project
330
- mapping by repo slug.
331
-
332
- All 4 tools apply `scopeFilterGet(oauthCtx, row)` for scope-aware cross-tenant collapse,
333
- mirroring the existing `get_memory` / `get_briefing_note` pattern (Day 92 S3.1 wave).
334
-
335
- Annotations test (chatgpt-tool-annotations.test.ts) READ_ONLY_TOOLS set extended with
336
- the 4 new tools. Pre-existing 84/97 count mismatch in same test is unrelated (separate
337
- F-list track).
338
-
339
- Phase 2 (follow-on PR) will add get_message / get_episode / get_recurring_task
340
- (Convex query additions required).
341
- Phase 3 (separate mission) will audit deployment entity (table+queries+tool) and the
342
- cross-backend cloud proxy redeploy cadence.
343
-
344
- ## [2.5.0] — 2026-06-06 — Day 92 VP MCP quality overhaul (mission k57a36y8)
345
-
346
- Day 92 mission `k57a36y8w5t085bqr23dsmvb2d882506` ships a fleet-wide VP MCP quality bump
347
- across audit, docs, hooks, security, and consistency dimensions. 15 PRs merged to main.
348
-
349
- ### Phase A — Audit + new tools
350
- - **A1** Day 92 VP MCP tools audit matrix (85 tools, 14 P0 zero-auth gaps) — `docs/test-reports/day92-vp-mcp-audit-matrix.md`.
351
- - **A2** Consistency analysis report — `docs/test-reports/day92-vp-mcp-consistency-analysis.md`.
352
- - **A3** New `whoami` LECTURE tool — first per-tool `outputSchema` export precedent.
353
- - **A4** Consolidated gap matrix — `docs/test-reports/day92-vp-mcp-gap-matrix-consolidated.md`.
354
-
355
- ### Phase B — Documentation
356
- - **B1** `docs/cloud/security-multi-tenant.md` §4 scope-aware filter framework rewrite.
357
- - **B2** `docs/cloud/tools-quality-standard.md` (NEW) — 12-section bilingual quality standard.
358
- - **B3** `docs/cloud/onboarding-customer.md` (NEW) — customer onboarding guide (bilingual FR+EN).
359
-
360
- ### Phase C — Consistency
361
- - **C0** 14 P0 zero-auth write tools secured with `guardMasterOnly` (C0.1 → C0.6, 6 PRs).
362
- - **C1** 87 Zod `outputSchema` exports per per-family envelope standard (B2 §3).
363
- - **C2** Orchestrator-id NFC normalization + case-insensitive matching; idempotent prod migration `convex/migrations/c2-normalize-orchestrator-ids.ts` (7 tables).
364
- - **C3** 97 tool descriptions standardized + 10 canonical aliases gated through `guardMasterOnly` (security regression fixed in iter 2) + alias-c0-gate-coverage test (15/15 PASS).
365
- - **C4** Legacy `claude-peers` references removed repo-wide + `grep-gate` CI workflow.
366
-
367
- ### Phase F — Hooks + plugin
368
- - **F1** New consolidated `validate_task_payload` MCP tool + TypeScript validator library (replaces 5 single-axis hooks).
369
- - **F2** Plugin propagation runbook + `plugin-vs-workspace-hooks.md` doctrine.
370
-
371
- ### Scope-aware filtering
372
- - `list_tasks` `fromAllowList[]` + case-insensitive matching (PR #654, #661).
373
- - 3 admin endpoints reinstated for Nadia cohort (prior session).
87
+ ### Added
374
88
 
375
- ### Tenant trio
376
- - Persistent test tenant trio (alpha/beta/gamma) seeded on prod with bearers, scope_profiles, and seed data for cross-orchestrator E2E.
89
+ - Keyword (BM25) search over tasks, messages and briefing notes: `search_tasks_by_keyword`, `search_messages_by_keyword`, `search_briefing_notes_by_keyword`. Default 20 results, maximum 200, compact projection available.
377
90
 
378
- ### Deploy authorization
379
- - `PI_AUTHORIZED_TASK_ID=k1751nfs27t9f9mpvg3ppd6xad884r59` (Day 82 doctrine).
380
- - Mission: `k57a36y8w5t085bqr23dsmvb2d882506`.
381
- - Branch: `release/v2.5.0` opened against `main` at HEAD `18a5530`.
91
+ ## [2.10.0] — 2026-06-14
382
92
 
383
- ## [2.4.13] — 2026-06-02 — Post-public republish: attribution + CHANGELOG day-numbers + RULE #7 narrative scrub
93
+ ### Added
384
94
 
385
- Repository visibility flip to PUBLIC on 2026-06-02 (mission D62 `k57e4t21sr55rhz8ng554eseb987wvh3`). This patch republishes the npm package so the published README + CHANGELOG + attribution match the now-public source.
95
+ - `search_components_by_keyword` and `search_fix_patterns_by_semantic` as the canonical names of `search_components` and `search_fix_patterns`.
386
96
 
387
- No runtime / API / schema changes. Documentation + metadata only.
97
+ ### Deprecated
388
98
 
389
- What changed since v2.4.12:
390
- - `mcp-server/package.json`: author restructured to "VantageOS AI Orchestrator Team" with contributors block (Pi, Laurent Perello, ElPi Corp). Dependency `@vantageos/mosaic@^0.1.2` added for Phase 1 Mosaic groundwork (PR #605, server-side createMosaicResource API ready for Phase 2 primitive swap).
391
- - `mcp-server/CHANGELOG.md`: version headers simplified to `X.Y.Z — YYYY-MM-DD` (Day N anchors dropped per Laurent verdict 2026-06-02 — dates are self-explanatory, day numbers added noise). Narrative client-name mentions (Nadia/<client-org>/Cédric Delport) genericized to "early-access RH cohort" / "self-host incident" per RULE #7 pre-public scrub.
392
- - Root README rework (PR #611 + PR #610 + PR #616 chain): TL;DR + Mermaid architecture diagram + 5 hero features + 22-features collapsed details + 84-tools 8-groups + Backend: Convex 3-paths + attribution Credits section. README /team 404 hotfix landed in PR #616.
99
+ - `search_components` and `search_fix_patterns`, kept as aliases of the canonical names. The removal of `text_search` and `recall` was moved to 2.11.0.
393
100
 
394
- Merged PRs in this republish window:
395
- - PR #611 (`9464f9a`) — T5ter README rework + CHANGELOG day-numbers + attribution
396
- - PR #615 (`c189a1d`) — Phase 1 RULE #7 pre-public scrub
397
- - PR #616 (`99eeae5`) — README /team 404 hotfix
101
+ ## [2.9.0] — 2026-06-14
398
102
 
399
- Mission: D62 pre-public cleanup `k57e4t21sr55rhz8ng554eseb987wvh3`.
400
- Friction capitalize: `post-public-flip-must-trigger-npm-republish-for-consistency-not-just-repo-visibility-flip` + `day-79-hook-should-validate-tree-not-commit-sha`.
103
+ ### Added
401
104
 
402
- ## [2.4.0] — 2026-05-29 — M3 iframeEmbedSessions + __VP_TOOL_RESULT__ stream marker + ack-checklist
105
+ - Episode tools: `get_episode`, `list_episodes`, `search_episodes_by_keyword`, `search_episodes_by_semantic`. Episodes are memories of type `episode`; these tools are shortcuts that apply that type for you. An ID that is not an episode returns "Episode not found".
403
106
 
404
- **Mission instance** : `sigma-vantage-peers-mcp-gui-iframe-embed-v1` (k5730xct6rvrwkvxhy5t5js12d87jwfw).
405
- **Pi sign-off** : PI_AUTHORIZED_TASK_ID=`k1793m1qgn0zaay6r87dhvsh7187kwya` (PROD-DEPLOY-AUTHORIZED).
406
- **Eta sign-off** : ETA_APPROVED_TASK_ID=`k171ep964sxabbrgmb21fk9axd87ka1n` at commit `338a7b9e6130ce69dc5fe7f3e2e9ecc4648b4f6a` (SHA-pinned).
407
- **Merge** : PR #545 squash `f509c8d92f0b142bc063a0e9dd070e1993cc729b`.
107
+ ## [2.8.0] — 2026-06-14
408
108
 
409
- M3 delivers the session registry and stream-marker protocol that connects the VP MCP server
410
- to the Gen UI iframe bridge. All marker emission is gated behind `VP_EMIT_UI_MARKERS=1`
411
- so production behaviour is unchanged until the bridge is deployed.
109
+ ### Added
412
110
 
413
- ### Convex schema — `iframeEmbedSessions` table
111
+ - `search_memories_by_keyword` (BM25) and `search_memories_by_semantic` (vector) as the canonical memory search tools.
414
112
 
415
- NEW table `iframeEmbedSessions` in `convex/schema.ts` :
416
- - Fields : `sessionId` (string), `tenantId` (optional string), `origin` (string),
417
- `userId` (optional string), `createdAt` (number), `lastSeenAt` (number),
418
- `expiresAt` (number), `revoked` (boolean).
419
- - Indexes : `by_session_id` on `["sessionId"]`, `by_origin_expires` on `["origin", "expiresAt"]`.
113
+ ### Deprecated
420
114
 
421
- NEW `convex/iframeEmbedSessions.ts` — 4 operations :
422
- - `createSession` mutation — inserts a new session row.
423
- - `getSession` query — returns session or null (null for expired / revoked).
424
- - `touchSession` mutation — bumps `lastSeenAt` to now; returns bool.
425
- - `revokeSession` mutation — sets `revoked=true`; returns bool.
115
+ - `text_search` and `recall`, kept as aliases of the two tools above with identical behaviour.
426
116
 
427
- ### Stream marker — `mcp-server/src/ui-resources/stream-marker.ts`
117
+ ## [2.7.1] — 2026-06-14
428
118
 
429
- NEW `MARKER_START = "__VP_TOOL_RESULT__"`, `MARKER_END = "__END__"`.
119
+ ### Fixed
430
120
 
431
- NEW `wrapToolResult(payload: VpToolResult): string` :
432
- - Validates via `VpToolResultSchema`, throws `TypeError` on schema failure.
433
- - Returns `__VP_TOOL_RESULT__<json>__END__`.
121
+ - Tool errors return a structured payload (`code`, `message`, `path`, `hint`) instead of an opaque "Server Error" string, so the real cause (for example a validation error) is visible to the client.
434
122
 
435
- NEW `parseToolResult(text: string): VpToolResult | null` :
436
- - Extracts marker substring (handles bare, embedded, surrounding text).
437
- - Returns validated `VpToolResult` or null on any failure (no-throw contract).
123
+ ## [2.7.0] — 2026-06-13
438
124
 
439
- ### MCP tools — marker emission gated by `VP_EMIT_UI_MARKERS=1`
125
+ ### Added
440
126
 
441
- `mcp-server/src/tools.ts` — 6 tools now append `wrapToolResult(...)` after the JSON payload
442
- when `VP_EMIT_UI_MARKERS=1` (default OFF) :
127
+ - `get_message` and `get_recurring_task`: fetch a single message or recurring task by ID, scoped to the caller.
443
128
 
444
- | Tool | kind |
445
- |-----------------------|--------------------|
446
- | `list_tasks` | `tasks-table` |
447
- | `list_messages` | `messages-feed` |
448
- | `get_diary` | `diary-entry` |
449
- | `list_missions` | `mission-timeline` |
450
- | `list_briefing_notes` | `briefing-note` |
451
- | `list_memories` | `memory-quote` |
129
+ ## [2.6.0] — 2026-06-13
452
130
 
453
- Change is surgical — existing return shape is preserved; marker is appended as a new line.
131
+ ### Added
454
132
 
455
- ### Ack checklist
133
+ - `get_task`, `get_fix_pattern`, `get_mandate` and `get_repo_mapping`: fetch a single record by ID, scoped to the caller.
456
134
 
457
- NEW `docs/M3-ACK-CHECKLIST.md` — bilingual FR/EN post-deploy verification checklist
458
- for the beta verifier cohort. Covers: package install, primitive reads, Shadow DOM scoping,
459
- stream marker emit + parse, bilingual spot check, WCAG AA (contrast + role attrs),
460
- default-OFF guard.
135
+ ## [2.5.0] — 2026-06-06
461
136
 
462
- ### Tests
137
+ ### Added
463
138
 
464
- 15+ new vitest cases (≥264 total after M3, baseline 253 after M2) :
465
- - `mcp-server/src/__tests__/m3-stream-marker.test.ts` — 14 cases:
466
- `wrapToolResult` ×6 valid kinds, ×2 throws on invalid, `parseToolResult` roundtrip,
467
- non-marker text ×2, embedded text, malformed JSON ×2, schema rejects unknown kind ×2.
468
- - `convex/iframeEmbedSessions.test.ts` — 7 cases:
469
- create+get, optional fields, getSession unknown, expired session null,
470
- touchSession updates lastSeenAt, touchSession unknown false,
471
- revokeSession marks revoked (getSession null), revokeSession unknown false.
139
+ - `whoami`: returns the identity attached to the current credential, so a client can discover its agent name instead of asking the user.
140
+ - `validate_task_payload`: checks a task or message payload against every validation rule at once and returns all failures together.
141
+ - Output schemas on tools, and standardised tool descriptions.
472
142
 
473
- 0 regression on M1+M2 suites (253/253 baseline).
143
+ ### Changed
474
144
 
475
- ---
145
+ - Agent names are Unicode-normalised and matched case-insensitively.
146
+ - `list_tasks` honours the caller's allowed agent names.
476
147
 
477
- ## [Unreleased] — M1 SEP-1865 ui:// resources backend + M2 primitives + Zod schemas
148
+ ### Security
478
149
 
479
- **Mission instance** : `sigma-vantage-peers-mcp-gui-iframe-embed-v1` (k5730xct6rvrwkvxhy5t5js12d87jwfw).
480
- **Template VR consumed** : `gui-iframe-embed-v1` v1.0.0 (jx7bzk0x1086tgwgj2zrssk2pn87k1ga).
150
+ - Write tools that previously required no authorisation are restricted to the service operator.
481
151
 
482
- M1 Foundation (adapted MCP-pure paradigm per Pi arbitrage 2026-05-28) :
483
- - NEW `mcp-server/src/ui-resources/index.ts` : URI parser `ui://vp/v1/<primitive>?<query>` + primitive registry + handler factory.
484
- - NEW `mcp-server/src/ui-resources/primitives/tasks-table.ts` : M1 MVP primitive returning HTML inline (Shadow DOM scoped CSS) — WCAG AA + bilingual FR+EN.
485
- - `mcp-server/server-http.ts` : wired `ListResourcesRequestSchema` + `ReadResourceRequestSchema` MCP handlers on the existing McpServer instance.
152
+ ## [2.4.13] — 2026-06-02
486
153
 
487
- Tests : 14 new vitest cases (`src/__tests__/ui-resources-sep-1865.test.ts`) — URI parsing, primitive registry, render variants (empty, populated, FR), backend arg forwarding, XSS escape, error fallback, limit clamping, unknown primitive rejection. 0 regression on existing suites.
154
+ ### Changed
488
155
 
489
- ### M2 — Resolve 5 Gaps + Bearer sha256 hardening (adapted MCP-pure paradigm)
156
+ - Documentation and package metadata only; no runtime change.
490
157
 
491
- 5 new ui:// primitives :
492
- - `messages-feed` (`messages:listMessages` backend — channel filter applied client-side)
493
- - `diary-entry` (`diary:get` single-entry + `diary:list` multi-entry backend)
494
- - `mission-timeline` (`missions:list` backend with fields=lite)
495
- - `briefing-note` (`briefingNotes:get` by noteId OR `briefingNotes:list` by topic backend)
496
- - `memory-quote` (`memories:listMemories` backend — supports both plain-array and paginated result shapes)
158
+ ## [2.4.0] — 2026-05-29
497
159
 
498
- Zod discriminated union schemas : `mcp-server/src/ui-resources/schemas.ts` exports `VpTaskPayloadSchema` + `VpMessagePayloadSchema` + `VpDiaryEntryPayloadSchema` + `VpMissionPayloadSchema` + `VpBriefingNotePayloadSchema` + `VpMemoryPayloadSchema` + `VpToolResultSchema` (discriminated union by `kind`). Cross-fleet ready for Mu vantage-bridge sidepanel S3 consumer.
160
+ ### Added
499
161
 
500
- Bearer sha256 validation : Already in place since v2.3.4 DCR security fix. `mcp-server/src/auth.ts` line 275 calls `sha256Hex(token)` before every Convex lookup (layers 2 and 4). Raw token never reaches Convex. No further hardening needed in M2.
162
+ - Optional UI result markers: with `VP_EMIT_UI_MARKERS=1` (off by default), `list_tasks`, `list_messages`, `get_diary`, `list_missions`, `list_briefing_notes` and `list_memories` append a machine-readable `__VP_TOOL_RESULT__…__END__` block after their normal output, for clients that render rich views. Output is unchanged when the variable is unset.
163
+ - Embedded-session registry backing those views.
501
164
 
502
- Tests : 42 new vitest cases in `src/__tests__/ui-resources-m2-primitives.test.ts` (target was ≥22). Covers : PRIMITIVES registry (6 entries), each of 5 new primitives (empty + populated + FR labels + XSS escape + error fallback = 5 cases each), Zod schema roundtrip (VpToolResultSchema all 6 variants accepted, malformed rejected, individual payload schema validations). 0 regression on M1 17 cases + 194 other MCP tests (253/253 total).
165
+ ## UI resources (released with 2.4.0)
503
166
 
504
- M3 next : Registry json-render + `__VP_TOOL_RESULT__<json>` stream marker + smoke E2E + ack-checklist + PI-SIGNED Convex prod deploy + visual ack from beta cohort verifiers.
167
+ ### Added
505
168
 
506
- ---
169
+ - `ui://vp/v1/<primitive>` MCP resources rendering tasks, messages, diary entries, missions, briefing notes and memories as accessible, bilingual (EN/FR) HTML fragments, with typed payload schemas.
507
170
 
508
171
  ## v2.3.5 — 2026-05-28
509
172
 
510
- **Critical hotfix** — v2.3.3 (PR #539) shipped the backend filters `createdBy` + `updatedSince` and the Zod schema exports but did NOT wire those params into the 4 list MCP tool args blocks. Pi pull-cycle quickstart `list_tasks createdBy="pi" status="review" fields="lite"` was silently dropping `createdBy` at the MCP boundary and returning all visible tasks. Auto-clamp safeguard (2026-05-27) also could not trigger because Zod `.default(50)` / `.default(20)` on `limit` overrode the absent-value signal before it reached the backend.
511
-
512
- Fixes:
513
- - `mcp-server/src/tools.ts` : 4 list tools now expose `createdBy` (`list_tasks` + `list_tasks_by_mission` only — `list_missions` + `list_briefing_notes` do not accept it backend-side) and `updatedSince` (all 4).
514
- - Removed `.default(50)` (3 tools) and `.default(20)` (1 tool) on `limit` so absent value reaches the backend, enabling the v2.3.3 auto-clamp safeguard.
515
-
516
- Tests : 8 new boundary-forwarding cases (`src/__tests__/list-queries-v2.3.5-wire-createdby-updatedsince.test.ts`) — verify MCP layer actually forwards new params to `convex.query` instead of dropping them. 0 regression on existing suites.
517
-
518
- Detection : Vantage-Bridge architecture review Sigma scope 2026-05-28 — direct `grep`/`sed` inspection of `tools.ts` confirmed the gap. Backend already correct since v2.3.3 (`convex/tasks.ts:354-357`).
519
-
520
- Fix-pattern (2026-05-28 capitalize) : when adding a new param across backend + MCP wrapper, the test suite MUST cover not only schema validation but also the tool-handler→convex.query forwarding boundary. Schema-only tests passed cleanly in v2.3.3 while the actual feature was broken in prod.
173
+ ### Fixed
521
174
 
522
- VP task : `k177tsvdxzase5sjy2qm9fdvp187kbwr`. Predecessor v2.3.3 PR #539 (`k1796s5j6jfkvkx0tn5n926ftd87jx9p`).
175
+ - `list_tasks` and `list_tasks_by_mission` forward `createdBy`, and all four list tools forward `updatedSince`; previously these filters were silently dropped. An omitted `limit` now reaches the backend so its automatic page-size cap applies.
523
176
 
524
177
  ## v2.3.4 — 2026-05-28
525
178
 
526
- **Security fix** — DCR (Dynamic Client Registration) self-registration now defaults to tenant-scope only. Master scope requires explicit admin authorization (`ADMIN_DCR_TOKEN` / `BEARER_SECRET_MASTER` env var). Closes beta blocker for early-access RH cohort onboarding identified in VP Cloud audit 2026-05-28.
527
-
528
- Changes:
529
- - `convex/oauth.ts`: `registerPublicClient` now explicitly rejects `scopeProfile="master"` with a `ScopeViolation` error. Previously only the HTTP server enforced this; the Convex-layer was bypassable via direct internal call.
530
- - `mcp-server/src/auth.ts`: bearer layer 3 (DCR token path) no longer maps `mcp:full` scope string to `scopeProfile="master"`. DCR tokens now always resolve to `client-generic` (deny-by-default). The `mcp:full` label in the legacy `oauthTokens` table was a scope label, not an authorization grant.
531
- - `convex/oauthDcr.ts`: added security documentation clarifying the legacy table is no longer an escalation path; the auth middleware fix is the primary gate.
532
-
533
- Tests: 5 new Convex security tests (`convex/oauth-dcr-security.test.ts`) + 5 new MCP scope enforcement tests (`mcp-server/src/__tests__/dcr-scope-enforcement.test.ts`), 0 regression on existing suites.
179
+ ### Security
534
180
 
535
- VP task: k17218rvqyncs1v6rwj3qdzfsn87jj4n. Beta unblock chain: DCR fix → 5 quick wins onboarding (seed-profiles + early-access RH cohort client + README VP Cloud + runbook + email).
181
+ - Dynamic client registration can no longer obtain operator scope; self-registered clients receive a tenant scope only.
536
182
 
537
183
  ## v2.3.3 — 2026-05-28
538
184
 
539
- **Follow-up to v2.3.2 (2026-05-28 scope élargi)** — Extend list queries with `createdBy` + `updatedSince` filters + auto-clamp safeguard.
540
-
541
- Backend (Convex) :
542
- - `tasks.list` + `tasks.listByMission` : + `createdBy` (filter by task creator) + `updatedSince` (Unix ms window) + auto-clamp limit=30 when `fields="full"` and no explicit limit
543
- - `missions.list` : + `updatedSince` + auto-clamp (30)
544
- - `briefingNotes.list` : + `updatedSince` + auto-clamp (15 when fields=full)
545
-
546
- MCP wrapper :
547
- - 4 list tools forward the new params
548
- - New export `updatedSinceSchema` (positive integer ms)
549
- - `limit` `.default()` removed on the 4 list tools so absent limit flows to backend → enables auto-clamp
550
-
551
- Tests : 15 new MCP schema cases (`src/__tests__/list-queries-v2.3.3-createdby-updatedsince.test.ts`) + 6 new Convex round-trip cases.
552
-
553
- Pi pull cycle unblocked : `list_tasks createdBy="pi" status="review" fields="lite"` returns only Pi-dispatched tasks recently moved to review, payload 5-10× smaller.
554
-
555
- Cap fleet : 0 overflow tolérance future (auto-clamp).
185
+ ### Added
556
186
 
557
- VP task: `k1796s5j6jfkvkx0tn5n926ftd87jx9p`. Successor of `k17e09ng1tf217n93z9m4tr0mx87hfe0` (v2.3.2 PR #537).
187
+ - `createdBy` and `updatedSince` filters on list queries, and an automatic page-size cap when full records are requested without a limit.
558
188
 
559
189
  ## v2.3.2 — 2026-05-28
560
190
 
561
- **Hotfix** — Expose `fields="lite"` + `status` array/aliases in MCP tool schemas (2026-05-26 sprint gap).
562
-
563
- Backend support for these params shipped in v2.3.1 but the MCP wrapper Zod schemas never exposed them, so MCP clients couldn't pass them. Fixed for 4 list tools:
564
-
565
- - `list_tasks`: + `fields`, status now accepts aliases (`"open"`, `"active"`, `"all"`) and arrays
566
- - `list_tasks_by_mission`: same
567
- - `list_missions`: + `fields`, status accepts aliases and arrays
568
- - `list_briefing_notes`: + `fields`
569
-
570
- Aliases NOT permitted inside arrays (matches backend rejection contract).
571
-
572
- Tests: 14 new cases (`src/__tests__/list-queries-schema-v2.3.2.test.ts`), 0 regression on 295+ existing.
573
-
574
- Fix-pattern (fleet-wide): When backend query supports a new param, ALWAYS update the MCP wrapper tool schema in the SAME PR.
191
+ ### Fixed
575
192
 
576
- VP task: `k17e09ng1tf217n93z9m4tr0mx87hfe0`.
193
+ - `list_tasks`, `list_tasks_by_mission`, `list_missions` and `list_briefing_notes` accept `fields="lite"`; the task and mission tools accept status arrays and aliases (`open`, `active`, `all`). Aliases are not allowed inside an array.
577
194
 
578
195
  ## 2.3.1 — 2026-05-26
579
196
 
580
- ### Fixed (Eta PR #530 delta-review)
581
- - `status="all"` now actually returns every row (no filter applied). Previously advertised in 2.3.0 docs but the Convex `expandTaskStatuses` / `expandMissionStatuses` helpers rejected it as invalid.
582
- - `status=["all"]` (alias inside an array) now correctly throws `ConvexError` — same conservative-rejection rule as `"open"` / `"active"`.
583
- - `setPendingAliasReleases` on the Convex backend converted from `mutation` to `internalMutation`. It was a public DoS surface against the auto-IRP pipeline; it is a lifecycle operation only and must not be reachable via MCP.
197
+ ### Fixed
198
+
199
+ - `status="all"` returns every row; `status=["all"]` is rejected like the other aliases inside an array.
584
200
 
585
201
  ## 2.3.0 — 2026-05-26
586
202
 
587
203
  ### Added
588
- - `list_tasks`, `list_missions`, `list_tasks_by_mission`, `list_briefing_notes` now accept `fields=lite` for compact payloads.
589
- - Status filters on `list_tasks`, `list_tasks_by_mission`, and `list_missions` now accept arrays and aliases:
590
- - `status=["todo","in_progress"]` — multi-value array
591
- - `status="open"` — expands to non-terminal statuses (tasks: todo+in_progress+review+blocked; missions: brainstorm+plan+execute+validate)
592
- - `status="active"` — in_progress only on tasks; plan+execute on missions
593
- - `status="all"` — no filter applied
594
-
595
- ### Backward compat
596
- - Single-string status still accepted unchanged.
597
- - Omitting `fields` defaults to `"full"` — existing callers unaffected.
598
204
 
599
- ---
205
+ - `fields=lite` on `list_tasks`, `list_missions`, `list_tasks_by_mission` and `list_briefing_notes` for compact payloads.
206
+ - Status filters accept arrays and the aliases `open` (non-terminal), `active` and `all`. A single status string and an omitted `fields` behave as before.
600
207
 
601
208
  ## 2.2.0 — 2026-05-07
602
209
 
603
- - 4 new fix-pattern tools: `create_fix_pattern`, `add_fix_attempt`, `validate_fix`, `link_issue_to_pattern`
604
- - Detailed per-tool docs with arg tables and example calls in README
605
- - New "Fix patterns cycle" section documenting the KB learning loop
606
- - 41 new Zod input-validation unit tests for fix-pattern tools
210
+ - New fix-pattern tools: `create_fix_pattern`, `add_fix_attempt`, `validate_fix`, `link_issue_to_pattern`.
211
+ - Per-tool documentation with argument tables and examples.
607
212
 
608
213
  ## 2.1.1 — 2026-05-04
609
214
 
610
- - Defense-in-depth `memoryIdSchema` validation for `create_briefing_note` and `update_briefing_note`
215
+ - Stricter memory ID validation on `create_briefing_note` and `update_briefing_note`.
611
216
 
612
217
  ## 2.1.0 — 2026-04-25
613
218
 
614
- - `update_briefing_note` MCP tool with RBAC
219
+ - `update_briefing_note` with role-based access control.
615
220
 
616
221
  ## 2.0.2 — 2026-04-14
617
222
 
618
- - Added badges (npm version, downloads, license, tool count) to the published README
619
- - Added Orchestrator Roles reference table including alpha, lambda, victor
620
- - Added note that any custom lowercase role name is accepted
621
- - Added `bugs` URL and additional keywords to `package.json`
223
+ - README badges, `bugs` URL and keywords in `package.json`. Any lowercase agent name is accepted.
622
224
 
623
225
  ## 2.0.1 — 2026-04-14
624
226
 
625
- - Docstring fix in server.ts (minor)
227
+ - Docstring fix.
626
228
 
627
229
  ## 2.0.0
628
230
 
629
- - Type-safe `api.ts` export for cross-deployment calls (`vantage-peers-mcp/api`)
630
- - Deploy key authentication guide
631
- - Mission Templates category (1 tool: `update_mission_template`)
632
- - Programmatic API section in README
231
+ - Typed function references for calling a deployment directly (`vantage-peers-mcp/api`).
232
+ - Deploy-key authentication guide.
233
+ - `update_mission_template`.
633
234
 
634
235
  ## 1.x
635
236
 
636
- - Initial public release with 82 MCP tools
237
+ - Initial public release.