runbios-mcp 0.2.1-dev.62
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/README.md +363 -0
- package/dist/api-client.d.ts +147 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +806 -0
- package/dist/api-client.js.map +1 -0
- package/dist/auth.d.ts +3 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +11 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +16 -0
- package/dist/config.js.map +1 -0
- package/dist/deployment-contract.d.ts +78 -0
- package/dist/deployment-contract.d.ts.map +1 -0
- package/dist/deployment-contract.js +155 -0
- package/dist/deployment-contract.js.map +1 -0
- package/dist/gpu-priorities.d.ts +25 -0
- package/dist/gpu-priorities.d.ts.map +1 -0
- package/dist/gpu-priorities.js +61 -0
- package/dist/gpu-priorities.js.map +1 -0
- package/dist/http/app.d.ts +14 -0
- package/dist/http/app.d.ts.map +1 -0
- package/dist/http/app.js +140 -0
- package/dist/http/app.js.map +1 -0
- package/dist/http/audit.d.ts +23 -0
- package/dist/http/audit.d.ts.map +1 -0
- package/dist/http/audit.js +41 -0
- package/dist/http/audit.js.map +1 -0
- package/dist/http/config.d.ts +23 -0
- package/dist/http/config.d.ts.map +1 -0
- package/dist/http/config.js +70 -0
- package/dist/http/config.js.map +1 -0
- package/dist/http/consent.d.ts +18 -0
- package/dist/http/consent.d.ts.map +1 -0
- package/dist/http/consent.js +148 -0
- package/dist/http/consent.js.map +1 -0
- package/dist/http/internal-auth.d.ts +22 -0
- package/dist/http/internal-auth.d.ts.map +1 -0
- package/dist/http/internal-auth.js +73 -0
- package/dist/http/internal-auth.js.map +1 -0
- package/dist/http/main.d.ts +3 -0
- package/dist/http/main.d.ts.map +1 -0
- package/dist/http/main.js +65 -0
- package/dist/http/main.js.map +1 -0
- package/dist/http/mcp-handler.d.ts +12 -0
- package/dist/http/mcp-handler.d.ts.map +1 -0
- package/dist/http/mcp-handler.js +103 -0
- package/dist/http/mcp-handler.js.map +1 -0
- package/dist/http/metadata.d.ts +6 -0
- package/dist/http/metadata.d.ts.map +1 -0
- package/dist/http/metadata.js +32 -0
- package/dist/http/metadata.js.map +1 -0
- package/dist/http/oauth.d.ts +56 -0
- package/dist/http/oauth.d.ts.map +1 -0
- package/dist/http/oauth.js +486 -0
- package/dist/http/oauth.js.map +1 -0
- package/dist/http/serviceHostGuard.d.ts +31 -0
- package/dist/http/serviceHostGuard.d.ts.map +1 -0
- package/dist/http/serviceHostGuard.js +68 -0
- package/dist/http/serviceHostGuard.js.map +1 -0
- package/dist/http/store.d.ts +150 -0
- package/dist/http/store.d.ts.map +1 -0
- package/dist/http/store.js +366 -0
- package/dist/http/store.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +79 -0
- package/dist/index.js.map +1 -0
- package/dist/inference-contract.d.ts +29 -0
- package/dist/inference-contract.d.ts.map +1 -0
- package/dist/inference-contract.js +112 -0
- package/dist/inference-contract.js.map +1 -0
- package/dist/redaction.d.ts +74 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +316 -0
- package/dist/redaction.js.map +1 -0
- package/dist/server.d.ts +63 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +2282 -0
- package/dist/server.js.map +1 -0
- package/dist/training-contract.d.ts +107 -0
- package/dist/training-contract.d.ts.map +1 -0
- package/dist/training-contract.js +141 -0
- package/dist/training-contract.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import pg from "pg";
|
|
3
|
+
import { loadHostedConfig } from "./config.js";
|
|
4
|
+
import { logServiceHostProblems } from "./serviceHostGuard.js";
|
|
5
|
+
import { PgStore } from "./store.js";
|
|
6
|
+
import { createApp } from "./app.js";
|
|
7
|
+
import { createAudit } from "./audit.js";
|
|
8
|
+
/** Entry point for the hosted MCP HTTP service (ECS service "bios-mcp"). */
|
|
9
|
+
function logLine(level, evt, fields = {}) {
|
|
10
|
+
process.stdout.write(`${JSON.stringify({ ts: new Date().toISOString(), level, evt, ...fields })}\n`);
|
|
11
|
+
}
|
|
12
|
+
async function main() {
|
|
13
|
+
const cfg = loadHostedConfig();
|
|
14
|
+
// Non-fatal ECS boot guard: warn loudly if internal peers would fall back to
|
|
15
|
+
// localhost under ECS. No-op locally. Never throws.
|
|
16
|
+
logServiceHostProblems();
|
|
17
|
+
const pool = new pg.Pool({
|
|
18
|
+
connectionString: cfg.databaseUrl,
|
|
19
|
+
max: 10,
|
|
20
|
+
idleTimeoutMillis: 30_000,
|
|
21
|
+
connectionTimeoutMillis: 10_000,
|
|
22
|
+
});
|
|
23
|
+
pool.on("error", (err) => {
|
|
24
|
+
logLine("error", "pg_pool_error", { error: err.message });
|
|
25
|
+
});
|
|
26
|
+
const store = new PgStore(pool);
|
|
27
|
+
await store.migrate();
|
|
28
|
+
const audit = createAudit({
|
|
29
|
+
auditBaseUrl: cfg.auditServiceHost ? `http://${cfg.auditServiceHost}:${cfg.auditServicePort}` : "",
|
|
30
|
+
internalServiceKey: cfg.internalServiceKey,
|
|
31
|
+
});
|
|
32
|
+
const app = createApp({ store, cfg, audit });
|
|
33
|
+
const server = app.listen(cfg.port, "0.0.0.0", () => {
|
|
34
|
+
logLine("info", "server_started", { port: cfg.port, mcp_path: cfg.publicMcpPath });
|
|
35
|
+
});
|
|
36
|
+
server.requestTimeout = 0; // long-lived MCP requests; the transport manages its own lifecycle
|
|
37
|
+
server.headersTimeout = 65_000;
|
|
38
|
+
const sweep = setInterval(() => {
|
|
39
|
+
void store.cleanupExpired().catch((err) => {
|
|
40
|
+
logLine("warn", "cleanup_failed", { error: err instanceof Error ? err.message : "unknown" });
|
|
41
|
+
});
|
|
42
|
+
}, 3600_000);
|
|
43
|
+
sweep.unref();
|
|
44
|
+
let shuttingDown = false;
|
|
45
|
+
const shutdown = (signal) => {
|
|
46
|
+
if (shuttingDown)
|
|
47
|
+
return;
|
|
48
|
+
shuttingDown = true;
|
|
49
|
+
logLine("info", "shutting_down", { signal });
|
|
50
|
+
clearInterval(sweep);
|
|
51
|
+
server.close(() => {
|
|
52
|
+
void pool.end().finally(() => process.exit(0));
|
|
53
|
+
});
|
|
54
|
+
// Do not hang forever on stuck connections.
|
|
55
|
+
setTimeout(() => process.exit(0), 25_000).unref();
|
|
56
|
+
};
|
|
57
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
58
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
59
|
+
}
|
|
60
|
+
main().catch((err) => {
|
|
61
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
62
|
+
console.error(`bios-mcp failed to start: ${message}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/http/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Request, Response } from "express";
|
|
2
|
+
import type { AuditEmitter } from "./audit.js";
|
|
3
|
+
import type { HostedConfig } from "./config.js";
|
|
4
|
+
import type { McpStore } from "./store.js";
|
|
5
|
+
export interface McpHandlerDeps {
|
|
6
|
+
store: McpStore;
|
|
7
|
+
cfg: HostedConfig;
|
|
8
|
+
audit: AuditEmitter;
|
|
9
|
+
}
|
|
10
|
+
export declare function createMcpPostHandler(deps: McpHandlerDeps): (req: Request, res: Response) => Promise<void>;
|
|
11
|
+
export declare function methodNotAllowed(req: Request, res: Response): void;
|
|
12
|
+
//# sourceMappingURL=mcp-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-handler.d.ts","sourceRoot":"","sources":["../../src/http/mcp-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA6B3C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,GAAG,EAAE,YAAY,CAAC;IAClB,KAAK,EAAE,YAAY,CAAC;CACrB;AAgBD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,cAAc,IAGnB,KAAK,OAAO,EAAE,KAAK,QAAQ,KAAG,OAAO,CAAC,IAAI,CAAC,CAwDhF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CASlE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
+
import { BiosClient } from "../api-client.js";
|
|
3
|
+
import { createBiosMcpServer, VERSION } from "../server.js";
|
|
4
|
+
import { validateAccessToken } from "./oauth.js";
|
|
5
|
+
/**
|
|
6
|
+
* The hosted MCP endpoint is fully stateless: every POST validates the
|
|
7
|
+
* bearer token, builds a per-request BiosClient pointed at the internal
|
|
8
|
+
* api-gateway (which re-checks the token, scopes, and workspace membership
|
|
9
|
+
* on every downstream call), runs the request through a fresh server +
|
|
10
|
+
* transport pair, and tears both down when the response ends.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Hosted variant of BiosClient. The control-plane API never returns a
|
|
14
|
+
* deployment's serving credential after creation (keys are shown exactly
|
|
15
|
+
* once at create/rotate time), so chat_with_inference cannot resolve one
|
|
16
|
+
* lazily. Fail with a clear, hosted-appropriate message instead of the
|
|
17
|
+
* stdio error that points at a local environment variable. The stdio path
|
|
18
|
+
* keeps using BiosClient unchanged.
|
|
19
|
+
*/
|
|
20
|
+
class HostedBiosClient extends BiosClient {
|
|
21
|
+
async inferenceApi() {
|
|
22
|
+
throw new Error("chat_with_inference is not available on the hosted MCP connection. " +
|
|
23
|
+
"Create an inference key from the deployment page in the console, then call the " +
|
|
24
|
+
"endpoint's OpenAI-compatible API directly with that key.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function unauthorized(res, cfg) {
|
|
28
|
+
res
|
|
29
|
+
.status(401)
|
|
30
|
+
.set("WWW-Authenticate", `Bearer resource_metadata="${cfg.publicBaseUrl}/.well-known/oauth-protected-resource/mcp", error="invalid_token"`)
|
|
31
|
+
.json({
|
|
32
|
+
jsonrpc: "2.0",
|
|
33
|
+
error: { code: -32001, message: "Unauthorized: a valid access token is required" },
|
|
34
|
+
id: null,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export function createMcpPostHandler(deps) {
|
|
38
|
+
const { store, cfg, audit } = deps;
|
|
39
|
+
return async function handleMcpPost(req, res) {
|
|
40
|
+
const header = req.header("authorization") ?? "";
|
|
41
|
+
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
42
|
+
const rawToken = match ? match[1].trim() : "";
|
|
43
|
+
const access = rawToken ? await validateAccessToken(store, rawToken) : null;
|
|
44
|
+
if (!access) {
|
|
45
|
+
unauthorized(res, cfg);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const { grant } = access;
|
|
49
|
+
const client = new HostedBiosClient({
|
|
50
|
+
baseUrl: `http://${cfg.apiGatewayHost}:${cfg.apiGatewayPort}`,
|
|
51
|
+
authHeaders: { Authorization: `Bearer ${rawToken}` },
|
|
52
|
+
workspaceId: grant.workspace_id,
|
|
53
|
+
orgId: grant.org_id || undefined,
|
|
54
|
+
userAgent: `bios-mcp-hosted/${VERSION}`,
|
|
55
|
+
});
|
|
56
|
+
const server = createBiosMcpServer(client, {
|
|
57
|
+
onToolCall: (info) => audit.emit("mcp_tool_call", {
|
|
58
|
+
tool: info.tool,
|
|
59
|
+
ok: info.ok,
|
|
60
|
+
ms: info.ms,
|
|
61
|
+
user_id: grant.user_id,
|
|
62
|
+
workspace_id: grant.workspace_id,
|
|
63
|
+
grant_id: grant.id,
|
|
64
|
+
...(info.error ? { error: info.error } : {}),
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
const transport = new StreamableHTTPServerTransport({
|
|
68
|
+
sessionIdGenerator: undefined,
|
|
69
|
+
enableJsonResponse: true,
|
|
70
|
+
});
|
|
71
|
+
res.on("close", () => {
|
|
72
|
+
void transport.close().catch(() => { });
|
|
73
|
+
void server.close().catch(() => { });
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
await server.connect(transport);
|
|
77
|
+
await transport.handleRequest(req, res, req.body);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
if (!res.headersSent) {
|
|
81
|
+
res.status(500).json({
|
|
82
|
+
jsonrpc: "2.0",
|
|
83
|
+
error: { code: -32603, message: "Internal server error" },
|
|
84
|
+
id: null,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else if (!res.writableEnded) {
|
|
88
|
+
res.end();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function methodNotAllowed(req, res) {
|
|
94
|
+
res
|
|
95
|
+
.status(405)
|
|
96
|
+
.set("Allow", "POST")
|
|
97
|
+
.json({
|
|
98
|
+
jsonrpc: "2.0",
|
|
99
|
+
error: { code: -32000, message: "Method not allowed: this MCP endpoint is stateless, use POST" },
|
|
100
|
+
id: null,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=mcp-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-handler.js","sourceRoot":"","sources":["../../src/http/mcp-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { HostedConfig } from "./config.js";
|
|
2
|
+
/** RFC 9728 protected resource metadata. */
|
|
3
|
+
export declare function protectedResourceMetadata(cfg: HostedConfig): Record<string, unknown>;
|
|
4
|
+
/** RFC 8414 authorization server metadata (also served as openid-configuration). */
|
|
5
|
+
export declare function authorizationServerMetadata(cfg: HostedConfig): Record<string, unknown>;
|
|
6
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/http/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQhD,4CAA4C;AAC5C,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASpF;AAED,oFAAoF;AACpF,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAatF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CANONICAL_SCOPES } from "./oauth.js";
|
|
2
|
+
// Docs live on the console; the origin is derived per environment from the
|
|
3
|
+
// hosted config's public base when available, with the production console as
|
|
4
|
+
// the default for published builds (customers use prod).
|
|
5
|
+
const DOCS_URL = `${(process.env.RUNBIOS_PLATFORM_ORIGIN || process.env.BIOS_PLATFORM_ORIGIN || "https://platform-dev.runbios.ai").replace(/\/$/, "")}/docs/mcp`;
|
|
6
|
+
/** RFC 9728 protected resource metadata. */
|
|
7
|
+
export function protectedResourceMetadata(cfg) {
|
|
8
|
+
return {
|
|
9
|
+
resource: `${cfg.publicBaseUrl}${cfg.publicMcpPath}`,
|
|
10
|
+
authorization_servers: [cfg.publicBaseUrl],
|
|
11
|
+
scopes_supported: [...CANONICAL_SCOPES],
|
|
12
|
+
bearer_methods_supported: ["header"],
|
|
13
|
+
resource_name: "Run BiOS",
|
|
14
|
+
resource_documentation: DOCS_URL,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** RFC 8414 authorization server metadata (also served as openid-configuration). */
|
|
18
|
+
export function authorizationServerMetadata(cfg) {
|
|
19
|
+
return {
|
|
20
|
+
issuer: cfg.publicBaseUrl,
|
|
21
|
+
authorization_endpoint: `${cfg.publicBaseUrl}/mcp/oauth/authorize`,
|
|
22
|
+
token_endpoint: `${cfg.publicBaseUrl}/mcp/oauth/token`,
|
|
23
|
+
registration_endpoint: `${cfg.publicBaseUrl}/mcp/oauth/register`,
|
|
24
|
+
response_types_supported: ["code"],
|
|
25
|
+
grant_types_supported: ["authorization_code", "refresh_token"],
|
|
26
|
+
code_challenge_methods_supported: ["S256"],
|
|
27
|
+
token_endpoint_auth_methods_supported: ["none", "client_secret_basic", "client_secret_post"],
|
|
28
|
+
scopes_supported: [...CANONICAL_SCOPES],
|
|
29
|
+
service_documentation: DOCS_URL,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/http/metadata.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,2EAA2E;AAC3E,6EAA6E;AAC7E,yDAAyD;AACzD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,iCAAiC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC;AAEjK,4CAA4C;AAC5C,MAAM,UAAU,yBAAyB,CAAC,GAAiB;IACzD,OAAO;QACL,QAAQ,EAAE,GAAG,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,aAAa,EAAE;QACpD,qBAAqB,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC;QAC1C,gBAAgB,EAAE,CAAC,GAAG,gBAAgB,CAAC;QACvC,wBAAwB,EAAE,CAAC,QAAQ,CAAC;QACpC,aAAa,EAAE,UAAU;QACzB,sBAAsB,EAAE,QAAQ;KACjC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,2BAA2B,CAAC,GAAiB;IAC3D,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,aAAa;QACzB,sBAAsB,EAAE,GAAG,GAAG,CAAC,aAAa,sBAAsB;QAClE,cAAc,EAAE,GAAG,GAAG,CAAC,aAAa,kBAAkB;QACtD,qBAAqB,EAAE,GAAG,GAAG,CAAC,aAAa,qBAAqB;QAChE,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,qBAAqB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAC9D,gCAAgC,EAAE,CAAC,MAAM,CAAC;QAC1C,qCAAqC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,oBAAoB,CAAC;QAC5F,gBAAgB,EAAE,CAAC,GAAG,gBAAgB,CAAC;QACvC,qBAAqB,EAAE,QAAQ;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import type { AuditEmitter } from "./audit.js";
|
|
3
|
+
import type { HostedConfig } from "./config.js";
|
|
4
|
+
import type { McpStore, OAuthGrantRow, OAuthTokenRow } from "./store.js";
|
|
5
|
+
export declare const CANONICAL_SCOPES: readonly ["models:read", "datasets:read", "datasets:write", "training:read", "training:write", "deployments:read", "deployments:write", "billing:read", "analytics:read", "integrations:read", "integrations:write", "serverless"];
|
|
6
|
+
/**
|
|
7
|
+
* Validates a scope list: non-empty, every scope canonical, no duplicates.
|
|
8
|
+
* Returns the scopes in catalog order (deterministic, like the Go side), or
|
|
9
|
+
* null when invalid.
|
|
10
|
+
*/
|
|
11
|
+
export declare function normalizeScopes(scopes: unknown): string[] | null;
|
|
12
|
+
/** Splits a space-separated scope parameter (RFC 6749 §3.3). */
|
|
13
|
+
export declare function parseScopeParam(scope: string): string[];
|
|
14
|
+
export declare function sha256Hex(value: string): string;
|
|
15
|
+
/** Constant-time string equality (hash both sides to normalize length). */
|
|
16
|
+
export declare function timingSafeEqualStr(a: string, b: string): boolean;
|
|
17
|
+
export declare function newRawToken(prefix: string): string;
|
|
18
|
+
export declare function newId(prefix: string): string;
|
|
19
|
+
export declare function verifyPkceS256(codeVerifier: string, codeChallenge: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Registered redirect URIs must be https, or http with a loopback hostname
|
|
22
|
+
* (localhost / 127.0.0.1) for native clients, and must not carry a fragment.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isValidRedirectUri(uri: string): boolean;
|
|
25
|
+
export declare const ACCESS_TOKEN_TTL_S = 3600;
|
|
26
|
+
export declare const REFRESH_TOKEN_TTL_MS: number;
|
|
27
|
+
export declare const AUTH_CODE_TTL_MS: number;
|
|
28
|
+
export declare const AUTH_REQUEST_TTL_MS: number;
|
|
29
|
+
export interface ValidatedAccess {
|
|
30
|
+
token: OAuthTokenRow;
|
|
31
|
+
grant: OAuthGrantRow;
|
|
32
|
+
}
|
|
33
|
+
export declare function validateAccessToken(store: McpStore, rawToken: string): Promise<ValidatedAccess | null>;
|
|
34
|
+
export interface IssuedPair {
|
|
35
|
+
accessToken: string;
|
|
36
|
+
refreshToken: string;
|
|
37
|
+
refreshTokenHash: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function issueTokenPair(store: McpStore, grantId: string, familyId?: string): Promise<IssuedPair>;
|
|
40
|
+
export declare class SlidingWindowLimiter {
|
|
41
|
+
private readonly limit;
|
|
42
|
+
private readonly windowMs;
|
|
43
|
+
private readonly now;
|
|
44
|
+
private readonly hits;
|
|
45
|
+
constructor(limit: number, windowMs: number, now?: () => number);
|
|
46
|
+
allow(key: string): boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface OAuthRouterDeps {
|
|
49
|
+
store: McpStore;
|
|
50
|
+
cfg: HostedConfig;
|
|
51
|
+
audit: AuditEmitter;
|
|
52
|
+
registerLimiter?: SlidingWindowLimiter;
|
|
53
|
+
tokenLimiter?: SlidingWindowLimiter;
|
|
54
|
+
}
|
|
55
|
+
export declare function createOAuthRouter(deps: OAuthRouterDeps): Router;
|
|
56
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/http/oauth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAkB,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIzF,eAAO,MAAM,gBAAgB,oOAiBnB,CAAC;AAIX;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,IAAI,CAUhE;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAID,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAIhE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5C;AAMD,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAInF;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAcvD;AAID,eAAO,MAAM,kBAAkB,OAAO,CAAC;AACvC,eAAO,MAAM,oBAAoB,QAAqB,CAAC;AACvD,eAAO,MAAM,gBAAgB,QAAc,CAAC;AAC5C,eAAO,MAAM,mBAAmB,QAAc,CAAC;AAI/C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,CAAC;IACrB,KAAK,EAAE,aAAa,CAAC;CACtB;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAUjC;AAID,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAsB,cAAc,CAClC,KAAK,EAAE,QAAQ,EACf,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAqB,GAC9B,OAAO,CAAC,UAAU,CAAC,CAoBrB;AAID,qBAAa,oBAAoB;IAI7B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IALtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;gBAGjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAM,MAAiB;IAG/C,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAiB5B;AAID,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,CAAC;IAChB,GAAG,EAAE,YAAY,CAAC;IAClB,KAAK,EAAE,YAAY,CAAC;IACpB,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AAyFD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAwS/D"}
|