@softure-ai/mcp-access 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +49 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/jobs/index.d.ts +12 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +22 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/options.d.ts +8 -0
- package/dist/options.d.ts.map +1 -1
- package/dist/options.js +7 -0
- package/dist/options.js.map +1 -1
- package/dist/schema.d.ts +58 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +9 -4
- package/dist/schema.js.map +1 -1
- package/dist/scripts/index.d.ts +2 -0
- package/dist/scripts/index.d.ts.map +1 -0
- package/dist/scripts/index.js +4 -0
- package/dist/scripts/index.js.map +1 -0
- package/dist/scripts/registration-scripts.d.ts +15 -0
- package/dist/scripts/registration-scripts.d.ts.map +1 -0
- package/dist/scripts/registration-scripts.js +73 -0
- package/dist/scripts/registration-scripts.js.map +1 -0
- package/dist/server/health.d.ts.map +1 -1
- package/dist/server/health.js +3 -2
- package/dist/server/health.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/oauth-http.d.ts +2 -0
- package/dist/server/oauth-http.d.ts.map +1 -1
- package/dist/server/oauth-http.js +18 -0
- package/dist/server/oauth-http.js.map +1 -1
- package/dist/server/registration-window.d.ts +20 -0
- package/dist/server/registration-window.d.ts.map +1 -0
- package/dist/server/registration-window.js +41 -0
- package/dist/server/registration-window.js.map +1 -0
- package/migrations/0003_create_oauth_registration_window.sql +11 -0
- package/module.json +3 -3
- package/package.json +21 -1
- package/src/index.ts +3 -3
- package/src/jobs/index.ts +23 -0
- package/src/options.ts +7 -0
- package/src/schema.ts +10 -4
- package/src/scripts/index.ts +9 -0
- package/src/scripts/registration-scripts.ts +98 -0
- package/src/server/health.ts +3 -2
- package/src/server/index.ts +9 -0
- package/src/server/oauth-http.ts +16 -0
- package/src/server/registration-window.ts +55 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// The window in which dynamic client registration is open while `oauth.registration` is "closed"
|
|
2
|
+
// (#520): one stored row with its end, written by the `open-client-registration` ops script. Every
|
|
3
|
+
// comparison uses the context's clock, so tests and scripts agree with the route.
|
|
4
|
+
import { oauthRegistrationWindow } from "../schema.js";
|
|
5
|
+
import { getMcpAccessOptions } from "./options.js";
|
|
6
|
+
import type { McpAccessContext } from "./tokens.js";
|
|
7
|
+
|
|
8
|
+
/** The longest window one call opens: a day. */
|
|
9
|
+
export const MAX_REGISTRATION_WINDOW_MINUTES = 1440;
|
|
10
|
+
|
|
11
|
+
export interface ClientRegistrationWindow {
|
|
12
|
+
readonly openedAt: Date;
|
|
13
|
+
readonly openUntil: Date;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface OpenClientRegistrationInput {
|
|
17
|
+
/** Minutes from now, 1 to 1440. */
|
|
18
|
+
readonly minutes: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The stored window, past or not; null when none is stored. */
|
|
22
|
+
export async function findClientRegistrationWindow(ctx: McpAccessContext): Promise<ClientRegistrationWindow | null> {
|
|
23
|
+
const [row] = await ctx.db
|
|
24
|
+
.select({ openedAt: oauthRegistrationWindow.openedAt, openUntil: oauthRegistrationWindow.openUntil })
|
|
25
|
+
.from(oauthRegistrationWindow)
|
|
26
|
+
.limit(1);
|
|
27
|
+
return row ?? null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** True with `oauth.registration: "open"`; with "closed", only while a stored window has not ended. */
|
|
31
|
+
export async function isClientRegistrationOpen(ctx: McpAccessContext): Promise<boolean> {
|
|
32
|
+
if (getMcpAccessOptions(ctx.config).oauth.registration === "open") return true;
|
|
33
|
+
const window = await findClientRegistrationWindow(ctx);
|
|
34
|
+
return window !== null && window.openUntil.getTime() > ctx.clock.now().getTime();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Opens registration for `minutes` from now, replacing any stored window. Throws on minutes outside 1 to 1440: a bug in the caller. */
|
|
38
|
+
export async function openClientRegistration(ctx: McpAccessContext, input: OpenClientRegistrationInput): Promise<ClientRegistrationWindow> {
|
|
39
|
+
if (!Number.isInteger(input.minutes) || input.minutes < 1 || input.minutes > MAX_REGISTRATION_WINDOW_MINUTES) {
|
|
40
|
+
throw new Error(`openClientRegistration: minutes must be a whole number from 1 to ${String(MAX_REGISTRATION_WINDOW_MINUTES)}, got ${String(input.minutes)}`);
|
|
41
|
+
}
|
|
42
|
+
const openedAt = ctx.clock.now();
|
|
43
|
+
const openUntil = new Date(openedAt.getTime() + input.minutes * 60_000);
|
|
44
|
+
await ctx.db
|
|
45
|
+
.insert(oauthRegistrationWindow)
|
|
46
|
+
.values({ id: 1, openedAt, openUntil })
|
|
47
|
+
.onConflictDoUpdate({ target: oauthRegistrationWindow.id, set: { openedAt, openUntil } });
|
|
48
|
+
return { openedAt, openUntil };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Deletes the stored window. True when one was stored, ended or not. */
|
|
52
|
+
export async function closeClientRegistration(ctx: McpAccessContext): Promise<boolean> {
|
|
53
|
+
const deleted = await ctx.db.delete(oauthRegistrationWindow).returning({ id: oauthRegistrationWindow.id });
|
|
54
|
+
return deleted.length > 0;
|
|
55
|
+
}
|