@fragno-dev/mcp-fragment 0.0.0-stage → 0.0.3
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/LICENSE.md +16 -0
- package/README.md +312 -2
- package/bin/run.js +7 -0
- package/dist/browser/client/react.d.ts +253 -0
- package/dist/browser/client/react.d.ts.map +1 -0
- package/dist/browser/client/react.js +194 -0
- package/dist/browser/client/react.js.map +1 -0
- package/dist/browser/client/solid.d.ts +256 -0
- package/dist/browser/client/solid.d.ts.map +1 -0
- package/dist/browser/client/solid.js +129 -0
- package/dist/browser/client/solid.js.map +1 -0
- package/dist/browser/client/svelte.d.ts +256 -0
- package/dist/browser/client/svelte.d.ts.map +1 -0
- package/dist/browser/client/svelte.js +131 -0
- package/dist/browser/client/svelte.js.map +1 -0
- package/dist/browser/client/vanilla.d.ts +283 -0
- package/dist/browser/client/vanilla.d.ts.map +1 -0
- package/dist/browser/client/vanilla.js +159 -0
- package/dist/browser/client/vanilla.js.map +1 -0
- package/dist/browser/client/vue.d.ts +256 -0
- package/dist/browser/client/vue.d.ts.map +1 -0
- package/dist/browser/client/vue.js +127 -0
- package/dist/browser/client/vue.js.map +1 -0
- package/dist/browser/client-BCzNDSlW.d.ts +711 -0
- package/dist/browser/client-BCzNDSlW.d.ts.map +1 -0
- package/dist/browser/index.d.ts +813 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +1 -0
- package/dist/browser/src-B6dHZXqB.js +2303 -0
- package/dist/browser/src-B6dHZXqB.js.map +1 -0
- package/dist/cli/cli.d.ts +6 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +227 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/definition.js +330 -0
- package/dist/cli/definition.js.map +1 -0
- package/dist/cli/diagnostics.js +93 -0
- package/dist/cli/diagnostics.js.map +1 -0
- package/dist/cli/index.js +13 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/mcp-api.js +87 -0
- package/dist/cli/mcp-api.js.map +1 -0
- package/dist/cli/mcp-types.js +100 -0
- package/dist/cli/mcp-types.js.map +1 -0
- package/dist/cli/oauth-provider.js +113 -0
- package/dist/cli/oauth-provider.js.map +1 -0
- package/dist/cli/routes.js +743 -0
- package/dist/cli/routes.js.map +1 -0
- package/dist/cli/schema.js +13 -0
- package/dist/cli/schema.js.map +1 -0
- package/dist/cli/services.js +330 -0
- package/dist/cli/services.js.map +1 -0
- package/dist/node/definition.d.ts +260 -0
- package/dist/node/definition.d.ts.map +1 -0
- package/dist/node/definition.js +330 -0
- package/dist/node/definition.js.map +1 -0
- package/dist/node/diagnostics.js +93 -0
- package/dist/node/diagnostics.js.map +1 -0
- package/dist/node/index.d.ts +694 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +26 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/mcp-api.d.ts +2 -0
- package/dist/node/mcp-api.js +87 -0
- package/dist/node/mcp-api.js.map +1 -0
- package/dist/node/mcp-types.d.ts +146 -0
- package/dist/node/mcp-types.d.ts.map +1 -0
- package/dist/node/mcp-types.js +100 -0
- package/dist/node/mcp-types.js.map +1 -0
- package/dist/node/oauth-provider.d.ts +24 -0
- package/dist/node/oauth-provider.d.ts.map +1 -0
- package/dist/node/oauth-provider.js +113 -0
- package/dist/node/oauth-provider.js.map +1 -0
- package/dist/node/routes.d.ts +466 -0
- package/dist/node/routes.d.ts.map +1 -0
- package/dist/node/routes.js +743 -0
- package/dist/node/routes.js.map +1 -0
- package/dist/node/schema.d.ts +9 -0
- package/dist/node/schema.d.ts.map +1 -0
- package/dist/node/schema.js +13 -0
- package/dist/node/schema.js.map +1 -0
- package/dist/node/services.d.ts +40 -0
- package/dist/node/services.d.ts.map +1 -0
- package/dist/node/services.js +330 -0
- package/dist/node/services.js.map +1 -0
- package/dist/node/testing/mcp-test-server.d.ts +42 -0
- package/dist/node/testing/mcp-test-server.d.ts.map +1 -0
- package/dist/node/testing/mcp-test-server.js +218 -0
- package/dist/node/testing/mcp-test-server.js.map +1 -0
- package/package.json +130 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.js","names":[],"sources":["../../src/definition.ts"],"sourcesContent":["import { defineFragment } from \"@fragno-dev/core\";\nimport { withDatabase, type HookContext, type HookFn } from \"@fragno-dev/db\";\n\nimport { listMcpTools } from \"./mcp-api\";\nimport type { McpFragmentConfig as BaseMcpFragmentConfig } from \"./mcp-types\";\nimport { mcpSchema } from \"./schema\";\nimport {\n createOAuthCallbackSnapshot,\n createMcpOperationAuth,\n createOAuthStartSnapshot,\n isMcpAuthReady,\n mcpAuthReadyUntil,\n resolveMcpOperationAuth,\n resolveOAuthStartClient,\n withoutOAuthConsent,\n writeOAuthSecretChanges,\n type AuthPersistenceChanges,\n} from \"./services\";\n\nexport interface McpServerConfigurationChangedPayload {\n serverId: string;\n current: {\n tools: unknown[];\n };\n}\n\nexport interface McpServerConfigurationDeletedPayload {\n serverId: string;\n}\n\nexport interface McpServerReadinessChangedPayload {\n serverId: string;\n /** Whether stored auth can authorize operations; the server can still reject it. */\n ready: boolean;\n}\n\n/**\n * A readiness change as delivered. The server is read at delivery rather than stored with the hook,\n * so it is the current configuration, or null after it was deleted.\n */\nexport interface McpServerReadinessChange extends McpServerReadinessChangedPayload {\n server: { name: string | null; authMode: string } | null;\n}\n\nexport interface McpFragmentHooksConfig {\n onServerConfigurationChanged?: (\n payload: McpServerConfigurationChangedPayload,\n context: HookContext,\n ) => Promise<void> | void;\n onServerConfigurationDeleted?: (\n payload: McpServerConfigurationDeletedPayload,\n context: HookContext,\n ) => Promise<void> | void;\n /**\n * Fires when a write changes whether the server can authorize operations, including creation\n * and credentials the server invalidates during an operation, and when an access token without a\n * refresh token expires.\n */\n onServerReadinessChanged?: (\n payload: McpServerReadinessChange,\n context: HookContext,\n ) => Promise<void> | void;\n}\n\nexport type McpFragmentConfig = BaseMcpFragmentConfig & McpFragmentHooksConfig;\n\nexport interface McpInternalRefreshServerConfigurationPayload {\n serverId: string;\n}\n\n/** The token stored when expiry was scheduled; a later write replaces it and reports itself. */\ninterface McpInternalAuthExpiredPayload {\n serverId: string;\n expiresAt: string;\n}\n\nexport type McpHooksMap = {\n internalRefreshServerConfiguration: HookFn<McpInternalRefreshServerConfigurationPayload>;\n internalAuthExpired: HookFn<McpInternalAuthExpiredPayload>;\n onServerConfigurationChanged: HookFn<McpServerConfigurationChangedPayload>;\n onServerConfigurationDeleted: HookFn<McpServerConfigurationDeletedPayload>;\n onServerReadinessChanged: HookFn<McpServerReadinessChangedPayload>;\n};\n\n/** Expiry changes readiness without a write, so a write that starts the countdown schedules it. */\nexport function scheduleMcpAuthExpiry(\n // Hook transactions type their hooks loosely, so only the one trigger is required.\n uow: {\n triggerHook(\n name: \"internalAuthExpired\",\n payload: McpInternalAuthExpiredPayload,\n options: { processAt: Date },\n ): void;\n },\n serverId: string,\n authMode: string,\n after: { payload: string; expiresAt: Date | null },\n) {\n const readyUntil = mcpAuthReadyUntil(authMode, after);\n if (readyUntil && after.expiresAt && isMcpAuthReady(authMode, after)) {\n uow.triggerHook(\n \"internalAuthExpired\",\n { serverId, expiresAt: after.expiresAt.toISOString() },\n { processAt: readyUntil },\n );\n }\n}\n\nexport const mcpFragmentDefinition = defineFragment<McpFragmentConfig>(\"mcp-fragment\")\n .extend(withDatabase(mcpSchema))\n .provideHooks<McpHooksMap>(({ defineHook, config }) => ({\n internalRefreshServerConfiguration: defineHook(async function ({ serverId }) {\n let prepared:\n | {\n authChanges?: AuthPersistenceChanges;\n toolsOperation: Awaited<ReturnType<typeof listMcpTools<AuthPersistenceChanges>>>;\n }\n | undefined;\n\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", serverId)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) => eb(\"serverId\", \"=\", serverId)),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", serverId)),\n ),\n )\n .afterRetrieve(async (_uow, [server, secrets]) => {\n if (!server) {\n return;\n }\n\n const auth = await createMcpOperationAuth({ config, server, secrets });\n const toolsOperation = await listMcpTools({\n endpointUrl: server.endpointUrl,\n auth,\n fetchImplementation: config.fetch,\n });\n prepared = {\n authChanges: toolsOperation.authChanges,\n toolsOperation,\n };\n })\n .mutate(({ forSchema, retrieveResult: [server, secrets, cache] }) => {\n if (!server) {\n return { action: \"missing\" as const };\n }\n if (!prepared) {\n throw new Error(\"MCP refresh operation was not prepared\");\n }\n\n const preparedOperation = prepared;\n const uow = forSchema(mcpSchema);\n const upsertSecret = (kind: string, payload: string, expiresAt: Date | null) => {\n const existing = secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.update(\"secret\", existing.id, (b) =>\n b.set({ payload, expiresAt, updatedAt: b.now() }).check(),\n );\n return;\n }\n uow.create(\"secret\", {\n id: `${serverId}:${kind}`,\n serverId,\n kind,\n payload,\n expiresAt,\n });\n };\n\n if (preparedOperation.authChanges) {\n writeOAuthSecretChanges(preparedOperation.authChanges, {\n upsert: (kind, payload) => {\n upsertSecret(kind, payload, null);\n },\n remove: (kind) => {\n const existing = secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.delete(\"secret\", existing.id);\n }\n },\n });\n }\n if (preparedOperation.authChanges?.authPayload) {\n const after = {\n payload: preparedOperation.authChanges.authPayload,\n expiresAt: preparedOperation.authChanges.authExpiresAt ?? null,\n };\n upsertSecret(\"auth\", after.payload, after.expiresAt);\n const before = secrets.find((secret) => secret.kind === \"auth\");\n const ready = isMcpAuthReady(server.authMode, after);\n if (ready !== isMcpAuthReady(server.authMode, before)) {\n uow.triggerHook(\"onServerReadinessChanged\", { serverId, ready });\n }\n scheduleMcpAuthExpiry(uow, serverId, server.authMode, after);\n }\n\n if (!preparedOperation.toolsOperation.ok) {\n return {\n action: \"error\" as const,\n error:\n preparedOperation.toolsOperation.error instanceof Error\n ? preparedOperation.toolsOperation.error.message\n : String(preparedOperation.toolsOperation.error),\n };\n }\n\n const tools = Array.isArray(preparedOperation.toolsOperation.result.tools)\n ? preparedOperation.toolsOperation.result.tools\n : [];\n const previousTools = Array.isArray(cache?.tools) ? cache.tools : null;\n if (!previousTools || JSON.stringify(previousTools) !== JSON.stringify(tools)) {\n uow.triggerHook(\"onServerConfigurationChanged\", {\n serverId,\n current: { tools },\n });\n }\n\n uow.delete(\"server_connection_cache\", serverId);\n uow.create(\"server_connection_cache\", {\n id: serverId,\n serverId,\n protocolVersion: preparedOperation.toolsOperation.metadata.protocolVersion ?? null,\n serverInfo: preparedOperation.toolsOperation.metadata.serverInfo ?? null,\n capabilities: preparedOperation.toolsOperation.metadata.capabilities ?? null,\n tools,\n });\n\n return { action: \"refreshed\" as const };\n })\n .execute();\n\n if (result.action === \"error\") {\n throw new Error(result.error);\n }\n }),\n onServerConfigurationChanged: defineHook(async function (payload) {\n await config.onServerConfigurationChanged?.(payload, this);\n }),\n onServerConfigurationDeleted: defineHook(async function (payload) {\n await config.onServerConfigurationDeleted?.(payload, this);\n }),\n onServerReadinessChanged: defineHook(async function (payload) {\n const server = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema).findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", payload.serverId)),\n ),\n )\n .transformRetrieve(([server]) => server && { name: server.name, authMode: server.authMode })\n .execute();\n await config.onServerReadinessChanged?.({ ...payload, server }, this);\n }),\n internalAuthExpired: defineHook(async function ({ serverId, expiresAt }) {\n const expired = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(mcpSchema)\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", serverId)),\n )\n .findFirst(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) =>\n eb.and(eb(\"serverId\", \"=\", serverId), eb(\"kind\", \"=\", \"auth\")),\n ),\n ),\n )\n .transformRetrieve(([server, secret]) =>\n // The hook's due time already passed, so an untouched token is the expired one.\n server !== null &&\n secret !== null &&\n secret.expiresAt?.getTime() === Date.parse(expiresAt) &&\n mcpAuthReadyUntil(server.authMode, secret) !== null\n ? { name: server.name, authMode: server.authMode }\n : null,\n )\n .execute();\n if (expired) {\n await config.onServerReadinessChanged?.({ serverId, ready: false, server: expired }, this);\n }\n }),\n }))\n .providesBaseService(({ defineService, config }) =>\n defineService({\n startOAuth: function (input: {\n serverId: string;\n stateId: string;\n redirectUri: string;\n scope?: string;\n clientId?: string;\n clientSecret?: string;\n discardTokens: boolean;\n }) {\n return this.serviceTx(mcpSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", input.serverId)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) => eb(\"serverId\", \"=\", input.serverId)),\n ),\n )\n .transformRetrieve(async ([server, secrets]) => {\n if (!server) {\n return { found: false as const };\n }\n const { authorizationUrl, changes } = await createOAuthStartSnapshot({\n config,\n server,\n secrets,\n stateId: input.stateId,\n redirectUri: input.redirectUri,\n ...resolveOAuthStartClient(secrets, input),\n });\n return {\n found: true as const,\n authorizationUrl: authorizationUrl.toString(),\n serverId: server.id.toString(),\n authMode: server.authMode,\n secrets,\n changes,\n };\n })\n .mutate(({ uow, retrieveResult }) => {\n if (!retrieveResult.found) {\n return { found: false as const };\n }\n\n const upsertSecret = (kind: string, payload: string, expiresAt: Date | null) => {\n const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.update(\"secret\", existing.id, (b) =>\n b.set({ payload, expiresAt, updatedAt: b.now() }).check(),\n );\n return;\n }\n uow.create(\"secret\", {\n id: `${retrieveResult.serverId}:${kind}`,\n serverId: retrieveResult.serverId,\n kind,\n payload,\n expiresAt,\n });\n };\n\n writeOAuthSecretChanges(retrieveResult.changes, {\n upsert: (kind, payload) => {\n upsertSecret(kind, payload, null);\n },\n remove: (kind) => {\n const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.delete(\"secret\", existing.id);\n }\n },\n });\n const authSecret = retrieveResult.secrets.find((secret) => secret.kind === \"auth\");\n if (input.discardTokens && authSecret) {\n // Keeps the client configuration; only consent evidence is discarded.\n const payload = withoutOAuthConsent(authSecret.payload);\n uow.update(\"secret\", authSecret.id, (b) =>\n b.set({ payload, expiresAt: null, updatedAt: b.now() }).check(),\n );\n const { authMode } = retrieveResult;\n const ready = isMcpAuthReady(authMode, { payload, expiresAt: null });\n if (ready !== isMcpAuthReady(authMode, authSecret)) {\n uow.triggerHook(\"onServerReadinessChanged\", {\n serverId: retrieveResult.serverId,\n ready,\n });\n }\n }\n if (retrieveResult.changes.oauthState) {\n uow.create(\"oauthState\", {\n id: retrieveResult.changes.oauthState.id,\n serverId: retrieveResult.serverId,\n // The link carries only the PKCE challenge, never the verifier.\n authorizationUrl: retrieveResult.authorizationUrl,\n codeVerifier: retrieveResult.changes.oauthState.codeVerifier,\n redirectUri: retrieveResult.changes.oauthState.redirectUri,\n scope: retrieveResult.changes.oauthState.scope ?? null,\n expiresAt: retrieveResult.changes.oauthState.expiresAt,\n consumedAt: null,\n });\n }\n\n return { found: true as const };\n })\n .transform(({ retrieveResult }) =>\n retrieveResult.found\n ? {\n found: true as const,\n authorizationUrl: retrieveResult.authorizationUrl,\n }\n : { found: false as const },\n )\n .build();\n },\n\n completeOAuthCallback: function (input: {\n stateId: string;\n code: string;\n iss: string | undefined;\n }) {\n const serverId = input.stateId.split(\":\")[0] ?? \"\";\n return this.serviceTx(mcpSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"oauthState\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", input.stateId)),\n )\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", serverId)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) => eb(\"serverId\", \"=\", serverId)),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", serverId)),\n ),\n )\n .transformRetrieve(async ([state, server, secrets, cache]) => {\n if (!state || state.consumedAt || new Date(state.expiresAt).getTime() < Date.now()) {\n return { found: false as const, reason: \"invalid_state\" as const };\n }\n if (!server) {\n return { found: false as const, reason: \"server_not_found\" as const };\n }\n const changes = await createOAuthCallbackSnapshot({\n config,\n stateId: input.stateId,\n code: input.code,\n iss: input.iss,\n state,\n server,\n secrets,\n });\n return { found: true as const, server, secrets, cache, changes };\n })\n .mutate(({ uow, retrieveResult }) => {\n if (!retrieveResult.found) {\n return { found: false as const, reason: retrieveResult.reason };\n }\n\n const serverId = retrieveResult.server.id.toString();\n const upsertSecret = (kind: string, payload: string, expiresAt: Date | null) => {\n const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.update(\"secret\", existing.id, (b) =>\n b.set({ payload, expiresAt, updatedAt: b.now() }).check(),\n );\n return;\n }\n uow.create(\"secret\", {\n id: `${serverId}:${kind}`,\n serverId,\n kind,\n payload,\n expiresAt,\n });\n };\n\n writeOAuthSecretChanges(retrieveResult.changes, {\n upsert: (kind, payload) => {\n upsertSecret(kind, payload, null);\n },\n remove: (kind) => {\n const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);\n if (existing) {\n uow.delete(\"secret\", existing.id);\n }\n },\n });\n if (retrieveResult.changes.authPayload) {\n const after = {\n payload: retrieveResult.changes.authPayload,\n expiresAt: retrieveResult.changes.authExpiresAt ?? null,\n };\n upsertSecret(\"auth\", after.payload, after.expiresAt);\n uow.update(\"server_configuration\", retrieveResult.server.id, (b) =>\n b.set({ authMode: \"oauth\", updatedAt: b.now() }).check(),\n );\n const before = retrieveResult.secrets.find((secret) => secret.kind === \"auth\");\n const ready = isMcpAuthReady(\"oauth\", after);\n if (ready !== isMcpAuthReady(retrieveResult.server.authMode, before)) {\n uow.triggerHook(\"onServerReadinessChanged\", { serverId, ready });\n }\n scheduleMcpAuthExpiry(uow, serverId, \"oauth\", after);\n if (retrieveResult.cache) {\n uow.delete(\"server_connection_cache\", retrieveResult.cache.id);\n }\n uow.triggerHook(\"internalRefreshServerConfiguration\", { serverId });\n }\n if (retrieveResult.changes.consumeStateId) {\n uow.update(\"oauthState\", input.stateId, (b) => b.set({ consumedAt: b.now() }));\n }\n\n return { found: true as const };\n })\n .transform(({ retrieveResult }) =>\n retrieveResult.found\n ? { found: true as const }\n : { found: false as const, reason: retrieveResult.reason },\n )\n .build();\n },\n\n prepareMcpOperation: function (input: { serverId: string }) {\n return this.serviceTx(mcpSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"server_configuration\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", input.serverId)),\n )\n .find(\"secret\", (b) =>\n b.whereIndex(\"idx_secret_server_kind\", (eb) => eb(\"serverId\", \"=\", input.serverId)),\n )\n .findFirst(\"server_connection_cache\", (b) =>\n b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", input.serverId)),\n ),\n )\n .transformRetrieve(async ([server, secrets, cache]) => {\n if (!server) {\n return { found: false as const };\n }\n const resolved = await resolveMcpOperationAuth({ config, server, secrets });\n return {\n found: true as const,\n serverId: server.id.toString(),\n endpointUrl: server.endpointUrl,\n token: resolved.token,\n secrets,\n cache,\n authChanges: resolved.authChanges,\n };\n })\n .transform(({ retrieveResult }) =>\n retrieveResult.found\n ? {\n found: true as const,\n endpointUrl: retrieveResult.endpointUrl,\n token: retrieveResult.token,\n secrets: retrieveResult.secrets,\n cache: retrieveResult.cache,\n authChanges: retrieveResult.authChanges,\n serverId: retrieveResult.serverId,\n }\n : { found: false as const },\n )\n .build();\n },\n }),\n )\n .build();\n"],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { parseSecretPayload } from "./mcp-api.js";
|
|
2
|
+
import { mcpToolSchema } from "./mcp-types.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
//#region src/diagnostics.ts
|
|
5
|
+
const serverConnectionCacheOutputSchema = z.object({
|
|
6
|
+
protocolVersion: z.string().nullable().optional(),
|
|
7
|
+
serverInfo: z.unknown().nullable().optional(),
|
|
8
|
+
capabilities: z.unknown().nullable().optional(),
|
|
9
|
+
tools: z.array(mcpToolSchema).nullable().optional(),
|
|
10
|
+
updatedAt: z.union([z.string(), z.date()]).optional()
|
|
11
|
+
});
|
|
12
|
+
const serverOutputSchema = z.object({
|
|
13
|
+
slug: z.string(),
|
|
14
|
+
name: z.string().nullable().optional(),
|
|
15
|
+
endpointUrl: z.string(),
|
|
16
|
+
authMode: z.string(),
|
|
17
|
+
cache: serverConnectionCacheOutputSchema.nullable().optional()
|
|
18
|
+
});
|
|
19
|
+
const refreshOutputSchema = z.object({
|
|
20
|
+
ok: z.boolean(),
|
|
21
|
+
tools: z.array(mcpToolSchema),
|
|
22
|
+
stage: z.enum(["auth", "list_tools"]).nullable(),
|
|
23
|
+
checkedAt: z.string(),
|
|
24
|
+
server: serverOutputSchema.omit({ cache: true }),
|
|
25
|
+
auth: z.object({
|
|
26
|
+
authenticated: z.boolean(),
|
|
27
|
+
mode: z.string(),
|
|
28
|
+
tokenPresent: z.boolean(),
|
|
29
|
+
expiresAt: z.union([z.string(), z.date()]).nullable(),
|
|
30
|
+
expired: z.boolean().nullable(),
|
|
31
|
+
scopes: z.object({
|
|
32
|
+
requested: z.array(z.string()).nullable(),
|
|
33
|
+
granted: z.array(z.string()).nullable(),
|
|
34
|
+
missing: z.array(z.string()).nullable(),
|
|
35
|
+
raw: z.string().nullable()
|
|
36
|
+
})
|
|
37
|
+
}),
|
|
38
|
+
live: z.object({
|
|
39
|
+
reachable: z.boolean(),
|
|
40
|
+
listToolsOk: z.boolean(),
|
|
41
|
+
toolCount: z.number().nullable(),
|
|
42
|
+
protocolVersion: z.string().nullable(),
|
|
43
|
+
serverInfo: z.unknown().nullable(),
|
|
44
|
+
capabilities: z.unknown().nullable()
|
|
45
|
+
}),
|
|
46
|
+
cache: z.object({
|
|
47
|
+
presentBeforeCheck: z.boolean(),
|
|
48
|
+
previousToolCount: z.number().nullable(),
|
|
49
|
+
updatedToolCount: z.number().nullable()
|
|
50
|
+
}),
|
|
51
|
+
error: z.object({
|
|
52
|
+
code: z.string(),
|
|
53
|
+
message: z.string()
|
|
54
|
+
}).nullable()
|
|
55
|
+
});
|
|
56
|
+
const splitScope = (scope) => {
|
|
57
|
+
const scopes = scope?.split(/\s+/).filter(Boolean) ?? [];
|
|
58
|
+
return scopes.length > 0 ? scopes : null;
|
|
59
|
+
};
|
|
60
|
+
const newestOAuthScope = (states) => {
|
|
61
|
+
const [state] = states.toSorted((left, right) => new Date(right.expiresAt).getTime() - new Date(left.expiresAt).getTime());
|
|
62
|
+
return splitScope(state?.scope);
|
|
63
|
+
};
|
|
64
|
+
const buildAuthDiagnostics = ({ mode, secrets, oauthStates, authChanges }) => {
|
|
65
|
+
const authSecret = secrets.find((secret) => secret.kind === "auth");
|
|
66
|
+
const authPayload = authChanges?.authPayload ?? authSecret?.payload;
|
|
67
|
+
const authExpiresAt = authChanges?.authExpiresAt ?? authSecret?.expiresAt ?? null;
|
|
68
|
+
const parsedAuth = authPayload ? parseSecretPayload(authPayload) : void 0;
|
|
69
|
+
const granted = splitScope(parsedAuth?.type === "oauth" || parsedAuth?.type === "client_credentials" ? parsedAuth.tokens?.scope : void 0);
|
|
70
|
+
const requested = parsedAuth?.type === "client_credentials" ? parsedAuth.scopes ?? null : mode === "oauth" ? newestOAuthScope(oauthStates) : null;
|
|
71
|
+
const grantedScopes = granted ? new Set(granted) : null;
|
|
72
|
+
const missing = requested && grantedScopes ? requested.filter((scope) => !grantedScopes.has(scope)) : null;
|
|
73
|
+
const tokenPresent = parsedAuth?.type === "bearer" ? Boolean(parsedAuth.token) : Boolean(parsedAuth?.tokens?.access_token);
|
|
74
|
+
const expired = authExpiresAt ? new Date(authExpiresAt).getTime() <= Date.now() : null;
|
|
75
|
+
return {
|
|
76
|
+
authenticated: mode === "none" || tokenPresent,
|
|
77
|
+
mode,
|
|
78
|
+
tokenPresent,
|
|
79
|
+
expiresAt: authExpiresAt,
|
|
80
|
+
expired,
|
|
81
|
+
scopes: {
|
|
82
|
+
requested,
|
|
83
|
+
granted,
|
|
84
|
+
missing,
|
|
85
|
+
raw: parsedAuth?.type === "oauth" || parsedAuth?.type === "client_credentials" ? parsedAuth.tokens?.scope ?? null : null
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
90
|
+
//#endregion
|
|
91
|
+
export { buildAuthDiagnostics, errorMessage, refreshOutputSchema };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","names":[],"sources":["../../src/diagnostics.ts"],"sourcesContent":["import { z } from \"zod\";\n\nimport { parseSecretPayload } from \"./mcp-api\";\nimport { mcpToolSchema } from \"./mcp-types\";\nimport type { AuthPersistenceChanges } from \"./services\";\n\nconst serverConnectionCacheOutputSchema = z.object({\n protocolVersion: z.string().nullable().optional(),\n serverInfo: z.unknown().nullable().optional(),\n capabilities: z.unknown().nullable().optional(),\n tools: z.array(mcpToolSchema).nullable().optional(),\n updatedAt: z.union([z.string(), z.date()]).optional(),\n});\n\nconst serverOutputSchema = z.object({\n slug: z.string(),\n name: z.string().nullable().optional(),\n endpointUrl: z.string(),\n authMode: z.string(),\n cache: serverConnectionCacheOutputSchema.nullable().optional(),\n});\n\nexport const refreshOutputSchema = z.object({\n ok: z.boolean(),\n tools: z.array(mcpToolSchema),\n stage: z.enum([\"auth\", \"list_tools\"]).nullable(),\n checkedAt: z.string(),\n server: serverOutputSchema.omit({ cache: true }),\n auth: z.object({\n authenticated: z.boolean(),\n mode: z.string(),\n tokenPresent: z.boolean(),\n expiresAt: z.union([z.string(), z.date()]).nullable(),\n expired: z.boolean().nullable(),\n scopes: z.object({\n requested: z.array(z.string()).nullable(),\n granted: z.array(z.string()).nullable(),\n missing: z.array(z.string()).nullable(),\n raw: z.string().nullable(),\n }),\n }),\n live: z.object({\n reachable: z.boolean(),\n listToolsOk: z.boolean(),\n toolCount: z.number().nullable(),\n protocolVersion: z.string().nullable(),\n serverInfo: z.unknown().nullable(),\n capabilities: z.unknown().nullable(),\n }),\n cache: z.object({\n presentBeforeCheck: z.boolean(),\n previousToolCount: z.number().nullable(),\n updatedToolCount: z.number().nullable(),\n }),\n error: z.object({ code: z.string(), message: z.string() }).nullable(),\n});\n\nexport type SecretForDiagnostics = {\n id: { toString(): string } | string;\n kind: string;\n payload: string;\n expiresAt?: Date | string | null;\n};\n\nexport type OAuthStateForDiagnostics = {\n scope?: string | null;\n expiresAt: Date | string;\n};\n\ntype AuthPayloadForDiagnostics =\n | { type: \"bearer\"; token?: string }\n | { type: \"oauth\"; tokens?: { access_token?: string; scope?: string } }\n | {\n type: \"client_credentials\";\n scopes?: string[];\n tokens?: { access_token?: string; scope?: string };\n };\n\nconst splitScope = (scope: string | null | undefined) => {\n const scopes = scope?.split(/\\s+/).filter(Boolean) ?? [];\n return scopes.length > 0 ? scopes : null;\n};\n\nconst newestOAuthScope = (states: OAuthStateForDiagnostics[]) => {\n const [state] = states.toSorted(\n (left, right) => new Date(right.expiresAt).getTime() - new Date(left.expiresAt).getTime(),\n );\n return splitScope(state?.scope);\n};\n\nexport const buildAuthDiagnostics = ({\n mode,\n secrets,\n oauthStates,\n authChanges,\n}: {\n mode: string;\n secrets: SecretForDiagnostics[];\n oauthStates: OAuthStateForDiagnostics[];\n authChanges?: AuthPersistenceChanges;\n}) => {\n const authSecret = secrets.find((secret) => secret.kind === \"auth\");\n const authPayload = authChanges?.authPayload ?? authSecret?.payload;\n const authExpiresAt = authChanges?.authExpiresAt ?? authSecret?.expiresAt ?? null;\n const parsedAuth = authPayload\n ? parseSecretPayload<AuthPayloadForDiagnostics>(authPayload)\n : undefined;\n const granted = splitScope(\n parsedAuth?.type === \"oauth\" || parsedAuth?.type === \"client_credentials\"\n ? parsedAuth.tokens?.scope\n : undefined,\n );\n const requested =\n parsedAuth?.type === \"client_credentials\"\n ? (parsedAuth.scopes ?? null)\n : mode === \"oauth\"\n ? newestOAuthScope(oauthStates)\n : null;\n const grantedScopes = granted ? new Set(granted) : null;\n const missing =\n requested && grantedScopes ? requested.filter((scope) => !grantedScopes.has(scope)) : null;\n const tokenPresent =\n parsedAuth?.type === \"bearer\"\n ? Boolean(parsedAuth.token)\n : Boolean(parsedAuth?.tokens?.access_token);\n const expired = authExpiresAt ? new Date(authExpiresAt).getTime() <= Date.now() : null;\n\n return {\n authenticated: mode === \"none\" || tokenPresent,\n mode,\n tokenPresent,\n expiresAt: authExpiresAt,\n expired,\n scopes: {\n requested,\n granted,\n missing,\n raw:\n parsedAuth?.type === \"oauth\" || parsedAuth?.type === \"client_credentials\"\n ? (parsedAuth.tokens?.scope ?? null)\n : null,\n },\n };\n};\n\nexport const errorMessage = (error: unknown) =>\n error instanceof Error ? error.message : String(error);\n"],"mappings":"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"}
|