vantage-peers-mcp 2.17.0 → 2.18.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 +5 -0
- package/README.md +1 -1
- package/dist/server.js +1 -1
- package/dist/src/tools.js +88 -0
- package/package.json +2 -1
- package/tool-exposure.json +70 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.18.0] — 2026-08-11
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- **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.
|
|
7
|
+
|
|
3
8
|
## [2.17.0] — 2026-08-11
|
|
4
9
|
|
|
5
10
|
### Removed
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[]()
|
|
7
7
|
|
|
8
8
|
> **Package:** `vantage-peers-mcp` (plain — NOT `@vantageos/vantage-peers-mcp`)
|
|
9
|
-
> **Current version:** `2.
|
|
9
|
+
> **Current version:** `2.18.0` (S8 CORE tool-exposure filter release — server now advertises only 66 CORE tools of 109 registered; masking is data-driven (`tool-exposure.json`) and reversible, non-CORE tools stay registered/handler-wired but are not listed)
|
|
10
10
|
> **License:** FSL-1.1-Apache-2.0
|
|
11
11
|
> **Repo:** https://github.com/vantageos-agency/vantage-peers (full monorepo README at `/README.md`)
|
|
12
12
|
> **Docs:** https://vantagepeers.com/docs
|
package/dist/server.js
CHANGED
|
@@ -57,7 +57,7 @@ const convexUrl = loadConvexUrl();
|
|
|
57
57
|
const convex = new ConvexHttpClient(convexUrl);
|
|
58
58
|
const server = new McpServer({
|
|
59
59
|
name: "vantage-peers",
|
|
60
|
-
version: "2.
|
|
60
|
+
version: "2.18.0",
|
|
61
61
|
});
|
|
62
62
|
// stdio transport has no OAuth identity → pass oauthCtx=undefined to opt into
|
|
63
63
|
// the legacy bearer / system-scope code path inside registerTools (same path
|
package/dist/src/tools.js
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
11
11
|
import { LEGACY_WILDCARD_CTX, scopeFilterGet, scopeFilterList, } from "@vantageos/cloud-identity";
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
13
|
+
import { dirname, resolve } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
12
15
|
import { z } from "zod";
|
|
13
16
|
import { checkFromAllowed, checkNamespaceRead, checkNamespaceWrite, isMasterScope, } from "./auth.js";
|
|
14
17
|
import { FreshStateGuardError, guardFreshState } from "./fresh-state-guard.js";
|
|
@@ -1232,7 +1235,88 @@ export const validateTaskPayloadOutputSchema = z.object({
|
|
|
1232
1235
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
1233
1236
|
// Main export: register all tools against a server + convex client pair
|
|
1234
1237
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
1238
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1239
|
+
// Tool exposure filter — DATA-DRIVEN CORE allowlist (S8, mission
|
|
1240
|
+
// vp-mcp-alias-cleanup-v1). Only tool names listed in `core` inside
|
|
1241
|
+
// tool-exposure.json are registered/advertised to clients; every other tool
|
|
1242
|
+
// stays fully present in the code + DB, just not exposed. The list lives as
|
|
1243
|
+
// DATA, never a code constant — reverting = editing tool-exposure.json.
|
|
1244
|
+
// VP_TOOL_EXPOSURE_PATH overrides the path for tests only.
|
|
1245
|
+
//
|
|
1246
|
+
// Derived from analysis/vantagepeers/vp-restructuring/vp-by-tool-day158.csv
|
|
1247
|
+
// (outil column where T2_verdict == "CORE"), intersected with the
|
|
1248
|
+
// actually-registered tool-name set — see tool-exposure.json's own header.
|
|
1249
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1250
|
+
function resolveToolExposurePath() {
|
|
1251
|
+
if (process.env.VP_TOOL_EXPOSURE_PATH) {
|
|
1252
|
+
return resolve(process.env.VP_TOOL_EXPOSURE_PATH);
|
|
1253
|
+
}
|
|
1254
|
+
// This module resolves at "<mcp-server>/src/tools.ts" when run from source
|
|
1255
|
+
// (bun run server.ts) and at "<mcp-server>/dist/src/tools.js" when run from
|
|
1256
|
+
// the tsc build (dist/server.js) — tool-exposure.json always lives at the
|
|
1257
|
+
// mcp-server package root, one directory further up in the built case.
|
|
1258
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
1259
|
+
const fromSource = resolve(here, "../tool-exposure.json");
|
|
1260
|
+
const fromDist = resolve(here, "../../tool-exposure.json");
|
|
1261
|
+
try {
|
|
1262
|
+
readFileSync(fromSource, "utf-8");
|
|
1263
|
+
return fromSource;
|
|
1264
|
+
}
|
|
1265
|
+
catch {
|
|
1266
|
+
return fromDist;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
function loadCoreToolNames() {
|
|
1270
|
+
const path = resolveToolExposurePath();
|
|
1271
|
+
let raw;
|
|
1272
|
+
try {
|
|
1273
|
+
raw = readFileSync(path, "utf-8");
|
|
1274
|
+
}
|
|
1275
|
+
catch (err) {
|
|
1276
|
+
throw new Error(`tool-exposure: failed to read ${path}: ${err.message}`);
|
|
1277
|
+
}
|
|
1278
|
+
let parsed;
|
|
1279
|
+
try {
|
|
1280
|
+
parsed = JSON.parse(raw);
|
|
1281
|
+
}
|
|
1282
|
+
catch (err) {
|
|
1283
|
+
throw new Error(`tool-exposure: invalid JSON in ${path}: ${err.message}`);
|
|
1284
|
+
}
|
|
1285
|
+
const core = parsed?.core;
|
|
1286
|
+
if (!Array.isArray(core) || !core.every((n) => typeof n === "string")) {
|
|
1287
|
+
throw new Error(`tool-exposure: "core" must be an array of strings in ${path}`);
|
|
1288
|
+
}
|
|
1289
|
+
return core;
|
|
1290
|
+
}
|
|
1235
1291
|
export function registerTools(server, convex, oauthCtx) {
|
|
1292
|
+
// Intercept EVERY server.tool(...) call made below (directly or through
|
|
1293
|
+
// defineTool()/registerExportOkfBundle()/registerImportOkfBundle()/
|
|
1294
|
+
// registerKbIngestTools()/registerValidateOkfBundle() — they all receive
|
|
1295
|
+
// this same `server` instance) so only CORE names are actually advertised.
|
|
1296
|
+
//
|
|
1297
|
+
// The registration itself always goes through — the tool stays fully
|
|
1298
|
+
// present in the code + handler wiring (masking ≠ deletion; a non-CORE
|
|
1299
|
+
// tool's handler is still reachable in-process, e.g. by existing unit
|
|
1300
|
+
// tests that capture registrations against a stub McpServer). What is
|
|
1301
|
+
// masked is client-facing ADVERTISEMENT: a non-CORE tool is immediately
|
|
1302
|
+
// `.disable()`d on its returned RegisteredTool, which is the MCP SDK's own
|
|
1303
|
+
// mechanism for keeping a tool out of `tools/list` (server/mcp.js filters
|
|
1304
|
+
// `tool.enabled` when building that list) while refusing `tools/call` on
|
|
1305
|
+
// it with an explicit "Tool <name> disabled" error — never a silent
|
|
1306
|
+
// unregistration.
|
|
1307
|
+
const coreToolNames = new Set(loadCoreToolNames());
|
|
1308
|
+
const allRegisteredNames = new Set();
|
|
1309
|
+
const realTool = server.tool.bind(server);
|
|
1310
|
+
// biome-ignore lint/suspicious/noExplicitAny: narrowing the overloaded McpServer#tool signature for interception.
|
|
1311
|
+
server.tool = (name, ...rest) => {
|
|
1312
|
+
allRegisteredNames.add(name);
|
|
1313
|
+
// @ts-expect-error — forwarding to the real overloaded signature.
|
|
1314
|
+
const registered = realTool(name, ...rest);
|
|
1315
|
+
if (!coreToolNames.has(name) && registered && typeof registered.disable === "function") {
|
|
1316
|
+
registered.disable();
|
|
1317
|
+
}
|
|
1318
|
+
return registered;
|
|
1319
|
+
};
|
|
1236
1320
|
// ── scope guards (no-op when oauthCtx is undefined — legacy bearer path) ────
|
|
1237
1321
|
const guardFrom = (from) => {
|
|
1238
1322
|
const err = checkFromAllowed(oauthCtx, from);
|
|
@@ -7216,4 +7300,8 @@ export function registerTools(server, convex, oauthCtx) {
|
|
|
7216
7300
|
return mcpConvexError(error);
|
|
7217
7301
|
}
|
|
7218
7302
|
});
|
|
7303
|
+
const missingCoreNames = [...coreToolNames].filter((name) => !allRegisteredNames.has(name));
|
|
7304
|
+
if (missingCoreNames.length > 0) {
|
|
7305
|
+
throw new Error(`tool-exposure: core name(s) not found among registered tools: ${missingCoreNames.join(", ")}`);
|
|
7306
|
+
}
|
|
7219
7307
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vantage-peers-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "MCP server for VantagePeers — shared memory, messaging, and task coordination for AI agent teams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/server.js",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist/",
|
|
19
|
+
"tool-exposure.json",
|
|
19
20
|
"README.md",
|
|
20
21
|
"CHANGELOG.md"
|
|
21
22
|
],
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"core": [
|
|
3
|
+
"add_task_dependency",
|
|
4
|
+
"billing_summary_by_project",
|
|
5
|
+
"block_task",
|
|
6
|
+
"bulk_complete_tasks",
|
|
7
|
+
"check_messages",
|
|
8
|
+
"checkout_task",
|
|
9
|
+
"complete_task",
|
|
10
|
+
"create_briefing_note",
|
|
11
|
+
"create_mission",
|
|
12
|
+
"create_recurring_task",
|
|
13
|
+
"create_task",
|
|
14
|
+
"delete_message",
|
|
15
|
+
"delete_recurring_task",
|
|
16
|
+
"delete_task",
|
|
17
|
+
"export_okf_bundle",
|
|
18
|
+
"get_briefing_note",
|
|
19
|
+
"get_diary",
|
|
20
|
+
"get_episode",
|
|
21
|
+
"get_memory",
|
|
22
|
+
"get_message",
|
|
23
|
+
"get_mission",
|
|
24
|
+
"get_mission_template",
|
|
25
|
+
"get_profile",
|
|
26
|
+
"get_recurring_task",
|
|
27
|
+
"get_task",
|
|
28
|
+
"hybrid_search",
|
|
29
|
+
"import_okf_bundle",
|
|
30
|
+
"improvisation_digest",
|
|
31
|
+
"instantiate_template_into_mission",
|
|
32
|
+
"list_briefing_notes",
|
|
33
|
+
"list_broadcast_status",
|
|
34
|
+
"list_diaries",
|
|
35
|
+
"list_episodes",
|
|
36
|
+
"list_memories",
|
|
37
|
+
"list_messages",
|
|
38
|
+
"list_missions",
|
|
39
|
+
"list_peers",
|
|
40
|
+
"list_recurring_tasks",
|
|
41
|
+
"list_tasks",
|
|
42
|
+
"list_tasks_by_mission",
|
|
43
|
+
"mark_as_read",
|
|
44
|
+
"pause_recurring_task",
|
|
45
|
+
"recall",
|
|
46
|
+
"resume_recurring_task",
|
|
47
|
+
"search_briefing_notes_by_keyword",
|
|
48
|
+
"search_episodes_by_keyword",
|
|
49
|
+
"search_episodes_by_semantic",
|
|
50
|
+
"search_messages_by_keyword",
|
|
51
|
+
"search_tasks_by_keyword",
|
|
52
|
+
"send_message",
|
|
53
|
+
"set_summary",
|
|
54
|
+
"soft_delete_document",
|
|
55
|
+
"soft_delete_memory",
|
|
56
|
+
"start_task",
|
|
57
|
+
"store_document_chunked",
|
|
58
|
+
"store_episode",
|
|
59
|
+
"store_memory",
|
|
60
|
+
"text_search",
|
|
61
|
+
"update_briefing_note",
|
|
62
|
+
"update_mission",
|
|
63
|
+
"update_mission_status",
|
|
64
|
+
"update_mission_template",
|
|
65
|
+
"update_profile",
|
|
66
|
+
"update_recurring_task",
|
|
67
|
+
"update_task",
|
|
68
|
+
"write_diary"
|
|
69
|
+
]
|
|
70
|
+
}
|