@codemem/mcp 0.37.0 → 0.38.0-alpha.1
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/dist/http.js +234 -227
- package/dist/http.js.map +1 -1
- package/dist/oauth.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/http.js
CHANGED
|
@@ -10,10 +10,10 @@ import { StreamableHTTPServerTransport as d } from "@modelcontextprotocol/sdk/se
|
|
|
10
10
|
import f from "express";
|
|
11
11
|
import { Buffer as p } from "node:buffer";
|
|
12
12
|
import { createHash as m, createHmac as h, createPublicKey as g, randomBytes as _, randomUUID as v, timingSafeEqual as y, verify as b } from "node:crypto";
|
|
13
|
-
import { existsSync as
|
|
14
|
-
import { chmod as
|
|
15
|
-
import { homedir as
|
|
16
|
-
import { dirname as
|
|
13
|
+
import { existsSync as x, mkdirSync as S, readFileSync as C, renameSync as ee, writeFileSync as w } from "node:fs";
|
|
14
|
+
import { chmod as T } from "node:fs/promises";
|
|
15
|
+
import { homedir as E } from "node:os";
|
|
16
|
+
import { dirname as D, join as te } from "node:path";
|
|
17
17
|
import { AccessDeniedError as ne, InvalidClientError as re, InvalidClientMetadataError as O, InvalidGrantError as k, InvalidRequestError as ie, InvalidTokenError as ae, ServerError as oe, TemporarilyUnavailableError as A, UnsupportedResponseTypeError as se } from "@modelcontextprotocol/sdk/server/auth/errors.js";
|
|
18
18
|
import { OAuthProtectedResourceMetadataSchema as ce, OAuthTokensSchema as le } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
19
19
|
//#region \0rolldown/runtime.js
|
|
@@ -1114,21 +1114,21 @@ function We(e = process.env.CODEMEM_MCP_AUDIT) {
|
|
|
1114
1114
|
let t = e?.trim().toLowerCase();
|
|
1115
1115
|
return t === "0" || t === "false" || t === "no" ? Ue() : He();
|
|
1116
1116
|
}
|
|
1117
|
-
var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github.com/kunickiaj/codemem#readme", Ke = "https://claude.ai/api/mcp/auth_callback", qe = new Set([
|
|
1117
|
+
var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github.com/kunickiaj/codemem#readme", Ke = "https://claude.ai/api/mcp/auth_callback", qe = "https://chatgpt.com/connector_platform_oauth_redirect", Je = new Set([
|
|
1118
1118
|
"localhost",
|
|
1119
1119
|
"127.0.0.1",
|
|
1120
1120
|
"::1"
|
|
1121
|
-
]),
|
|
1121
|
+
]), Ye = new Set(["authorization_code", "refresh_token"]), Xe = new Set(["code"]), B = 3600, V = 720 * 60 * 60, Ze = 100, Qe = 100, $e = 100, et = 32, tt = 43, nt = /^[A-Za-z0-9_-]{43}$/, rt = /^[A-Za-z0-9_-]{43}$/, it = /^[A-Za-z0-9_-]{1,128}$/, at = class {
|
|
1122
1122
|
#e = /* @__PURE__ */ new Map();
|
|
1123
1123
|
getClient(e) {
|
|
1124
1124
|
return this.#e.get(e);
|
|
1125
1125
|
}
|
|
1126
1126
|
registerClient(e) {
|
|
1127
|
-
let t =
|
|
1127
|
+
let t = xt(e.redirect_uris);
|
|
1128
1128
|
if (t) throw new O(t);
|
|
1129
1129
|
if (e.client_secret || e.token_endpoint_auth_method !== "none") throw new O("Only public clients with token_endpoint_auth_method=none are supported");
|
|
1130
|
-
if (e.grant_types && !H(e.grant_types,
|
|
1131
|
-
if (e.response_types && !H(e.response_types,
|
|
1130
|
+
if (e.grant_types && !H(e.grant_types, Ye)) throw new O("Only authorization_code and refresh_token grant_types are supported");
|
|
1131
|
+
if (e.response_types && !H(e.response_types, Xe)) throw new O("Only code response_type is supported");
|
|
1132
1132
|
if (this.#e.size >= 100) {
|
|
1133
1133
|
let e = this.#e.keys().next().value;
|
|
1134
1134
|
e && this.#e.delete(e);
|
|
@@ -1143,10 +1143,10 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1143
1143
|
};
|
|
1144
1144
|
return this.#e.set(n.client_id, n), n;
|
|
1145
1145
|
}
|
|
1146
|
-
},
|
|
1146
|
+
}, ot = class {
|
|
1147
1147
|
#e = /* @__PURE__ */ new Map();
|
|
1148
1148
|
issueCode(e, t = Date.now()) {
|
|
1149
|
-
if (this.#t(t), this.#e.size >=
|
|
1149
|
+
if (this.#t(t), this.#e.size >= Ze) return;
|
|
1150
1150
|
let n = v();
|
|
1151
1151
|
return this.#e.set(n, {
|
|
1152
1152
|
...e,
|
|
@@ -1164,12 +1164,12 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1164
1164
|
#t(e) {
|
|
1165
1165
|
for (let [t, n] of this.#e) n.expiresAt <= e && this.#e.delete(t);
|
|
1166
1166
|
}
|
|
1167
|
-
},
|
|
1167
|
+
}, st = class {
|
|
1168
1168
|
#e = /* @__PURE__ */ new Map();
|
|
1169
1169
|
#t = _(32);
|
|
1170
1170
|
issueToken(e, t = Date.now(), n, r, i = []) {
|
|
1171
|
-
if (this.#n(t), this.#e.size >=
|
|
1172
|
-
let a = _(
|
|
1171
|
+
if (this.#n(t), this.#e.size >= Qe) return;
|
|
1172
|
+
let a = _(et), o = kt(a, this.#t);
|
|
1173
1173
|
return this.#e.set(o, {
|
|
1174
1174
|
clientId: e,
|
|
1175
1175
|
grantId: r,
|
|
@@ -1191,7 +1191,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1191
1191
|
ok: !1,
|
|
1192
1192
|
reason: "unknown_token"
|
|
1193
1193
|
};
|
|
1194
|
-
let r =
|
|
1194
|
+
let r = kt(n, this.#t), i = this.#e.get(r);
|
|
1195
1195
|
return !i || !J(i.tokenHash, r) ? {
|
|
1196
1196
|
ok: !1,
|
|
1197
1197
|
reason: "unknown_token"
|
|
@@ -1209,7 +1209,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1209
1209
|
revokeToken(e, t = Date.now()) {
|
|
1210
1210
|
let n = W(e);
|
|
1211
1211
|
if (!n) return !1;
|
|
1212
|
-
let r =
|
|
1212
|
+
let r = kt(n, this.#t), i = this.#e.get(r);
|
|
1213
1213
|
return !i || !J(i.tokenHash, r) ? !1 : (i.revokedAt === null && (i.revokedAt = t), !0);
|
|
1214
1214
|
}
|
|
1215
1215
|
revokeTokensForGrant(e, t = Date.now()) {
|
|
@@ -1220,13 +1220,13 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1220
1220
|
#n(e) {
|
|
1221
1221
|
for (let [t, n] of this.#e) (n.expiresAt <= e || n.revokedAt !== null) && this.#e.delete(t);
|
|
1222
1222
|
}
|
|
1223
|
-
},
|
|
1223
|
+
}, ct = class {
|
|
1224
1224
|
#e = /* @__PURE__ */ new Map();
|
|
1225
1225
|
#t = /* @__PURE__ */ new Map();
|
|
1226
1226
|
#n = /* @__PURE__ */ new Map();
|
|
1227
1227
|
#r = _(32);
|
|
1228
1228
|
issueGrant(e, t = Date.now()) {
|
|
1229
|
-
if (this.#i(t), this.#e.size >=
|
|
1229
|
+
if (this.#i(t), this.#e.size >= $e) return;
|
|
1230
1230
|
let n = G(), r = K(n, this.#r);
|
|
1231
1231
|
if (!r) return;
|
|
1232
1232
|
let i = {
|
|
@@ -1281,7 +1281,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1281
1281
|
reason: "client_mismatch",
|
|
1282
1282
|
grantId: a
|
|
1283
1283
|
};
|
|
1284
|
-
if (!
|
|
1284
|
+
if (!jt(n.scopes ?? o.scopes, o.scopes)) return {
|
|
1285
1285
|
ok: !1,
|
|
1286
1286
|
reason: "scope_mismatch",
|
|
1287
1287
|
grantId: a
|
|
@@ -1333,7 +1333,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1333
1333
|
}
|
|
1334
1334
|
this.#t.delete(e.currentRefreshTokenHash), e.previousRefreshTokenHash && this.#t.delete(e.previousRefreshTokenHash);
|
|
1335
1335
|
}
|
|
1336
|
-
},
|
|
1336
|
+
}, lt = class {
|
|
1337
1337
|
#e;
|
|
1338
1338
|
#t = /* @__PURE__ */ new Map();
|
|
1339
1339
|
#n = /* @__PURE__ */ new Map();
|
|
@@ -1341,18 +1341,18 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1341
1341
|
#i = /* @__PURE__ */ new Map();
|
|
1342
1342
|
#a = /* @__PURE__ */ new Map();
|
|
1343
1343
|
#o = /* @__PURE__ */ new Map();
|
|
1344
|
-
constructor(e =
|
|
1344
|
+
constructor(e = ht()) {
|
|
1345
1345
|
this.#e = e, this.#s();
|
|
1346
1346
|
}
|
|
1347
1347
|
getClient(e) {
|
|
1348
1348
|
return this.#n.get(e);
|
|
1349
1349
|
}
|
|
1350
1350
|
registerClient(e) {
|
|
1351
|
-
let t =
|
|
1351
|
+
let t = xt(e.redirect_uris);
|
|
1352
1352
|
if (t) throw new O(t);
|
|
1353
1353
|
if (e.client_secret || e.token_endpoint_auth_method !== "none") throw new O("Only public clients with token_endpoint_auth_method=none are supported");
|
|
1354
|
-
if (e.grant_types && !H(e.grant_types,
|
|
1355
|
-
if (e.response_types && !H(e.response_types,
|
|
1354
|
+
if (e.grant_types && !H(e.grant_types, Ye)) throw new O("Only authorization_code and refresh_token grant_types are supported");
|
|
1355
|
+
if (e.response_types && !H(e.response_types, Xe)) throw new O("Only code response_type is supported");
|
|
1356
1356
|
if (this.#u(Date.now()), this.#n.size >= 100) {
|
|
1357
1357
|
let e = this.#n.keys().next().value;
|
|
1358
1358
|
e && this.#n.delete(e);
|
|
@@ -1368,7 +1368,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1368
1368
|
return this.#n.set(n.client_id, n), this.#c(), n;
|
|
1369
1369
|
}
|
|
1370
1370
|
issueCode(e, t = Date.now()) {
|
|
1371
|
-
if (this.#l(t), this.#t.size >=
|
|
1371
|
+
if (this.#l(t), this.#t.size >= Ze) return;
|
|
1372
1372
|
let n = v();
|
|
1373
1373
|
return this.#t.set(n, {
|
|
1374
1374
|
...e,
|
|
@@ -1384,7 +1384,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1384
1384
|
if (!(!t || t.used)) return t.used = !0, t;
|
|
1385
1385
|
}
|
|
1386
1386
|
issueToken(e, t = Date.now(), n, r, i = []) {
|
|
1387
|
-
if (this.#u(t), this.#r.size >=
|
|
1387
|
+
if (this.#u(t), this.#r.size >= Qe) return;
|
|
1388
1388
|
let a = G(), o = q(a);
|
|
1389
1389
|
if (o) return this.#r.set(o, {
|
|
1390
1390
|
clientId: e,
|
|
@@ -1437,7 +1437,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1437
1437
|
return n > 0 && this.#c(), n;
|
|
1438
1438
|
}
|
|
1439
1439
|
issueGrant(e, t = Date.now()) {
|
|
1440
|
-
if (this.#u(t), this.#i.size >=
|
|
1440
|
+
if (this.#u(t), this.#i.size >= $e) return;
|
|
1441
1441
|
let n = G(), r = q(n);
|
|
1442
1442
|
if (!r) return;
|
|
1443
1443
|
let i = {
|
|
@@ -1492,7 +1492,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1492
1492
|
reason: "client_mismatch",
|
|
1493
1493
|
grantId: a
|
|
1494
1494
|
};
|
|
1495
|
-
if (!
|
|
1495
|
+
if (!jt(n.scopes ?? o.scopes, o.scopes)) return {
|
|
1496
1496
|
ok: !1,
|
|
1497
1497
|
reason: "scope_mismatch",
|
|
1498
1498
|
grantId: a
|
|
@@ -1533,10 +1533,10 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1533
1533
|
return n ? n.revokedAt === null ? (n.revokedAt = t, this.#d(n), this.#c(), !0) : !0 : !1;
|
|
1534
1534
|
}
|
|
1535
1535
|
#s() {
|
|
1536
|
-
if (!
|
|
1536
|
+
if (!x(this.#e)) return;
|
|
1537
1537
|
let e;
|
|
1538
1538
|
try {
|
|
1539
|
-
e = JSON.parse(
|
|
1539
|
+
e = JSON.parse(C(this.#e, "utf8"));
|
|
1540
1540
|
} catch {
|
|
1541
1541
|
return;
|
|
1542
1542
|
}
|
|
@@ -1551,7 +1551,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1551
1551
|
}
|
|
1552
1552
|
}
|
|
1553
1553
|
#c() {
|
|
1554
|
-
|
|
1554
|
+
S(D(this.#e), {
|
|
1555
1555
|
recursive: !0,
|
|
1556
1556
|
mode: 448
|
|
1557
1557
|
});
|
|
@@ -1562,7 +1562,7 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1562
1562
|
refreshGrants: [...this.#i.values()],
|
|
1563
1563
|
refreshHashesByGrantId: Object.fromEntries([...this.#o.entries()].map(([e, t]) => [e, [...t]]))
|
|
1564
1564
|
}, t = `${this.#e}.${process.pid}.${Date.now()}.tmp`;
|
|
1565
|
-
|
|
1565
|
+
w(t, `${JSON.stringify(e, null, 2)}\n`, { mode: 384 }), ee(t, this.#e), T(this.#e, 384).catch(() => void 0);
|
|
1566
1566
|
}
|
|
1567
1567
|
#l(e) {
|
|
1568
1568
|
for (let [t, n] of this.#t) n.expiresAt <= e && this.#t.delete(t);
|
|
@@ -1583,29 +1583,29 @@ var Ge = "codemem MCP", R = ["memory:read", "memory:write"], z = "https://github
|
|
|
1583
1583
|
this.#a.delete(e.currentRefreshTokenHash), e.previousRefreshTokenHash && this.#a.delete(e.previousRefreshTokenHash);
|
|
1584
1584
|
}
|
|
1585
1585
|
};
|
|
1586
|
-
function ct() {
|
|
1587
|
-
return new rt();
|
|
1588
|
-
}
|
|
1589
|
-
function lt() {
|
|
1590
|
-
return new it();
|
|
1591
|
-
}
|
|
1592
1586
|
function ut() {
|
|
1593
1587
|
return new at();
|
|
1594
1588
|
}
|
|
1595
1589
|
function dt() {
|
|
1596
1590
|
return new ot();
|
|
1597
1591
|
}
|
|
1598
|
-
function ft(
|
|
1599
|
-
return new st(
|
|
1592
|
+
function ft() {
|
|
1593
|
+
return new st();
|
|
1600
1594
|
}
|
|
1601
1595
|
function pt() {
|
|
1602
|
-
return
|
|
1596
|
+
return new ct();
|
|
1603
1597
|
}
|
|
1604
1598
|
function mt(e) {
|
|
1605
|
-
|
|
1599
|
+
return new lt(e);
|
|
1600
|
+
}
|
|
1601
|
+
function ht() {
|
|
1602
|
+
return te(process.env.HOME?.trim() || E(), ".codemem", "mcp-oauth-state.json");
|
|
1603
|
+
}
|
|
1604
|
+
function gt(e) {
|
|
1605
|
+
let t = bt(yt(e.mcpUrl));
|
|
1606
1606
|
return {
|
|
1607
1607
|
...c({
|
|
1608
|
-
provider:
|
|
1608
|
+
provider: Mt(e.clientsStore),
|
|
1609
1609
|
issuerUrl: t,
|
|
1610
1610
|
baseUrl: t
|
|
1611
1611
|
}),
|
|
@@ -1618,10 +1618,10 @@ function mt(e) {
|
|
|
1618
1618
|
client_id_metadata_document_supported: !1
|
|
1619
1619
|
};
|
|
1620
1620
|
}
|
|
1621
|
-
function
|
|
1622
|
-
let t =
|
|
1621
|
+
function _t(e) {
|
|
1622
|
+
let t = yt(e), n = {
|
|
1623
1623
|
resource: t.href,
|
|
1624
|
-
authorization_servers: [
|
|
1624
|
+
authorization_servers: [bt(t).href],
|
|
1625
1625
|
scopes_supported: R,
|
|
1626
1626
|
bearer_methods_supported: ["header"],
|
|
1627
1627
|
resource_name: Ge,
|
|
@@ -1629,12 +1629,12 @@ function ht(e) {
|
|
|
1629
1629
|
};
|
|
1630
1630
|
return ce.parse(n);
|
|
1631
1631
|
}
|
|
1632
|
-
function
|
|
1633
|
-
let n = e.get("client_id") ?? "", r = e.get("redirect_uri") ?? "", i = e.get("response_type") ?? "", a = e.get("code_challenge") ?? "", o = e.get("code_challenge_method") ?? "", s = e.get("resource"), c =
|
|
1632
|
+
function vt(e, t) {
|
|
1633
|
+
let n = e.get("client_id") ?? "", r = e.get("redirect_uri") ?? "", i = e.get("response_type") ?? "", a = e.get("code_challenge") ?? "", o = e.get("code_challenge_method") ?? "", s = e.get("resource"), c = Dt(e.get("scope")), l = e.get("state");
|
|
1634
1634
|
if (i !== "code") return U("unsupported_response_type");
|
|
1635
1635
|
if (o !== "S256") return U("invalid_request", "PKCE code_challenge_method=S256 is required");
|
|
1636
|
-
if (!
|
|
1637
|
-
let u =
|
|
1636
|
+
if (!rt.test(a)) return U("invalid_request", "Valid PKCE S256 code_challenge is required");
|
|
1637
|
+
let u = Ot(t, n);
|
|
1638
1638
|
return u ? u.redirect_uris.includes(r) ? {
|
|
1639
1639
|
clientId: n,
|
|
1640
1640
|
redirectUri: r,
|
|
@@ -1644,43 +1644,50 @@ function gt(e, t) {
|
|
|
1644
1644
|
state: l
|
|
1645
1645
|
} : U("invalid_request", "redirect_uri is not registered for this client") : U("invalid_client", "Unknown OAuth client_id");
|
|
1646
1646
|
}
|
|
1647
|
-
function
|
|
1647
|
+
function yt(e) {
|
|
1648
1648
|
let t;
|
|
1649
1649
|
try {
|
|
1650
1650
|
t = new URL(e);
|
|
1651
1651
|
} catch {
|
|
1652
1652
|
throw Error("Invalid MCP HTTP public URL; expected an HTTPS /mcp URL");
|
|
1653
1653
|
}
|
|
1654
|
-
if (t.protocol !== "https:" && !
|
|
1654
|
+
if (t.protocol !== "https:" && !Tt(t)) throw Error("Invalid MCP HTTP public URL; use HTTPS for non-loopback URLs");
|
|
1655
1655
|
if (t.username || t.password || t.search || t.hash) throw Error("Invalid MCP HTTP public URL; credentials, query strings, and fragments are not allowed");
|
|
1656
1656
|
if (t.pathname === "/" && (t.pathname = "/mcp"), t.pathname !== "/mcp") throw Error("Invalid MCP HTTP public URL; expected /mcp path");
|
|
1657
1657
|
return t;
|
|
1658
1658
|
}
|
|
1659
|
-
function
|
|
1659
|
+
function bt(e) {
|
|
1660
1660
|
return new URL(e.origin);
|
|
1661
1661
|
}
|
|
1662
|
-
function
|
|
1662
|
+
function xt(e) {
|
|
1663
1663
|
for (let t of e) {
|
|
1664
1664
|
let e = new URL(t);
|
|
1665
|
-
if (e.username || e.password || e.hash) return
|
|
1666
|
-
if (e
|
|
1665
|
+
if (e.username || e.password || e.hash) return "Invalid redirect URI";
|
|
1666
|
+
if (!St(e) && !wt(e)) return "Unsupported redirect URI";
|
|
1667
1667
|
}
|
|
1668
1668
|
return null;
|
|
1669
1669
|
}
|
|
1670
|
+
function St(e) {
|
|
1671
|
+
return e.search === "" ? e.href === Ke || e.href === qe ? !0 : e.protocol === "https:" && e.hostname === "chatgpt.com" && Ct(e) : !1;
|
|
1672
|
+
}
|
|
1673
|
+
function Ct(e) {
|
|
1674
|
+
let t = e.pathname.split("/").filter(Boolean);
|
|
1675
|
+
return t.length === 3 && t[0] === "connector" && t[1] === "oauth" && it.test(t[2] ?? "");
|
|
1676
|
+
}
|
|
1670
1677
|
function H(e, t) {
|
|
1671
1678
|
return e.length > 0 && e.every((e) => t.has(e));
|
|
1672
1679
|
}
|
|
1673
|
-
function
|
|
1674
|
-
return e.protocol === "http:" &&
|
|
1680
|
+
function wt(e) {
|
|
1681
|
+
return e.protocol === "http:" && Je.has(Et(e.hostname)) && (e.pathname === "/callback" || e.pathname === "/oauth/callback") && e.search === "";
|
|
1675
1682
|
}
|
|
1676
|
-
function
|
|
1677
|
-
let t =
|
|
1678
|
-
return e.protocol === "http:" &&
|
|
1683
|
+
function Tt(e) {
|
|
1684
|
+
let t = Et(e.hostname);
|
|
1685
|
+
return e.protocol === "http:" && Je.has(t);
|
|
1679
1686
|
}
|
|
1680
|
-
function
|
|
1687
|
+
function Et(e) {
|
|
1681
1688
|
return e.replace(/^\[(.*)]$/, "$1").toLowerCase();
|
|
1682
1689
|
}
|
|
1683
|
-
function
|
|
1690
|
+
function Dt(e) {
|
|
1684
1691
|
return e?.split(/\s+/).map((e) => e.trim()).filter(Boolean) ?? [];
|
|
1685
1692
|
}
|
|
1686
1693
|
function U(e, t) {
|
|
@@ -1692,42 +1699,42 @@ function U(e, t) {
|
|
|
1692
1699
|
} : { error: e }
|
|
1693
1700
|
};
|
|
1694
1701
|
}
|
|
1695
|
-
function
|
|
1702
|
+
function Ot(e, t) {
|
|
1696
1703
|
let n = e.getClient(t);
|
|
1697
1704
|
if (n instanceof Promise) throw Error("Asynchronous OAuth client stores are not supported by this HTTP bootstrap yet");
|
|
1698
1705
|
return n;
|
|
1699
1706
|
}
|
|
1700
1707
|
function W(e) {
|
|
1701
|
-
if (typeof e != "string" || e.length !==
|
|
1708
|
+
if (typeof e != "string" || e.length !== tt || !nt.test(e)) return null;
|
|
1702
1709
|
let t = Buffer.from(e, "base64url");
|
|
1703
|
-
return t.length ===
|
|
1710
|
+
return t.length === et ? t : null;
|
|
1704
1711
|
}
|
|
1705
1712
|
function G() {
|
|
1706
|
-
return _(
|
|
1713
|
+
return _(et).toString("base64url");
|
|
1707
1714
|
}
|
|
1708
1715
|
function K(e, t) {
|
|
1709
1716
|
let n = W(e);
|
|
1710
|
-
return n ?
|
|
1717
|
+
return n ? At(n, t) : null;
|
|
1711
1718
|
}
|
|
1712
1719
|
function q(e) {
|
|
1713
1720
|
let t = W(e);
|
|
1714
1721
|
return t ? m("sha256").update(t).digest("base64url") : null;
|
|
1715
1722
|
}
|
|
1716
|
-
function
|
|
1717
|
-
return
|
|
1723
|
+
function kt(e, t) {
|
|
1724
|
+
return At(e, t);
|
|
1718
1725
|
}
|
|
1719
|
-
function
|
|
1726
|
+
function At(e, t) {
|
|
1720
1727
|
return h("sha256", t).update(e).digest("base64url");
|
|
1721
1728
|
}
|
|
1722
1729
|
function J(e, t) {
|
|
1723
1730
|
let n = Buffer.from(e), r = Buffer.from(t);
|
|
1724
1731
|
return n.length === r.length && y(n, r);
|
|
1725
1732
|
}
|
|
1726
|
-
function
|
|
1733
|
+
function jt(e, t) {
|
|
1727
1734
|
let n = new Set(t);
|
|
1728
1735
|
return e.every((e) => n.has(e));
|
|
1729
1736
|
}
|
|
1730
|
-
function
|
|
1737
|
+
function Mt(e) {
|
|
1731
1738
|
return {
|
|
1732
1739
|
clientsStore: e,
|
|
1733
1740
|
async authorize() {
|
|
@@ -1749,14 +1756,14 @@ function Ot(e) {
|
|
|
1749
1756
|
}
|
|
1750
1757
|
//#endregion
|
|
1751
1758
|
//#region src/oidc.ts
|
|
1752
|
-
var
|
|
1759
|
+
var Nt = "CODEMEM_MCP_OIDC_ISSUER_URL", Pt = "CODEMEM_MCP_OIDC_CLIENT_ID", Ft = "CODEMEM_MCP_OIDC_CLIENT_SECRET", It = "CODEMEM_MCP_OAUTH_ALLOWED_SUBJECT", Lt = "CODEMEM_MCP_OAUTH_ALLOWED_EMAIL", Rt = 300 * 1e3, zt = 100, Bt = 300 * 1e3, Vt = class {
|
|
1753
1760
|
#e = /* @__PURE__ */ new Map();
|
|
1754
1761
|
issue(e, t = Date.now()) {
|
|
1755
|
-
if (this.#t(t), this.#e.size >=
|
|
1762
|
+
if (this.#t(t), this.#e.size >= zt) return;
|
|
1756
1763
|
let n = v();
|
|
1757
1764
|
return this.#e.set(n, {
|
|
1758
1765
|
...e,
|
|
1759
|
-
expiresAt: t +
|
|
1766
|
+
expiresAt: t + Rt
|
|
1760
1767
|
}), n;
|
|
1761
1768
|
}
|
|
1762
1769
|
consume(e) {
|
|
@@ -1767,11 +1774,11 @@ var kt = "CODEMEM_MCP_OIDC_ISSUER_URL", At = "CODEMEM_MCP_OIDC_CLIENT_ID", jt =
|
|
|
1767
1774
|
for (let [t, n] of this.#e) n.expiresAt <= e && this.#e.delete(t);
|
|
1768
1775
|
}
|
|
1769
1776
|
};
|
|
1770
|
-
function
|
|
1771
|
-
return new
|
|
1777
|
+
function Ht() {
|
|
1778
|
+
return new Vt();
|
|
1772
1779
|
}
|
|
1773
|
-
function
|
|
1774
|
-
let t = e[
|
|
1780
|
+
function Ut(e = process.env) {
|
|
1781
|
+
let t = e[Nt]?.trim(), n = e[Pt]?.trim(), r = e[Ft]?.trim(), i = e[It]?.trim(), a = e[Lt]?.trim().toLowerCase();
|
|
1775
1782
|
if (!(!t && !n && !r && !i && !a)) {
|
|
1776
1783
|
if (!t || !n || !r) throw Error("Incomplete MCP OIDC configuration");
|
|
1777
1784
|
if (Y(t, "issuer", { allowLoopbackHttp: !0 }), !i && !a) throw Error("MCP OIDC requires CODEMEM_MCP_OAUTH_ALLOWED_SUBJECT or CODEMEM_MCP_OAUTH_ALLOWED_EMAIL");
|
|
@@ -1784,39 +1791,39 @@ function zt(e = process.env) {
|
|
|
1784
1791
|
};
|
|
1785
1792
|
}
|
|
1786
1793
|
}
|
|
1787
|
-
async function
|
|
1794
|
+
async function Wt(e, t, n, r, i, a = Date.now()) {
|
|
1788
1795
|
if (!r) return X("temporarily_unavailable", "OIDC is not configured");
|
|
1789
|
-
let o =
|
|
1796
|
+
let o = vt(e, t);
|
|
1790
1797
|
if ("status" in o) return o;
|
|
1791
|
-
let s = await
|
|
1798
|
+
let s = await qt(r.issuerUrl), c = v(), l = n.issue({
|
|
1792
1799
|
oauthParams: e.toString(),
|
|
1793
1800
|
nonce: c
|
|
1794
1801
|
}, a);
|
|
1795
1802
|
if (!l) return X("temporarily_unavailable", "Too many pending OIDC authorizations");
|
|
1796
|
-
let u =
|
|
1803
|
+
let u = Kt(i), d = new URL(s.authorization_endpoint);
|
|
1797
1804
|
return d.searchParams.set("response_type", "code"), d.searchParams.set("client_id", r.clientId), d.searchParams.set("redirect_uri", u), d.searchParams.set("scope", "openid email"), d.searchParams.set("state", l), d.searchParams.set("nonce", c), {
|
|
1798
1805
|
status: 302,
|
|
1799
1806
|
location: d.href
|
|
1800
1807
|
};
|
|
1801
1808
|
}
|
|
1802
|
-
async function
|
|
1809
|
+
async function Gt(e, t, n, r, i = Date.now()) {
|
|
1803
1810
|
try {
|
|
1804
1811
|
let a = e.get("code") ?? "", o = e.get("state") ?? "";
|
|
1805
1812
|
if (!o) return X("invalid_request", "Missing OIDC state");
|
|
1806
1813
|
let s = t.consume(o);
|
|
1807
1814
|
if (!s || s.expiresAt <= i) return X("invalid_request", "Expired or unknown OIDC state");
|
|
1808
1815
|
if (!a) return X("invalid_request", "Missing OIDC code");
|
|
1809
|
-
let c = await
|
|
1810
|
-
return l.id_token ?
|
|
1816
|
+
let c = await qt(n.issuerUrl), l = await Jt(c.token_endpoint, n, Kt(r), a);
|
|
1817
|
+
return l.id_token ? $t(await Yt(l.id_token, c, n.clientId, s.nonce, i), n) ? { oauthParams: new URLSearchParams(s.oauthParams) } : X("access_denied", "OIDC identity is not allowed") : X("invalid_request", "OIDC token exchange failed");
|
|
1811
1818
|
} catch {
|
|
1812
1819
|
return X("access_denied", "OIDC identity verification failed");
|
|
1813
1820
|
}
|
|
1814
1821
|
}
|
|
1815
|
-
function
|
|
1822
|
+
function Kt(e) {
|
|
1816
1823
|
let t = new URL(e);
|
|
1817
1824
|
return new URL("/oauth/callback", t.origin).href;
|
|
1818
1825
|
}
|
|
1819
|
-
async function
|
|
1826
|
+
async function qt(e) {
|
|
1820
1827
|
let t = new URL(e);
|
|
1821
1828
|
if (t.search || t.hash) throw Error("OIDC issuer must not include query or fragment");
|
|
1822
1829
|
if (t.username || t.password) throw Error("OIDC issuer must not include credentials");
|
|
@@ -1825,10 +1832,10 @@ async function Ut(e) {
|
|
|
1825
1832
|
let i = await r.json();
|
|
1826
1833
|
if (i.issuer !== t.href && i.issuer !== t.href.replace(/\/$/, "")) throw Error("OIDC discovery issuer mismatch");
|
|
1827
1834
|
if (!i.authorization_endpoint || !i.token_endpoint || !i.jwks_uri) throw Error("OIDC discovery metadata is incomplete");
|
|
1828
|
-
let a = t.protocol === "http:" &&
|
|
1835
|
+
let a = t.protocol === "http:" && en(t.hostname);
|
|
1829
1836
|
return Y(i.authorization_endpoint, "authorization endpoint", { allowLoopbackHttp: a }), Y(i.token_endpoint, "token endpoint", { allowLoopbackHttp: a }), Y(i.jwks_uri, "JWKS URI", { allowLoopbackHttp: a }), i;
|
|
1830
1837
|
}
|
|
1831
|
-
async function
|
|
1838
|
+
async function Jt(e, t, n, r) {
|
|
1832
1839
|
let i = new URLSearchParams({
|
|
1833
1840
|
grant_type: "authorization_code",
|
|
1834
1841
|
code: r,
|
|
@@ -1843,17 +1850,17 @@ async function Wt(e, t, n, r) {
|
|
|
1843
1850
|
if (!a.ok) throw Error("OIDC token request failed");
|
|
1844
1851
|
return await a.json();
|
|
1845
1852
|
}
|
|
1846
|
-
async function
|
|
1853
|
+
async function Yt(e, t, n, r, i) {
|
|
1847
1854
|
let [a, o, s] = e.split(".");
|
|
1848
1855
|
if (!a || !o || !s) throw Error("Invalid OIDC id_token");
|
|
1849
|
-
let c =
|
|
1856
|
+
let c = Xt(a), l = Xt(o);
|
|
1850
1857
|
if (c.alg !== "RS256" || !c.kid) throw Error("Unsupported OIDC id_token signature");
|
|
1851
1858
|
if (l.iss !== t.issuer) throw Error("OIDC id_token issuer mismatch");
|
|
1852
|
-
if (!
|
|
1853
|
-
if (!
|
|
1859
|
+
if (!Zt(l.aud, n)) throw Error("OIDC id_token audience mismatch");
|
|
1860
|
+
if (!Qt(l.aud, l.azp, n)) throw Error("OIDC id_token authorized party mismatch");
|
|
1854
1861
|
if (typeof l.exp != "number" || !Number.isFinite(l.exp) || l.exp * 1e3 <= i) throw Error("OIDC id_token is expired");
|
|
1855
1862
|
if (typeof l.iat != "number" || !Number.isFinite(l.iat)) throw Error("OIDC id_token issued-at time is missing");
|
|
1856
|
-
if (l.iat * 1e3 > i +
|
|
1863
|
+
if (l.iat * 1e3 > i + Bt) throw Error("OIDC id_token issued-at time is in the future");
|
|
1857
1864
|
if (l.nonce !== r) throw Error("OIDC id_token nonce mismatch");
|
|
1858
1865
|
if (!l.sub) throw Error("OIDC id_token subject is missing");
|
|
1859
1866
|
let u = await fetch(t.jwks_uri);
|
|
@@ -1867,24 +1874,24 @@ async function Gt(e, t, n, r, i) {
|
|
|
1867
1874
|
if (!b("RSA-SHA256", Buffer.from(p), f, Buffer.from(s, "base64url"))) throw Error("OIDC id_token signature verification failed");
|
|
1868
1875
|
return l;
|
|
1869
1876
|
}
|
|
1870
|
-
function
|
|
1877
|
+
function Xt(e) {
|
|
1871
1878
|
return JSON.parse(Buffer.from(e, "base64url").toString("utf8"));
|
|
1872
1879
|
}
|
|
1873
|
-
function
|
|
1880
|
+
function Zt(e, t) {
|
|
1874
1881
|
return Array.isArray(e) ? e.includes(t) : e === t;
|
|
1875
1882
|
}
|
|
1876
|
-
function
|
|
1883
|
+
function Qt(e, t, n) {
|
|
1877
1884
|
return t && t !== n ? !1 : !Array.isArray(e) || e.length <= 1 || t === n;
|
|
1878
1885
|
}
|
|
1879
|
-
function
|
|
1886
|
+
function $t(e, t) {
|
|
1880
1887
|
return t.allowedSubject && e.sub === t.allowedSubject ? !0 : t.allowedEmail ? e.email_verified === !0 && e.email?.toLowerCase() === t.allowedEmail : !1;
|
|
1881
1888
|
}
|
|
1882
1889
|
function Y(e, t, n = {}) {
|
|
1883
1890
|
let r = new URL(e);
|
|
1884
1891
|
if (r.username || r.password) throw Error(`OIDC ${t} must not include credentials`);
|
|
1885
|
-
if (r.protocol !== "https:" && !(n.allowLoopbackHttp && r.protocol === "http:" &&
|
|
1892
|
+
if (r.protocol !== "https:" && !(n.allowLoopbackHttp && r.protocol === "http:" && en(r.hostname))) throw Error(`OIDC ${t} must use HTTPS`);
|
|
1886
1893
|
}
|
|
1887
|
-
function
|
|
1894
|
+
function en(e) {
|
|
1888
1895
|
let t = e.replace(/^\[(.*)]$/, "$1").toLowerCase();
|
|
1889
1896
|
return t === "localhost" || t === "127.0.0.1" || t === "::1";
|
|
1890
1897
|
}
|
|
@@ -1899,7 +1906,7 @@ function X(e, t) {
|
|
|
1899
1906
|
}
|
|
1900
1907
|
//#endregion
|
|
1901
1908
|
//#region src/provider.ts
|
|
1902
|
-
var
|
|
1909
|
+
var tn = class {
|
|
1903
1910
|
#e;
|
|
1904
1911
|
#t;
|
|
1905
1912
|
#n;
|
|
@@ -1909,19 +1916,19 @@ var Zt = class {
|
|
|
1909
1916
|
#o;
|
|
1910
1917
|
#s;
|
|
1911
1918
|
constructor(e) {
|
|
1912
|
-
this.#e = e.clientsStore, this.#t = e.codeStore, this.#n = e.tokenStore, this.#r = e.refreshTokenStore ??
|
|
1919
|
+
this.#e = e.clientsStore, this.#t = e.codeStore, this.#n = e.tokenStore, this.#r = e.refreshTokenStore ?? pt(), this.#i = e.publicMcpUrl, this.#a = new URL(e.publicMcpUrl).href, this.#o = e.oidc, this.#s = e.now ?? Date.now;
|
|
1913
1920
|
}
|
|
1914
1921
|
get clientsStore() {
|
|
1915
1922
|
return this.#e;
|
|
1916
1923
|
}
|
|
1917
1924
|
async authorize(e, t, n) {
|
|
1918
1925
|
if (!this.#o) throw new A("OIDC is not configured");
|
|
1919
|
-
let r = await
|
|
1926
|
+
let r = await Wt(nn(e, t), this.#e, this.#o.pendingStore, this.#o.config, this.#i, this.#s());
|
|
1920
1927
|
if (r.status === 302) {
|
|
1921
1928
|
n.redirect(302, r.location);
|
|
1922
1929
|
return;
|
|
1923
1930
|
}
|
|
1924
|
-
throw
|
|
1931
|
+
throw rn(r.body);
|
|
1925
1932
|
}
|
|
1926
1933
|
async challengeForAuthorizationCode(e, t) {
|
|
1927
1934
|
let n = this.#t.peekCode(t);
|
|
@@ -1937,7 +1944,7 @@ var Zt = class {
|
|
|
1937
1944
|
if (o.clientId !== e.client_id) throw this.#t.consumeCode(t), new k("Code does not match client");
|
|
1938
1945
|
if (r === void 0 || o.redirectUri !== r) throw this.#t.consumeCode(t), new k("Code does not match redirect_uri");
|
|
1939
1946
|
if ((o.resource ?? null) !== (i?.href ?? null)) throw this.#t.consumeCode(t), new k("Code does not match resource");
|
|
1940
|
-
let s =
|
|
1947
|
+
let s = on(o.scopes) ?? [], c = this.#r.issueGrant({
|
|
1941
1948
|
clientId: e.client_id,
|
|
1942
1949
|
scopes: s,
|
|
1943
1950
|
resource: o.resource
|
|
@@ -1955,10 +1962,10 @@ var Zt = class {
|
|
|
1955
1962
|
}
|
|
1956
1963
|
async exchangeRefreshToken(e, t, n, r) {
|
|
1957
1964
|
let i = this.#s(), a = this.#r.rotateRefreshToken(e.client_id, t, {
|
|
1958
|
-
scopes:
|
|
1965
|
+
scopes: on(n),
|
|
1959
1966
|
...r ? { resource: r.href } : {}
|
|
1960
1967
|
}, i);
|
|
1961
|
-
if (!a.ok) throw a.reason === "refresh_token_replay" && a.grantId && this.#n.revokeTokensForGrant?.(a.grantId, i), new k(
|
|
1968
|
+
if (!a.ok) throw a.reason === "refresh_token_replay" && a.grantId && this.#n.revokeTokensForGrant?.(a.grantId, i), new k(an(a.reason));
|
|
1962
1969
|
let o = this.#n.issueToken(e.client_id, i, a.grant.resource, a.grant.grantId, a.grant.scopes);
|
|
1963
1970
|
if (!o) throw new A("Too many active access tokens");
|
|
1964
1971
|
return le.parse({
|
|
@@ -1990,11 +1997,11 @@ var Zt = class {
|
|
|
1990
1997
|
r && this.#n.revokeTokensForGrant?.(r, n);
|
|
1991
1998
|
}
|
|
1992
1999
|
};
|
|
1993
|
-
function
|
|
2000
|
+
function nn(e, t) {
|
|
1994
2001
|
let n = new URLSearchParams();
|
|
1995
2002
|
return n.set("client_id", e.client_id), n.set("redirect_uri", t.redirectUri), n.set("response_type", "code"), n.set("code_challenge", t.codeChallenge), n.set("code_challenge_method", "S256"), t.state && n.set("state", t.state), t.scopes?.length && n.set("scope", t.scopes.join(" ")), t.resource && n.set("resource", t.resource.href), n;
|
|
1996
2003
|
}
|
|
1997
|
-
function
|
|
2004
|
+
function rn(e) {
|
|
1998
2005
|
let t = e.error_description ?? e.error;
|
|
1999
2006
|
switch (e.error) {
|
|
2000
2007
|
case "temporarily_unavailable": return new A(t);
|
|
@@ -2005,7 +2012,7 @@ function $t(e) {
|
|
|
2005
2012
|
default: return new oe(t);
|
|
2006
2013
|
}
|
|
2007
2014
|
}
|
|
2008
|
-
function
|
|
2015
|
+
function an(e) {
|
|
2009
2016
|
switch (e) {
|
|
2010
2017
|
case "expired_refresh_token": return "Refresh token has expired";
|
|
2011
2018
|
case "revoked_refresh_token": return "Refresh token has been revoked";
|
|
@@ -2016,34 +2023,34 @@ function en(e) {
|
|
|
2016
2023
|
default: return "Invalid refresh token";
|
|
2017
2024
|
}
|
|
2018
2025
|
}
|
|
2019
|
-
function
|
|
2026
|
+
function on(e) {
|
|
2020
2027
|
let t = e?.map((e) => e.trim()).filter(Boolean).map((e) => e === "memory:read_access" ? "memory:read" : e === "memory:write_access" ? "memory:write" : e);
|
|
2021
2028
|
return t && t.length > 0 ? t : void 0;
|
|
2022
2029
|
}
|
|
2023
2030
|
//#endregion
|
|
2024
2031
|
//#region src/http.ts
|
|
2025
|
-
var
|
|
2032
|
+
var sn = "127.0.0.1", cn = 38889, ln = 80, un = new Set(["https://chatgpt.com", "https://claude.ai"]), dn = "authorization,content-type,mcp-session-id", fn = "600", pn = 256, mn = 900 * 1e3, hn = 600, gn = /^[a-zA-Z0-9.-]+$/, _n = new Set([
|
|
2026
2033
|
"127.0.0.1",
|
|
2027
2034
|
"::1",
|
|
2028
2035
|
"localhost"
|
|
2029
2036
|
]);
|
|
2030
|
-
function
|
|
2037
|
+
function vn(e, t = !1) {
|
|
2031
2038
|
let r = e?.trim() || "127.0.0.1";
|
|
2032
|
-
if (r.includes("://") || r.includes("/") || r.includes("\\") || !(n(r) || r === "localhost" ||
|
|
2039
|
+
if (r.includes("://") || r.includes("/") || r.includes("\\") || !(n(r) || r === "localhost" || gn.test(r))) throw Error(`Invalid MCP HTTP host: ${e}`);
|
|
2033
2040
|
if (!t && !Z(r)) throw Error(`Refusing unsafe MCP HTTP host ${r}; set CODEMEM_MCP_HTTP_UNSAFE_PUBLIC=1 to allow non-loopback binding`);
|
|
2034
2041
|
return r;
|
|
2035
2042
|
}
|
|
2036
2043
|
function Z(e) {
|
|
2037
|
-
return
|
|
2044
|
+
return _n.has(Q(e));
|
|
2038
2045
|
}
|
|
2039
|
-
function
|
|
2046
|
+
function yn(e = process.env.CODEMEM_MCP_HTTP_UNSAFE_PUBLIC) {
|
|
2040
2047
|
return e === "1" || e?.toLowerCase() === "true" || e?.toLowerCase() === "yes";
|
|
2041
2048
|
}
|
|
2042
|
-
function
|
|
2043
|
-
let n =
|
|
2044
|
-
return !n || !Z(n.host) ? !1 : n.port === null ? t ===
|
|
2049
|
+
function bn(e, t) {
|
|
2050
|
+
let n = Cn(e);
|
|
2051
|
+
return !n || !Z(n.host) ? !1 : n.port === null ? t === ln : n.port === t;
|
|
2045
2052
|
}
|
|
2046
|
-
function
|
|
2053
|
+
function xn(e, t) {
|
|
2047
2054
|
if (!e) return !0;
|
|
2048
2055
|
try {
|
|
2049
2056
|
let n = new URL(e), r = n.port ? Number(n.port) : n.protocol === "https:" ? 443 : 80;
|
|
@@ -2052,13 +2059,13 @@ function _n(e, t) {
|
|
|
2052
2059
|
return !1;
|
|
2053
2060
|
}
|
|
2054
2061
|
}
|
|
2055
|
-
function
|
|
2062
|
+
function Sn(e) {
|
|
2056
2063
|
return e ? Z(e.replace(/^::ffff:/, "")) : !1;
|
|
2057
2064
|
}
|
|
2058
2065
|
function Q(e) {
|
|
2059
2066
|
return e.replace(/^\[(.*)]$/, "$1").toLowerCase();
|
|
2060
2067
|
}
|
|
2061
|
-
function
|
|
2068
|
+
function Cn(e) {
|
|
2062
2069
|
if (!e) return null;
|
|
2063
2070
|
if (e.startsWith("[")) {
|
|
2064
2071
|
let t = /^\[([^\]]+)]:(\d+)$/.exec(e);
|
|
@@ -2083,70 +2090,70 @@ function yn(e) {
|
|
|
2083
2090
|
port: r
|
|
2084
2091
|
} : null;
|
|
2085
2092
|
}
|
|
2086
|
-
function
|
|
2087
|
-
if (e === void 0 || e === "") return
|
|
2093
|
+
function wn(e) {
|
|
2094
|
+
if (e === void 0 || e === "") return cn;
|
|
2088
2095
|
let t = typeof e == "number" ? e : Number(e);
|
|
2089
2096
|
if (!Number.isInteger(t) || t < 0 || t > 65535) throw Error(`Invalid MCP HTTP port: ${e}`);
|
|
2090
2097
|
return t;
|
|
2091
2098
|
}
|
|
2092
|
-
async function
|
|
2093
|
-
let r =
|
|
2094
|
-
|
|
2095
|
-
let
|
|
2099
|
+
async function Tn(n = {}) {
|
|
2100
|
+
let r = vn(n.host ?? process.env.CODEMEM_MCP_HTTP_HOST, n.allowUnsafePublic ?? yn()), i = wn(n.port ?? process.env.CODEMEM_MCP_HTTP_PORT), c = n.publicUrl ?? process.env.CODEMEM_MCP_HTTP_PUBLIC_URL, p = c ? yt(c) : void 0, m = new a(n.dbPath ?? o()), h = n.oauthAccessTokenStore ? void 0 : mt(n.oauthStatePath), g = h ?? ut(), _ = h ?? dt(), v = n.oauthAccessTokenStore ?? h ?? ft(), y = Ut(), b = Ht(), x = p !== void 0 || y !== void 0, S = Ve(n.auditEmitter ?? We()), C = /* @__PURE__ */ new Set(), ee = null, w = f();
|
|
2101
|
+
w.disable("x-powered-by"), w.set("trust proxy", "loopback");
|
|
2102
|
+
let T = t(w);
|
|
2096
2103
|
await new Promise((e, t) => {
|
|
2097
|
-
|
|
2104
|
+
T.once("error", t), T.listen({
|
|
2098
2105
|
host: r,
|
|
2099
2106
|
port: i
|
|
2100
2107
|
}, () => {
|
|
2101
|
-
|
|
2108
|
+
T.off("error", t), e();
|
|
2102
2109
|
});
|
|
2103
2110
|
});
|
|
2104
|
-
let
|
|
2111
|
+
let E = p?.href ?? In(T, r), D = new URL(E), te = Ln(D, $(T)), ne = new tn({
|
|
2105
2112
|
clientsStore: g,
|
|
2106
2113
|
codeStore: _,
|
|
2107
2114
|
tokenStore: v,
|
|
2108
|
-
publicMcpUrl:
|
|
2115
|
+
publicMcpUrl: E,
|
|
2109
2116
|
...h ? { refreshTokenStore: h } : {},
|
|
2110
2117
|
...y ? { oidc: {
|
|
2111
2118
|
config: y,
|
|
2112
2119
|
pendingStore: b
|
|
2113
2120
|
} } : {}
|
|
2114
|
-
}), re = l(
|
|
2115
|
-
|
|
2116
|
-
windowMs:
|
|
2117
|
-
limit:
|
|
2121
|
+
}), re = l(D);
|
|
2122
|
+
w.use(Re({
|
|
2123
|
+
windowMs: mn,
|
|
2124
|
+
limit: hn,
|
|
2118
2125
|
standardHeaders: "draft-8",
|
|
2119
2126
|
legacyHeaders: !1,
|
|
2120
2127
|
ipv6Subnet: !1
|
|
2121
|
-
})),
|
|
2122
|
-
let r = $(
|
|
2128
|
+
})), w.use((e, t, n) => {
|
|
2129
|
+
let r = $(T), i = zn(e.path);
|
|
2123
2130
|
if (i === "/mcp") {
|
|
2124
|
-
if (
|
|
2125
|
-
if (
|
|
2131
|
+
if (En(e, r, p)) {
|
|
2132
|
+
if (An(e, t, p), e.method === "OPTIONS") {
|
|
2126
2133
|
t.status(204).send("");
|
|
2127
2134
|
return;
|
|
2128
2135
|
}
|
|
2129
2136
|
return n();
|
|
2130
2137
|
}
|
|
2131
|
-
|
|
2138
|
+
Mn(e, i, p), t.status(403).type("text/plain").send("Forbidden");
|
|
2132
2139
|
return;
|
|
2133
2140
|
}
|
|
2134
|
-
if (
|
|
2135
|
-
if (
|
|
2136
|
-
if (
|
|
2141
|
+
if (Rn(i)) {
|
|
2142
|
+
if (On(e, r, p)) {
|
|
2143
|
+
if (An(e, t, p), e.method === "OPTIONS") {
|
|
2137
2144
|
t.status(204).send("");
|
|
2138
2145
|
return;
|
|
2139
2146
|
}
|
|
2140
2147
|
return n();
|
|
2141
2148
|
}
|
|
2142
|
-
|
|
2149
|
+
Mn(e, i, p), t.status(403).type("text/plain").send("Forbidden");
|
|
2143
2150
|
return;
|
|
2144
2151
|
}
|
|
2145
2152
|
n();
|
|
2146
|
-
}),
|
|
2153
|
+
}), w.use(Bn(S)), w.get("/oauth/callback", async (e, t) => {
|
|
2147
2154
|
let n = e.socket.remoteAddress ?? void 0;
|
|
2148
2155
|
if (!y) {
|
|
2149
|
-
|
|
2156
|
+
S(L("oidc_callback", {
|
|
2150
2157
|
outcome: "denied",
|
|
2151
2158
|
reason: "oidc_not_configured",
|
|
2152
2159
|
remoteAddress: n
|
|
@@ -2156,9 +2163,9 @@ async function xn(n = {}) {
|
|
|
2156
2163
|
});
|
|
2157
2164
|
return;
|
|
2158
2165
|
}
|
|
2159
|
-
let r = await
|
|
2166
|
+
let r = await Gt(new URLSearchParams(e.query), b, y, E);
|
|
2160
2167
|
if ("status" in r) {
|
|
2161
|
-
|
|
2168
|
+
S(L("oidc_callback", {
|
|
2162
2169
|
outcome: "denied",
|
|
2163
2170
|
reason: r.body.error,
|
|
2164
2171
|
remoteAddress: n
|
|
@@ -2169,12 +2176,12 @@ async function xn(n = {}) {
|
|
|
2169
2176
|
clientId: r.oauthParams.get("client_id") ?? "",
|
|
2170
2177
|
redirectUri: r.oauthParams.get("redirect_uri") ?? "",
|
|
2171
2178
|
codeChallenge: r.oauthParams.get("code_challenge") ?? "",
|
|
2172
|
-
scopes:
|
|
2179
|
+
scopes: Yn(r.oauthParams.get("scope")),
|
|
2173
2180
|
...r.oauthParams.get("resource") ? { resource: r.oauthParams.get("resource") ?? void 0 } : {},
|
|
2174
2181
|
expiresAt: Date.now() + 300 * 1e3
|
|
2175
2182
|
});
|
|
2176
2183
|
if (!a) {
|
|
2177
|
-
|
|
2184
|
+
S(L("oidc_callback", {
|
|
2178
2185
|
outcome: "denied",
|
|
2179
2186
|
reason: "temporarily_unavailable",
|
|
2180
2187
|
clientId: i,
|
|
@@ -2188,99 +2195,99 @@ async function xn(n = {}) {
|
|
|
2188
2195
|
let o = new URL(r.oauthParams.get("redirect_uri") ?? "");
|
|
2189
2196
|
o.searchParams.set("code", a);
|
|
2190
2197
|
let s = r.oauthParams.get("state");
|
|
2191
|
-
s && o.searchParams.set("state", s),
|
|
2198
|
+
s && o.searchParams.set("state", s), S(L("oidc_callback", {
|
|
2192
2199
|
outcome: "success",
|
|
2193
2200
|
reason: "code_issued",
|
|
2194
2201
|
clientId: i,
|
|
2195
2202
|
remoteAddress: n
|
|
2196
2203
|
})), t.redirect(302, o.href);
|
|
2197
|
-
}),
|
|
2198
|
-
t.status(200).json(
|
|
2199
|
-
mcpUrl:
|
|
2204
|
+
}), w.get("/.well-known/oauth-authorization-server", (e, t) => {
|
|
2205
|
+
t.status(200).json(gt({
|
|
2206
|
+
mcpUrl: E,
|
|
2200
2207
|
clientsStore: g
|
|
2201
2208
|
}));
|
|
2202
|
-
}),
|
|
2203
|
-
t.status(200).json(
|
|
2204
|
-
}),
|
|
2209
|
+
}), w.get("/.well-known/oauth-protected-resource/mcp", (e, t) => {
|
|
2210
|
+
t.status(200).json(_t(E));
|
|
2211
|
+
}), w.use(u({
|
|
2205
2212
|
provider: ne,
|
|
2206
|
-
issuerUrl:
|
|
2207
|
-
baseUrl:
|
|
2208
|
-
resourceServerUrl:
|
|
2213
|
+
issuerUrl: te,
|
|
2214
|
+
baseUrl: te,
|
|
2215
|
+
resourceServerUrl: D,
|
|
2209
2216
|
resourceName: Ge,
|
|
2210
2217
|
scopesSupported: R,
|
|
2211
2218
|
serviceDocumentationUrl: new URL(z),
|
|
2212
2219
|
clientRegistrationOptions: { clientSecretExpirySeconds: 0 }
|
|
2213
2220
|
}));
|
|
2214
|
-
let O =
|
|
2221
|
+
let O = x ? s({
|
|
2215
2222
|
verifier: ne,
|
|
2216
2223
|
resourceMetadataUrl: re
|
|
2217
|
-
}) : (e, t, n) => n(), k =
|
|
2218
|
-
return
|
|
2219
|
-
t.auth &&
|
|
2224
|
+
}) : (e, t, n) => n(), k = x ? qn(S, v) : (e, t, n) => n();
|
|
2225
|
+
return w.post("/mcp", k, O, async (t, n) => {
|
|
2226
|
+
t.auth && S(L("bearer", {
|
|
2220
2227
|
outcome: "success",
|
|
2221
2228
|
clientId: t.auth.clientId,
|
|
2222
2229
|
remoteAddress: t.socket.remoteAddress ?? void 0
|
|
2223
2230
|
}));
|
|
2224
2231
|
let r = e(m), i = new d({ sessionIdGenerator: void 0 }), a = { mcpServer: r };
|
|
2225
|
-
|
|
2232
|
+
C.add(a);
|
|
2226
2233
|
try {
|
|
2227
2234
|
await r.connect(i), await i.handleRequest(t, n);
|
|
2228
2235
|
} finally {
|
|
2229
|
-
|
|
2236
|
+
C.delete(a), await r.close();
|
|
2230
2237
|
}
|
|
2231
|
-
}),
|
|
2238
|
+
}), w.all("/mcp", (e, t) => {
|
|
2232
2239
|
t.setHeader("Allow", "POST"), t.status(405).type("text/plain").send("Method not allowed");
|
|
2233
|
-
}),
|
|
2240
|
+
}), w.use((e, t) => {
|
|
2234
2241
|
t.status(404).type("text/plain").send("Not found");
|
|
2235
2242
|
}), {
|
|
2236
|
-
server:
|
|
2243
|
+
server: T,
|
|
2237
2244
|
store: m,
|
|
2238
|
-
url: `http://${
|
|
2239
|
-
close: () => (
|
|
2240
|
-
await Promise.allSettled([...
|
|
2241
|
-
|
|
2245
|
+
url: `http://${Fn(r)}:${$(T)}/mcp`,
|
|
2246
|
+
close: () => (ee ??= (async () => {
|
|
2247
|
+
await Promise.allSettled([...C].map(({ mcpServer: e }) => e.close())), await new Promise((e, t) => {
|
|
2248
|
+
T.close((n) => {
|
|
2242
2249
|
if (!n || n.code === "ERR_SERVER_NOT_RUNNING") {
|
|
2243
2250
|
e();
|
|
2244
2251
|
return;
|
|
2245
2252
|
}
|
|
2246
2253
|
t(n);
|
|
2247
|
-
}),
|
|
2254
|
+
}), T.closeAllConnections();
|
|
2248
2255
|
}), m.close();
|
|
2249
|
-
})(),
|
|
2256
|
+
})(), ee)
|
|
2250
2257
|
};
|
|
2251
2258
|
}
|
|
2252
|
-
function
|
|
2253
|
-
return
|
|
2259
|
+
function En(e, t, n) {
|
|
2260
|
+
return Dn(e, t) ? !0 : n ? Pn(e.headers.host, n) && kn(e.headers.origin, n) : !1;
|
|
2254
2261
|
}
|
|
2255
|
-
function
|
|
2256
|
-
return
|
|
2262
|
+
function Dn(e, t) {
|
|
2263
|
+
return Sn(e.socket.remoteAddress) && bn(e.headers.host, t) && xn(e.headers.origin, t);
|
|
2257
2264
|
}
|
|
2258
|
-
function
|
|
2259
|
-
return
|
|
2265
|
+
function On(e, t, n) {
|
|
2266
|
+
return Dn(e, t) ? !0 : n ? Pn(e.headers.host, n) && kn(e.headers.origin, n) : !1;
|
|
2260
2267
|
}
|
|
2261
|
-
function
|
|
2268
|
+
function kn(e, t) {
|
|
2262
2269
|
if (!e) return !0;
|
|
2263
2270
|
try {
|
|
2264
2271
|
let n = new URL(e);
|
|
2265
|
-
return n.origin === t.origin ||
|
|
2272
|
+
return n.origin === t.origin || un.has(n.origin);
|
|
2266
2273
|
} catch {
|
|
2267
2274
|
return !1;
|
|
2268
2275
|
}
|
|
2269
2276
|
}
|
|
2270
|
-
function
|
|
2277
|
+
function An(e, t, n) {
|
|
2271
2278
|
if (!n) return;
|
|
2272
|
-
let r =
|
|
2273
|
-
r && (t.setHeader("Access-Control-Allow-Origin", r), t.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS"), t.setHeader("Access-Control-Allow-Headers", e.headers["access-control-request-headers"] ??
|
|
2279
|
+
let r = jn(e.headers.origin, n);
|
|
2280
|
+
r && (t.setHeader("Access-Control-Allow-Origin", r), t.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS"), t.setHeader("Access-Control-Allow-Headers", e.headers["access-control-request-headers"] ?? dn), t.setHeader("Access-Control-Max-Age", fn), t.setHeader("Vary", "Origin"));
|
|
2274
2281
|
}
|
|
2275
|
-
function
|
|
2282
|
+
function jn(e, t) {
|
|
2276
2283
|
if (e) try {
|
|
2277
2284
|
let n = new URL(e).origin;
|
|
2278
|
-
if (n === t.origin ||
|
|
2285
|
+
if (n === t.origin || un.has(n)) return n;
|
|
2279
2286
|
} catch {
|
|
2280
2287
|
return;
|
|
2281
2288
|
}
|
|
2282
2289
|
}
|
|
2283
|
-
function
|
|
2290
|
+
function Mn(e, t, n) {
|
|
2284
2291
|
console.warn(JSON.stringify({
|
|
2285
2292
|
source: "codemem-mcp-http-guard",
|
|
2286
2293
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -2288,50 +2295,50 @@ function On(e, t, n) {
|
|
|
2288
2295
|
reason: "host_or_origin_mismatch",
|
|
2289
2296
|
method: e.method,
|
|
2290
2297
|
path: t,
|
|
2291
|
-
host:
|
|
2292
|
-
origin:
|
|
2298
|
+
host: Nn(e.headers.host),
|
|
2299
|
+
origin: Nn(e.headers.origin),
|
|
2293
2300
|
expectedOrigin: n?.origin,
|
|
2294
2301
|
remoteAddress: e.socket.remoteAddress ?? void 0
|
|
2295
2302
|
}));
|
|
2296
2303
|
}
|
|
2297
|
-
function
|
|
2298
|
-
return !e || e.length <=
|
|
2304
|
+
function Nn(e) {
|
|
2305
|
+
return !e || e.length <= pn ? e : `${e.slice(0, pn)}…`;
|
|
2299
2306
|
}
|
|
2300
|
-
function
|
|
2301
|
-
let n =
|
|
2307
|
+
function Pn(e, t) {
|
|
2308
|
+
let n = Cn(e);
|
|
2302
2309
|
if (!n) return !1;
|
|
2303
2310
|
let r = t.port ? Number(t.port) : t.protocol === "https:" ? 443 : 80, i = t.protocol === "https:" ? 443 : 80, a = n.port ?? i;
|
|
2304
2311
|
return Q(n.host) === Q(t.hostname) && a === r;
|
|
2305
2312
|
}
|
|
2306
2313
|
function $(e) {
|
|
2307
2314
|
let t = e.address();
|
|
2308
|
-
return !t || typeof t == "string" ?
|
|
2315
|
+
return !t || typeof t == "string" ? cn : t.port;
|
|
2309
2316
|
}
|
|
2310
|
-
function
|
|
2317
|
+
function Fn(e) {
|
|
2311
2318
|
return n(e) === 6 ? `[${e}]` : e;
|
|
2312
2319
|
}
|
|
2313
|
-
function
|
|
2314
|
-
return `http://${
|
|
2320
|
+
function In(e, t) {
|
|
2321
|
+
return `http://${Fn(t)}:${$(e)}/mcp`;
|
|
2315
2322
|
}
|
|
2316
|
-
function
|
|
2323
|
+
function Ln(e, t) {
|
|
2317
2324
|
return e.protocol === "https:" || Z(e.hostname) && Q(e.hostname) !== "::1" ? new URL(e.origin) : new URL(`http://localhost:${t}/`);
|
|
2318
2325
|
}
|
|
2319
|
-
function
|
|
2326
|
+
function Rn(e) {
|
|
2320
2327
|
return e === "/register" || e === "/authorize" || e === "/token" || e === "/revoke" || e === "/oauth/callback" || e === "/.well-known/oauth-authorization-server" || e === "/.well-known/oauth-protected-resource/mcp";
|
|
2321
2328
|
}
|
|
2322
|
-
function
|
|
2329
|
+
function zn(e) {
|
|
2323
2330
|
return e.length > 1 ? e.replace(/\/+$/, "") : e;
|
|
2324
2331
|
}
|
|
2325
|
-
function
|
|
2332
|
+
function Bn(e) {
|
|
2326
2333
|
return (t, n, r) => {
|
|
2327
2334
|
let i = t.path;
|
|
2328
|
-
if (!
|
|
2335
|
+
if (!Vn(i)) return r();
|
|
2329
2336
|
let a, o = n.json.bind(n);
|
|
2330
2337
|
n.json = ((e) => (a = e, o(e))), n.on("finish", () => {
|
|
2331
2338
|
if (i === "/oauth/callback") return;
|
|
2332
|
-
let r =
|
|
2339
|
+
let r = Hn(i, t);
|
|
2333
2340
|
if (!r) return;
|
|
2334
|
-
let o =
|
|
2341
|
+
let o = Wn(n, a), s = Kn(t, a);
|
|
2335
2342
|
e(L(r, {
|
|
2336
2343
|
outcome: o ? "denied" : "success",
|
|
2337
2344
|
...o ? { reason: o } : {},
|
|
@@ -2341,17 +2348,17 @@ function In(e) {
|
|
|
2341
2348
|
}), r();
|
|
2342
2349
|
};
|
|
2343
2350
|
}
|
|
2344
|
-
function
|
|
2345
|
-
return
|
|
2351
|
+
function Vn(e) {
|
|
2352
|
+
return Un(e) !== null;
|
|
2346
2353
|
}
|
|
2347
|
-
function
|
|
2348
|
-
return e === "/token" && t.body?.grant_type === "refresh_token" ? "refresh" :
|
|
2354
|
+
function Hn(e, t) {
|
|
2355
|
+
return e === "/token" && t.body?.grant_type === "refresh_token" ? "refresh" : Un(e);
|
|
2349
2356
|
}
|
|
2350
|
-
function
|
|
2357
|
+
function Un(e) {
|
|
2351
2358
|
return e === "/register" ? "registration" : e === "/authorize" ? "authorize" : e === "/token" ? "token" : e === "/revoke" ? "revocation" : null;
|
|
2352
2359
|
}
|
|
2353
|
-
function
|
|
2354
|
-
let n =
|
|
2360
|
+
function Wn(e, t) {
|
|
2361
|
+
let n = Gn(t);
|
|
2355
2362
|
if (n) return n;
|
|
2356
2363
|
let r = e.getHeader("location");
|
|
2357
2364
|
if (typeof r == "string") try {
|
|
@@ -2360,15 +2367,15 @@ function Bn(e, t) {
|
|
|
2360
2367
|
return;
|
|
2361
2368
|
}
|
|
2362
2369
|
}
|
|
2363
|
-
function
|
|
2370
|
+
function Gn(e) {
|
|
2364
2371
|
if (typeof e == "object" && e && "error" in e && typeof e.error == "string") return e.error;
|
|
2365
2372
|
}
|
|
2366
|
-
function
|
|
2373
|
+
function Kn(e, t) {
|
|
2367
2374
|
return typeof t == "object" && t && "client_id" in t && typeof t.client_id == "string" ? t.client_id : (typeof e.body?.client_id == "string" ? e.body.client_id : void 0) || (typeof e.query.client_id == "string" ? e.query.client_id : void 0);
|
|
2368
2375
|
}
|
|
2369
|
-
function
|
|
2376
|
+
function qn(e, t) {
|
|
2370
2377
|
return (n, r, i) => {
|
|
2371
|
-
let a =
|
|
2378
|
+
let a = Jn(n.headers.authorization, t);
|
|
2372
2379
|
a && e(L("bearer", {
|
|
2373
2380
|
outcome: "denied",
|
|
2374
2381
|
reason: a,
|
|
@@ -2376,22 +2383,22 @@ function Un(e, t) {
|
|
|
2376
2383
|
})), i();
|
|
2377
2384
|
};
|
|
2378
2385
|
}
|
|
2379
|
-
function
|
|
2386
|
+
function Jn(e, t) {
|
|
2380
2387
|
if (!e) return "missing_authorization_header";
|
|
2381
2388
|
let [n, r, i] = e.trim().split(/\s+/);
|
|
2382
2389
|
if (!n || !r || i || n.toLowerCase() !== "bearer") return "malformed_authorization_header";
|
|
2383
2390
|
let a = t.verifyToken(r);
|
|
2384
2391
|
return a.ok ? null : a.reason;
|
|
2385
2392
|
}
|
|
2386
|
-
function
|
|
2393
|
+
function Yn(e) {
|
|
2387
2394
|
return e?.split(/\s+/).map((e) => e.trim()).filter(Boolean) ?? [];
|
|
2388
2395
|
}
|
|
2389
|
-
function
|
|
2396
|
+
function Xn() {
|
|
2390
2397
|
let e = process.argv[1];
|
|
2391
2398
|
return e ? import.meta.url === i(e).href : !1;
|
|
2392
2399
|
}
|
|
2393
|
-
async function
|
|
2394
|
-
let e = await
|
|
2400
|
+
async function Zn() {
|
|
2401
|
+
let e = await Tn();
|
|
2395
2402
|
console.error(`codemem MCP HTTP server listening at ${e.url}`);
|
|
2396
2403
|
let t = async () => {
|
|
2397
2404
|
try {
|
|
@@ -2401,10 +2408,10 @@ async function qn() {
|
|
|
2401
2408
|
};
|
|
2402
2409
|
process.on("SIGINT", t), process.on("SIGTERM", t);
|
|
2403
2410
|
}
|
|
2404
|
-
|
|
2411
|
+
Xn() && Zn().catch((e) => {
|
|
2405
2412
|
console.error("codemem MCP HTTP server failed to start:", e), process.exit(1);
|
|
2406
2413
|
});
|
|
2407
2414
|
//#endregion
|
|
2408
|
-
export {
|
|
2415
|
+
export { sn as DEFAULT_MCP_HTTP_HOST, cn as DEFAULT_MCP_HTTP_PORT, bn as isAllowedMcpHttpRequestHost, xn as isAllowedMcpHttpRequestOrigin, Sn as isAllowedMcpHttpRequestRemoteAddress, Z as isLoopbackHost, yn as isUnsafePublicBindAllowed, wn as parseMcpHttpPort, Tn as startCodememMcpHttpServer, vn as validateMcpHttpHost };
|
|
2409
2416
|
|
|
2410
2417
|
//# sourceMappingURL=http.js.map
|