@sentropic/h2a-cli 0.24.0 → 0.26.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/dist/bin.js +4 -1
- package/dist/bin.js.map +1 -1
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli-contract.js +33 -1
- package/dist/cli-contract.js.map +1 -1
- package/dist/cli.d.ts +16 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +294 -16
- package/dist/cli.js.map +1 -1
- package/dist/hosts/plugin.d.ts +14 -2
- package/dist/hosts/plugin.d.ts.map +1 -1
- package/dist/hosts/plugin.js +23 -0
- package/dist/hosts/plugin.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/runtime/drive/index.d.ts +84 -0
- package/dist/runtime/drive/index.d.ts.map +1 -1
- package/dist/runtime/drive/index.js +325 -22
- package/dist/runtime/drive/index.js.map +1 -1
- package/dist/runtime/drumbeat/relaunchers.d.ts +5 -1
- package/dist/runtime/drumbeat/relaunchers.d.ts.map +1 -1
- package/dist/runtime/drumbeat/relaunchers.js +12 -6
- package/dist/runtime/drumbeat/relaunchers.js.map +1 -1
- package/dist/runtime/local-files/store.d.ts +14 -1
- package/dist/runtime/local-files/store.d.ts.map +1 -1
- package/dist/runtime/local-files/store.js +141 -1
- package/dist/runtime/local-files/store.js.map +1 -1
- package/dist/runtime/mcp-http/app.d.ts +12 -0
- package/dist/runtime/mcp-http/app.d.ts.map +1 -0
- package/dist/runtime/mcp-http/app.js +64 -0
- package/dist/runtime/mcp-http/app.js.map +1 -0
- package/dist/runtime/mcp-http/hosted-mcp-server.d.ts +14 -0
- package/dist/runtime/mcp-http/hosted-mcp-server.d.ts.map +1 -0
- package/dist/runtime/mcp-http/hosted-mcp-server.js +38 -0
- package/dist/runtime/mcp-http/hosted-mcp-server.js.map +1 -0
- package/dist/runtime/mcp-http/index.d.ts +14 -0
- package/dist/runtime/mcp-http/index.d.ts.map +1 -0
- package/dist/runtime/mcp-http/index.js +14 -0
- package/dist/runtime/mcp-http/index.js.map +1 -0
- package/dist/runtime/mcp-http/main.d.ts +2 -0
- package/dist/runtime/mcp-http/main.d.ts.map +1 -0
- package/dist/runtime/mcp-http/main.js +14 -0
- package/dist/runtime/mcp-http/main.js.map +1 -0
- package/dist/runtime/mcp-http/oauth/config.d.ts +33 -0
- package/dist/runtime/mcp-http/oauth/config.d.ts.map +1 -0
- package/dist/runtime/mcp-http/oauth/config.js +31 -0
- package/dist/runtime/mcp-http/oauth/config.js.map +1 -0
- package/dist/runtime/mcp-http/oauth/crypto.d.ts +5 -0
- package/dist/runtime/mcp-http/oauth/crypto.d.ts.map +1 -0
- package/dist/runtime/mcp-http/oauth/crypto.js +19 -0
- package/dist/runtime/mcp-http/oauth/crypto.js.map +1 -0
- package/dist/runtime/mcp-http/oauth/file-store.d.ts +40 -0
- package/dist/runtime/mcp-http/oauth/file-store.d.ts.map +1 -0
- package/dist/runtime/mcp-http/oauth/file-store.js +101 -0
- package/dist/runtime/mcp-http/oauth/file-store.js.map +1 -0
- package/dist/runtime/mcp-http/oauth/hono-oauth-router.d.ts +5 -0
- package/dist/runtime/mcp-http/oauth/hono-oauth-router.d.ts.map +1 -0
- package/dist/runtime/mcp-http/oauth/hono-oauth-router.js +83 -0
- package/dist/runtime/mcp-http/oauth/hono-oauth-router.js.map +1 -0
- package/dist/runtime/mcp-http/oauth/redirect-uri.d.ts +11 -0
- package/dist/runtime/mcp-http/oauth/redirect-uri.d.ts.map +1 -0
- package/dist/runtime/mcp-http/oauth/redirect-uri.js +29 -0
- package/dist/runtime/mcp-http/oauth/redirect-uri.js.map +1 -0
- package/dist/runtime/mcp-http/oauth/single-tenant-provider.d.ts +68 -0
- package/dist/runtime/mcp-http/oauth/single-tenant-provider.d.ts.map +1 -0
- package/dist/runtime/mcp-http/oauth/single-tenant-provider.js +238 -0
- package/dist/runtime/mcp-http/oauth/single-tenant-provider.js.map +1 -0
- package/dist/runtime/mcp-http/readonly-allowlist.d.ts +24 -0
- package/dist/runtime/mcp-http/readonly-allowlist.d.ts.map +1 -0
- package/dist/runtime/mcp-http/readonly-allowlist.js +43 -0
- package/dist/runtime/mcp-http/readonly-allowlist.js.map +1 -0
- package/dist/runtime/mcp-http/serve.d.ts +30 -0
- package/dist/runtime/mcp-http/serve.d.ts.map +1 -0
- package/dist/runtime/mcp-http/serve.js +53 -0
- package/dist/runtime/mcp-http/serve.js.map +1 -0
- package/package.json +6 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/crypto.ts"],"names":[],"mappings":"AAKA,wBAAgB,WAAW,CAAC,UAAU,SAAK,GAAG,MAAM,CAEnD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAInE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-12 hosted OAuth — token crypto helpers (ported from mcp-wave, generic).
|
|
3
|
+
*/
|
|
4
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
5
|
+
export function randomToken(byteLength = 32) {
|
|
6
|
+
return randomBytes(byteLength).toString("base64url");
|
|
7
|
+
}
|
|
8
|
+
export function sha256Hex(value) {
|
|
9
|
+
return createHash("sha256").update(value).digest("hex");
|
|
10
|
+
}
|
|
11
|
+
export function tokenHashPrefix(tokenHash) {
|
|
12
|
+
return tokenHash.slice(0, 12);
|
|
13
|
+
}
|
|
14
|
+
export function timingSafeEqualString(a, b) {
|
|
15
|
+
const left = Buffer.from(sha256Hex(a), "hex");
|
|
16
|
+
const right = Buffer.from(sha256Hex(b), "hex");
|
|
17
|
+
return timingSafeEqual(left, right);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/crypto.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvE,MAAM,UAAU,WAAW,CAAC,UAAU,GAAG,EAAE;IACzC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,CAAS,EAAE,CAAS;IACxD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/C,OAAO,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { OAuthRegisteredClientsStore } from "@modelcontextprotocol/sdk/server/auth/clients.js";
|
|
2
|
+
import type { OAuthClientInformationFull } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
3
|
+
export interface StoredAuthorizationCode {
|
|
4
|
+
codeHash: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
redirectUri: string;
|
|
7
|
+
codeChallenge: string;
|
|
8
|
+
scopes: string[];
|
|
9
|
+
resource: string;
|
|
10
|
+
createdAt: number;
|
|
11
|
+
expiresAt: number;
|
|
12
|
+
consumedAt?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface StoredToken {
|
|
15
|
+
tokenHash: string;
|
|
16
|
+
tokenType: "access" | "refresh";
|
|
17
|
+
clientId: string;
|
|
18
|
+
scopes: string[];
|
|
19
|
+
resource: string;
|
|
20
|
+
issuedAt: number;
|
|
21
|
+
expiresAt: number;
|
|
22
|
+
revokedAt?: number;
|
|
23
|
+
parentRefreshTokenHash?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare class FileOAuthStore implements OAuthRegisteredClientsStore {
|
|
26
|
+
readonly path: string;
|
|
27
|
+
private snapshot;
|
|
28
|
+
constructor(path: string);
|
|
29
|
+
load(): Promise<void>;
|
|
30
|
+
getClient(clientId: string): Promise<OAuthClientInformationFull | undefined>;
|
|
31
|
+
registerClient(client: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
|
|
32
|
+
putAuthorizationCode(code: string, record: Omit<StoredAuthorizationCode, "codeHash" | "consumedAt">): Promise<void>;
|
|
33
|
+
getAuthorizationCode(code: string, nowSeconds: number): Promise<StoredAuthorizationCode | undefined>;
|
|
34
|
+
consumeAuthorizationCode(code: string, nowSeconds: number): Promise<StoredAuthorizationCode | undefined>;
|
|
35
|
+
putToken(token: string, record: Omit<StoredToken, "tokenHash" | "revokedAt">): Promise<StoredToken>;
|
|
36
|
+
findToken(token: string): Promise<StoredToken | undefined>;
|
|
37
|
+
revokeToken(token: string, nowSeconds: number): Promise<void>;
|
|
38
|
+
private persist;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=file-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/file-store.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AACpG,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AAI3F,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AASD,qBAAa,cAAe,YAAW,2BAA2B;IAGpD,QAAQ,CAAC,IAAI,EAAE,MAAM;IAFjC,OAAO,CAAC,QAAQ,CAA6E;gBAExE,IAAI,EAAE,MAAM;IAE3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBrB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAI5E,cAAc,CAAC,MAAM,EAAE,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAMvF,oBAAoB,CACxB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,GAAG,YAAY,CAAC,GAC/D,OAAO,CAAC,IAAI,CAAC;IAMV,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC;IAMpG,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC;IASxG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAQnG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAI1D,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAQrD,OAAO;CAmBtB"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-12 hosted OAuth — file-backed store for DCR clients, auth codes, tokens
|
|
3
|
+
* (ported from mcp-wave; generic, atomic-persist). Holds only OAuth artifacts
|
|
4
|
+
* (hashed codes/tokens) — never an h2a ed25519 private key.
|
|
5
|
+
*/
|
|
6
|
+
import { mkdir, open, readFile, rename, writeFile } from "node:fs/promises";
|
|
7
|
+
import { dirname } from "node:path";
|
|
8
|
+
import { sha256Hex } from "./crypto.js";
|
|
9
|
+
export class FileOAuthStore {
|
|
10
|
+
path;
|
|
11
|
+
snapshot = { version: 1, clients: {}, authorizationCodes: {}, tokens: {} };
|
|
12
|
+
constructor(path) {
|
|
13
|
+
this.path = path;
|
|
14
|
+
}
|
|
15
|
+
async load() {
|
|
16
|
+
try {
|
|
17
|
+
const parsed = JSON.parse(await readFile(this.path, "utf8"));
|
|
18
|
+
this.snapshot = {
|
|
19
|
+
version: 1,
|
|
20
|
+
clients: parsed.clients ?? {},
|
|
21
|
+
authorizationCodes: parsed.authorizationCodes ?? {},
|
|
22
|
+
tokens: parsed.tokens ?? {}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
27
|
+
await this.persist();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async getClient(clientId) {
|
|
34
|
+
return this.snapshot.clients[clientId];
|
|
35
|
+
}
|
|
36
|
+
async registerClient(client) {
|
|
37
|
+
this.snapshot.clients[client.client_id] = client;
|
|
38
|
+
await this.persist();
|
|
39
|
+
return client;
|
|
40
|
+
}
|
|
41
|
+
async putAuthorizationCode(code, record) {
|
|
42
|
+
const codeHash = sha256Hex(code);
|
|
43
|
+
this.snapshot.authorizationCodes[codeHash] = { ...record, codeHash };
|
|
44
|
+
await this.persist();
|
|
45
|
+
}
|
|
46
|
+
async getAuthorizationCode(code, nowSeconds) {
|
|
47
|
+
const record = this.snapshot.authorizationCodes[sha256Hex(code)];
|
|
48
|
+
if (!record || record.consumedAt || record.expiresAt <= nowSeconds)
|
|
49
|
+
return undefined;
|
|
50
|
+
return record;
|
|
51
|
+
}
|
|
52
|
+
async consumeAuthorizationCode(code, nowSeconds) {
|
|
53
|
+
const codeHash = sha256Hex(code);
|
|
54
|
+
const record = this.snapshot.authorizationCodes[codeHash];
|
|
55
|
+
if (!record || record.consumedAt || record.expiresAt <= nowSeconds)
|
|
56
|
+
return undefined;
|
|
57
|
+
record.consumedAt = nowSeconds;
|
|
58
|
+
await this.persist();
|
|
59
|
+
return record;
|
|
60
|
+
}
|
|
61
|
+
async putToken(token, record) {
|
|
62
|
+
const tokenHash = sha256Hex(token);
|
|
63
|
+
const stored = { ...record, tokenHash };
|
|
64
|
+
this.snapshot.tokens[tokenHash] = stored;
|
|
65
|
+
await this.persist();
|
|
66
|
+
return stored;
|
|
67
|
+
}
|
|
68
|
+
async findToken(token) {
|
|
69
|
+
return this.snapshot.tokens[sha256Hex(token)];
|
|
70
|
+
}
|
|
71
|
+
async revokeToken(token, nowSeconds) {
|
|
72
|
+
const record = this.snapshot.tokens[sha256Hex(token)];
|
|
73
|
+
if (record && record.revokedAt === undefined) {
|
|
74
|
+
record.revokedAt = nowSeconds;
|
|
75
|
+
await this.persist();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async persist() {
|
|
79
|
+
await mkdir(dirname(this.path), { recursive: true });
|
|
80
|
+
const body = `${JSON.stringify(this.snapshot, null, 2)}\n`;
|
|
81
|
+
const tempPath = `${this.path}.${process.pid}.${Date.now()}.tmp`;
|
|
82
|
+
await writeFile(tempPath, body, { mode: 0o600 });
|
|
83
|
+
const handle = await open(tempPath, "r");
|
|
84
|
+
try {
|
|
85
|
+
await handle.sync();
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
// Windows rejects fsync on some handles with EPERM, and exotic FUSE/CI
|
|
89
|
+
// filesystems return ENOSYS. The durability hint is best-effort; the
|
|
90
|
+
// rename below still provides atomic replace on every platform.
|
|
91
|
+
const code = error.code;
|
|
92
|
+
if (code !== "EPERM" && code !== "ENOSYS")
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
await handle.close();
|
|
97
|
+
}
|
|
98
|
+
await rename(tempPath, this.path);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=file-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/file-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { type H2AHostedOAuthConfig } from "./config.js";
|
|
3
|
+
import type { SingleTenantOAuthProvider } from "./single-tenant-provider.js";
|
|
4
|
+
export declare function buildOAuthRoutes(provider: SingleTenantOAuthProvider, oauth: H2AHostedOAuthConfig): Hono;
|
|
5
|
+
//# sourceMappingURL=hono-oauth-router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono-oauth-router.d.ts","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/hono-oauth-router.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAyC,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAE7E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,yBAAyB,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAsFvG"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-12 hosted OAuth — authorization-server + protected-resource routes
|
|
3
|
+
* (ported from mcp-wave). Standard endpoints (DCR, token+PKCE, revoke,
|
|
4
|
+
* well-known metadata) come from `@hono/mcp/auth`; only `/authorize` is custom
|
|
5
|
+
* (operator consent secret gate, single-tenant). resourceName = "h2a".
|
|
6
|
+
*/
|
|
7
|
+
import { authenticateClient, clientRegistrationHandler, createOAuthMetadata, revokeHandler, tokenHandler, wellKnownRouter } from "@hono/mcp/auth";
|
|
8
|
+
import { OAuthError, ServerError } from "@modelcontextprotocol/sdk/server/auth/errors.js";
|
|
9
|
+
import { Hono } from "hono";
|
|
10
|
+
import { H2A_HOSTED_OAUTH_SCOPE as OAUTH_SCOPE } from "./config.js";
|
|
11
|
+
export function buildOAuthRoutes(provider, oauth) {
|
|
12
|
+
const sdkProvider = provider;
|
|
13
|
+
const clientsStore = provider.clientsStore;
|
|
14
|
+
const router = new Hono();
|
|
15
|
+
// RFC 8414: issuer identifier must equal the metadata-URL value (no trailing
|
|
16
|
+
// slash) — a URL object would normalize to a trailing slash that claude.ai rejects.
|
|
17
|
+
const issuer = oauth.issuerUrl.href.replace(/\/+$/, "");
|
|
18
|
+
const oauthMetadata = createOAuthMetadata({
|
|
19
|
+
provider: sdkProvider,
|
|
20
|
+
issuerUrl: issuer,
|
|
21
|
+
baseUrl: oauth.publicBaseUrl,
|
|
22
|
+
scopesSupported: [OAUTH_SCOPE]
|
|
23
|
+
});
|
|
24
|
+
router.route("/", wellKnownRouter({
|
|
25
|
+
oauthMetadata,
|
|
26
|
+
resourceServerUrl: oauth.resourceServerUrl,
|
|
27
|
+
scopesSupported: [OAUTH_SCOPE],
|
|
28
|
+
resourceName: "h2a"
|
|
29
|
+
}));
|
|
30
|
+
// Also serve PRM at the unsuffixed path (the bearerAuth 401 advertises it there).
|
|
31
|
+
router.get("/.well-known/oauth-protected-resource", (c) => c.json({
|
|
32
|
+
resource: oauth.resourceServerUrl.href,
|
|
33
|
+
authorization_servers: [issuer],
|
|
34
|
+
bearer_methods_supported: ["header"],
|
|
35
|
+
scopes_supported: [OAUTH_SCOPE],
|
|
36
|
+
resource_name: "h2a"
|
|
37
|
+
}));
|
|
38
|
+
router.post("/register", clientRegistrationHandler({ clientsStore }));
|
|
39
|
+
router.post("/token", authenticateClient({ clientsStore }), tokenHandler(sdkProvider));
|
|
40
|
+
router.post("/revoke", authenticateClient({ clientsStore }), revokeHandler(sdkProvider));
|
|
41
|
+
router.on(["GET", "POST"], "/authorize", async (c) => {
|
|
42
|
+
c.header("Cache-Control", "no-store");
|
|
43
|
+
const raw = c.req.method === "POST"
|
|
44
|
+
? (await c.req.parseBody())
|
|
45
|
+
: c.req.query();
|
|
46
|
+
const clientId = raw["client_id"];
|
|
47
|
+
if (!clientId) {
|
|
48
|
+
return c.json({ error: "invalid_request", error_description: "missing client_id" }, 400);
|
|
49
|
+
}
|
|
50
|
+
const client = await provider.clientsStore.getClient(clientId);
|
|
51
|
+
if (!client) {
|
|
52
|
+
return c.json({ error: "invalid_client", error_description: "unknown client_id" }, 400);
|
|
53
|
+
}
|
|
54
|
+
const redirectUri = raw["redirect_uri"] ?? client.redirect_uris[0] ?? "";
|
|
55
|
+
const scopeRaw = raw["scope"];
|
|
56
|
+
const stateRaw = raw["state"];
|
|
57
|
+
const resourceRaw = raw["resource"];
|
|
58
|
+
const params = {
|
|
59
|
+
redirectUri,
|
|
60
|
+
codeChallenge: raw["code_challenge"] ?? "",
|
|
61
|
+
...(scopeRaw !== undefined && { scopes: scopeRaw.split(" ") }),
|
|
62
|
+
...(stateRaw !== undefined && { state: stateRaw }),
|
|
63
|
+
...(resourceRaw !== undefined && { resource: new URL(resourceRaw) })
|
|
64
|
+
};
|
|
65
|
+
try {
|
|
66
|
+
const consentSecret = raw["consent_secret"];
|
|
67
|
+
const outcome = await provider.authorizeRequest(client, params, {
|
|
68
|
+
method: c.req.method,
|
|
69
|
+
...(consentSecret !== undefined && { consentSecret })
|
|
70
|
+
});
|
|
71
|
+
if (outcome.kind === "consent") {
|
|
72
|
+
return c.html(outcome.html, outcome.status);
|
|
73
|
+
}
|
|
74
|
+
return c.redirect(outcome.location, 302);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
const err = e instanceof OAuthError ? e : new ServerError("Internal Server Error");
|
|
78
|
+
return c.json(err.toResponseObject(), err instanceof ServerError ? 500 : 400);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return router;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=hono-oauth-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hono-oauth-router.js","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/hono-oauth-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-12 hosted OAuth — redirect-uri allow checks (ported from mcp-wave;
|
|
3
|
+
* decoupled from the Wave env type — takes a plain nodeEnv string).
|
|
4
|
+
*
|
|
5
|
+
* claude.ai's connector uses fixed redirect URIs
|
|
6
|
+
* (https://claude.ai|claude.com/api/mcp/auth_callback) — those must be in
|
|
7
|
+
* `allowedRedirectUris`. Loopback is allowed only outside production (local dev).
|
|
8
|
+
*/
|
|
9
|
+
export declare function redirectUriAllowed(redirectUri: string, allowedRedirectUris: readonly string[], nodeEnv: string): boolean;
|
|
10
|
+
export declare function allRedirectUrisAllowed(redirectUris: readonly string[], allowedRedirectUris: readonly string[], nodeEnv: string): boolean;
|
|
11
|
+
//# sourceMappingURL=redirect-uri.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect-uri.d.ts","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/redirect-uri.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,mBAAmB,EAAE,SAAS,MAAM,EAAE,EACtC,OAAO,EAAE,MAAM,GACd,OAAO,CAiBT;AAED,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,mBAAmB,EAAE,SAAS,MAAM,EAAE,EACtC,OAAO,EAAE,MAAM,GACd,OAAO,CAET"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-12 hosted OAuth — redirect-uri allow checks (ported from mcp-wave;
|
|
3
|
+
* decoupled from the Wave env type — takes a plain nodeEnv string).
|
|
4
|
+
*
|
|
5
|
+
* claude.ai's connector uses fixed redirect URIs
|
|
6
|
+
* (https://claude.ai|claude.com/api/mcp/auth_callback) — those must be in
|
|
7
|
+
* `allowedRedirectUris`. Loopback is allowed only outside production (local dev).
|
|
8
|
+
*/
|
|
9
|
+
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "::1"]);
|
|
10
|
+
export function redirectUriAllowed(redirectUri, allowedRedirectUris, nodeEnv) {
|
|
11
|
+
let parsed;
|
|
12
|
+
try {
|
|
13
|
+
parsed = new URL(redirectUri);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (allowedRedirectUris.includes(parsed.href)) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
if (nodeEnv !== "production" && LOOPBACK_HOSTS.has(parsed.hostname)) {
|
|
22
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
export function allRedirectUrisAllowed(redirectUris, allowedRedirectUris, nodeEnv) {
|
|
27
|
+
return redirectUris.every((uri) => redirectUriAllowed(uri, allowedRedirectUris, nodeEnv));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=redirect-uri.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect-uri.js","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/redirect-uri.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;AAElE,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,mBAAsC,EACtC,OAAe;IAEf,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,OAAO,KAAK,YAAY,IAAI,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpE,OAAO,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,CAAC;IACrE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,YAA+B,EAC/B,mBAAsC,EACtC,OAAe;IAEf,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,EAAE,OAAO,CAAC,CAAC,CAAC;AAC5F,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EVO-12 hosted OAuth — single-tenant authorization server (ported from
|
|
3
|
+
* mcp-wave). Implements the MCP SDK OAuthServerProvider surface: DCR client
|
|
4
|
+
* registration (redirect-uri allowlisted), operator-consent authorize,
|
|
5
|
+
* auth-code + PKCE exchange, refresh, access-token verify/revoke. Scope is
|
|
6
|
+
* read-only `h2a:read`. The OAuth tokens grant access to the read-only MCP tool
|
|
7
|
+
* surface only — never to any signing tool / private key (DEC-116). The
|
|
8
|
+
* client never receives an h2a private key.
|
|
9
|
+
*/
|
|
10
|
+
import type { OAuthRegisteredClientsStore } from "@modelcontextprotocol/sdk/server/auth/clients.js";
|
|
11
|
+
import type { AuthorizationParams } from "@modelcontextprotocol/sdk/server/auth/provider.js";
|
|
12
|
+
import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
|
|
13
|
+
import type { OAuthClientInformationFull, OAuthTokenRevocationRequest, OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
14
|
+
import type { FileOAuthStore } from "./file-store.js";
|
|
15
|
+
export type AuthorizeOutcome = {
|
|
16
|
+
kind: "consent";
|
|
17
|
+
status: 200 | 401;
|
|
18
|
+
html: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "redirect";
|
|
21
|
+
location: string;
|
|
22
|
+
};
|
|
23
|
+
interface ProviderOptions {
|
|
24
|
+
store: FileOAuthStore;
|
|
25
|
+
nodeEnv: string;
|
|
26
|
+
issuerUrl: URL;
|
|
27
|
+
publicBaseUrl: URL;
|
|
28
|
+
resourceServerUrl: URL;
|
|
29
|
+
consentSecret: string;
|
|
30
|
+
allowedRedirectUris: readonly string[];
|
|
31
|
+
authCodeTtlSeconds: number;
|
|
32
|
+
accessTokenTtlSeconds: number;
|
|
33
|
+
refreshTokenTtlSeconds: number;
|
|
34
|
+
nowSeconds?: () => number;
|
|
35
|
+
}
|
|
36
|
+
interface IssueCodeParams {
|
|
37
|
+
redirectUri: string;
|
|
38
|
+
codeChallenge: string;
|
|
39
|
+
scopes: string[];
|
|
40
|
+
resource?: URL;
|
|
41
|
+
state?: string;
|
|
42
|
+
}
|
|
43
|
+
type WideClientsStore = Omit<OAuthRegisteredClientsStore, "registerClient"> & {
|
|
44
|
+
registerClient?(client: OAuthClientInformationFull): OAuthClientInformationFull | Promise<OAuthClientInformationFull>;
|
|
45
|
+
};
|
|
46
|
+
export declare class SingleTenantOAuthProvider {
|
|
47
|
+
private readonly opts;
|
|
48
|
+
readonly clientsStore: WideClientsStore;
|
|
49
|
+
constructor(opts: ProviderOptions);
|
|
50
|
+
private nowSeconds;
|
|
51
|
+
authorizeRequest(client: OAuthClientInformationFull, params: AuthorizationParams, input: {
|
|
52
|
+
method: string;
|
|
53
|
+
consentSecret?: string;
|
|
54
|
+
}): Promise<AuthorizeOutcome>;
|
|
55
|
+
issueAuthorizationCode(client: OAuthClientInformationFull, params: IssueCodeParams): Promise<string>;
|
|
56
|
+
private renderConsentForm;
|
|
57
|
+
challengeForAuthorizationCode(_client: OAuthClientInformationFull, authorizationCode: string): Promise<string>;
|
|
58
|
+
exchangeAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string, _codeVerifier?: string, redirectUri?: string, resource?: URL): Promise<OAuthTokens>;
|
|
59
|
+
exchangeRefreshToken(client: OAuthClientInformationFull, refreshToken: string, scopes?: string[], resource?: URL): Promise<OAuthTokens>;
|
|
60
|
+
verifyAccessToken(token: string): Promise<AuthInfo>;
|
|
61
|
+
revokeToken(_client: OAuthClientInformationFull, request: OAuthTokenRevocationRequest): Promise<void>;
|
|
62
|
+
issueTokensForTests(client: OAuthClientInformationFull): Promise<OAuthTokens>;
|
|
63
|
+
private issueTokens;
|
|
64
|
+
private normalizeScopes;
|
|
65
|
+
private normalizeResource;
|
|
66
|
+
}
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=single-tenant-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"single-tenant-provider.d.ts","sourceRoot":"","sources":["../../../../src/runtime/mcp-http/oauth/single-tenant-provider.ts"],"names":[],"mappings":"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"}
|