vantage-peers-mcp 2.14.1 → 2.14.2
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 +4 -0
- package/README.md +1 -1
- package/dist/server-http.js +49 -4
- package/package.json +93 -93
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.14.2 — 2026-06-30
|
|
4
|
+
|
|
5
|
+
- 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.
|
|
6
|
+
|
|
3
7
|
## [Unreleased]
|
|
4
8
|
|
|
5
9
|
### Added
|
package/README.md
CHANGED
|
@@ -171,7 +171,7 @@ VantagePeers ships a built-in OAuth 2.1 authorization server so Claude.ai web ca
|
|
|
171
171
|
|--------|------|-------------|
|
|
172
172
|
| `GET` | `/.well-known/oauth-authorization-server` | Authorization Server Metadata (RFC 8414) — advertises supported grant types, endpoints, and capabilities |
|
|
173
173
|
| `GET` | `/.well-known/oauth-protected-resource` | Protected Resource Metadata (RFC 9728) — links back to the authorization server |
|
|
174
|
-
| `POST` | `/register` | Dynamic Client Registration (RFC 7591) — Claude.ai registers itself automatically on first connect |
|
|
174
|
+
| `POST` | `/register` | Dynamic Client Registration (RFC 7591) — Claude.ai registers itself automatically on first connect. `redirect_uris` MUST be a non-empty array of valid `https://` URIs (or `http://localhost` / `http://127.0.0.1` for dev); absent, empty, non-string, unparseable, non-https, or fragment-bearing entries are rejected with `invalid_redirect_uri` (RFC 7591 §3.2.2, commit `2f3e653`). |
|
|
175
175
|
| `GET` | `/authorize` | Authorization endpoint — redirects the user to grant access |
|
|
176
176
|
| `POST` | `/token` | Token endpoint — issues access tokens per OAuth 2.1 |
|
|
177
177
|
|
package/dist/server-http.js
CHANGED
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
import { readFileSync } from "node:fs";
|
|
28
28
|
import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
29
29
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
30
|
+
import { timingSafeEqual } from "@vantageos/cloud-identity";
|
|
30
31
|
import { ConvexHttpClient } from "convex/browser";
|
|
31
32
|
import { Hono } from "hono";
|
|
32
33
|
import { cors } from "hono/cors";
|
|
33
34
|
import { bearerAuthMiddleware, internalClient, masterOnlyMiddleware, sha256Base64Url, sha256Hex, } from "./src/auth.js";
|
|
34
|
-
import { timingSafeEqual } from "@vantageos/cloud-identity";
|
|
35
35
|
import { registerTools } from "./src/tools.js";
|
|
36
36
|
import { listUiResources, readUiResource } from "./src/ui-resources/index.js";
|
|
37
37
|
let pkg;
|
|
@@ -262,9 +262,54 @@ app.post("/register", async (c) => {
|
|
|
262
262
|
catch {
|
|
263
263
|
// allow empty body — Claude sometimes posts nothing
|
|
264
264
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
265
|
+
// RFC 7591 §2: redirect_uris is REQUIRED for authorization_code grant.
|
|
266
|
+
// RFC 7591 §3.2.2: invalid_redirect_uri is the canonical error code for
|
|
267
|
+
// bad, missing, or empty redirect_uris. Reject here so zombie clients
|
|
268
|
+
// (e.g. prod 87abdf5c-616b-4767-8a96-5ca04db88d9f) can never be created.
|
|
269
|
+
if (!Array.isArray(body.redirect_uris) ||
|
|
270
|
+
body.redirect_uris.length === 0) {
|
|
271
|
+
return c.json({
|
|
272
|
+
error: "invalid_redirect_uri",
|
|
273
|
+
error_description: "redirect_uris is required and must be a non-empty array of valid HTTPS URIs",
|
|
274
|
+
}, 400);
|
|
275
|
+
}
|
|
276
|
+
// Validate each URI: must be parseable and https: scheme (or http://localhost
|
|
277
|
+
// for dev). Reject file://, javascript:, data:, fragments, etc.
|
|
278
|
+
for (const uri of body.redirect_uris) {
|
|
279
|
+
if (typeof uri !== "string") {
|
|
280
|
+
return c.json({
|
|
281
|
+
error: "invalid_redirect_uri",
|
|
282
|
+
error_description: "redirect_uris is required and must be a non-empty array of valid HTTPS URIs",
|
|
283
|
+
}, 400);
|
|
284
|
+
}
|
|
285
|
+
let parsed;
|
|
286
|
+
try {
|
|
287
|
+
parsed = new URL(uri);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
return c.json({
|
|
291
|
+
error: "invalid_redirect_uri",
|
|
292
|
+
error_description: "redirect_uris is required and must be a non-empty array of valid HTTPS URIs",
|
|
293
|
+
}, 400);
|
|
294
|
+
}
|
|
295
|
+
const isHttpsScheme = parsed.protocol === "https:";
|
|
296
|
+
const isLocalhostHttp = parsed.protocol === "http:" &&
|
|
297
|
+
(parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1");
|
|
298
|
+
if (!isHttpsScheme && !isLocalhostHttp) {
|
|
299
|
+
return c.json({
|
|
300
|
+
error: "invalid_redirect_uri",
|
|
301
|
+
error_description: "redirect_uris is required and must be a non-empty array of valid HTTPS URIs",
|
|
302
|
+
}, 400);
|
|
303
|
+
}
|
|
304
|
+
// Reject URIs with fragments (RFC 6749 §3.1.2)
|
|
305
|
+
if (parsed.hash) {
|
|
306
|
+
return c.json({
|
|
307
|
+
error: "invalid_redirect_uri",
|
|
308
|
+
error_description: "redirect_uris is required and must be a non-empty array of valid HTTPS URIs",
|
|
309
|
+
}, 400);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
const redirectUris = body.redirect_uris;
|
|
268
313
|
const clientId = crypto.randomUUID();
|
|
269
314
|
const clientSecret = randomOpaqueToken();
|
|
270
315
|
const clientSecretHash = await sha256Hex(clientSecret);
|
package/package.json
CHANGED
|
@@ -1,95 +1,95 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
2
|
+
"name": "vantage-peers-mcp",
|
|
3
|
+
"version": "2.14.2",
|
|
4
|
+
"description": "MCP server for VantagePeers — shared memory, messaging, and task coordination for AI agent teams",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/server.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./dist/server.js",
|
|
9
|
+
"./api": {
|
|
10
|
+
"types": "./dist/api.d.ts",
|
|
11
|
+
"default": "./dist/api.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"vantage-peers-mcp": "./dist/server.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/",
|
|
19
|
+
"README.md",
|
|
20
|
+
"CHANGELOG.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"generate:api": "cd .. && npx convex-helpers ts-api-spec --prod --output-file mcp-server/api.ts",
|
|
24
|
+
"build": "tsc --project tsconfig.json",
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
26
|
+
"dev": "bun run server.ts",
|
|
27
|
+
"start": "bun run dist/server-http.js",
|
|
28
|
+
"dev:http": "bun run server-http.ts",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test:coverage": "vitest run --coverage"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/vantageos-agency/vantage-peers.git",
|
|
36
|
+
"directory": "mcp-server"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://vantagepeers.com/docs",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/vantageos-agency/vantage-peers/issues"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"mcp",
|
|
44
|
+
"claude",
|
|
45
|
+
"convex",
|
|
46
|
+
"ai-agents",
|
|
47
|
+
"memory",
|
|
48
|
+
"messaging",
|
|
49
|
+
"tasks",
|
|
50
|
+
"multi-agent",
|
|
51
|
+
"orchestration",
|
|
52
|
+
"vantagepeers",
|
|
53
|
+
"diary",
|
|
54
|
+
"episodes",
|
|
55
|
+
"mandates",
|
|
56
|
+
"knowledge-base",
|
|
57
|
+
"rag",
|
|
58
|
+
"vector-search"
|
|
59
|
+
],
|
|
60
|
+
"author": "VantageOS AI Orchestrator Team",
|
|
61
|
+
"contributors": [
|
|
62
|
+
"Pi (π) — Lead orchestrator",
|
|
63
|
+
"Laurent Perello — Founder, supervisor",
|
|
64
|
+
"ElPi Corp"
|
|
65
|
+
],
|
|
66
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"@mcp-ui/server": "^6.1.0",
|
|
69
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
70
|
+
"@vantageos/cloud-identity": "^0.1.0",
|
|
71
|
+
"@vantageos/mosaic": "^0.1.2",
|
|
72
|
+
"convex": ">=1.0.0",
|
|
73
|
+
"dotenv": "^17.4.2",
|
|
74
|
+
"zod": "^4.3.6"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"convex": ">=1.0.0"
|
|
78
|
+
},
|
|
79
|
+
"devDependencies": {
|
|
80
|
+
"@types/node": "^24.12.2",
|
|
81
|
+
"@vitest/coverage-v8": "^4.1.8",
|
|
82
|
+
"typescript": "^5.9.3",
|
|
83
|
+
"vitest": "^4.1.8"
|
|
84
|
+
},
|
|
85
|
+
"overrides": {
|
|
86
|
+
"path-to-regexp": "^8.4.0"
|
|
87
|
+
},
|
|
88
|
+
"engines": {
|
|
89
|
+
"node": ">=20"
|
|
90
|
+
},
|
|
91
|
+
"publishConfig": {
|
|
92
|
+
"access": "public",
|
|
93
|
+
"provenance": true
|
|
94
|
+
}
|
|
95
95
|
}
|