@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.
Files changed (90) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +312 -2
  3. package/bin/run.js +7 -0
  4. package/dist/browser/client/react.d.ts +253 -0
  5. package/dist/browser/client/react.d.ts.map +1 -0
  6. package/dist/browser/client/react.js +194 -0
  7. package/dist/browser/client/react.js.map +1 -0
  8. package/dist/browser/client/solid.d.ts +256 -0
  9. package/dist/browser/client/solid.d.ts.map +1 -0
  10. package/dist/browser/client/solid.js +129 -0
  11. package/dist/browser/client/solid.js.map +1 -0
  12. package/dist/browser/client/svelte.d.ts +256 -0
  13. package/dist/browser/client/svelte.d.ts.map +1 -0
  14. package/dist/browser/client/svelte.js +131 -0
  15. package/dist/browser/client/svelte.js.map +1 -0
  16. package/dist/browser/client/vanilla.d.ts +283 -0
  17. package/dist/browser/client/vanilla.d.ts.map +1 -0
  18. package/dist/browser/client/vanilla.js +159 -0
  19. package/dist/browser/client/vanilla.js.map +1 -0
  20. package/dist/browser/client/vue.d.ts +256 -0
  21. package/dist/browser/client/vue.d.ts.map +1 -0
  22. package/dist/browser/client/vue.js +127 -0
  23. package/dist/browser/client/vue.js.map +1 -0
  24. package/dist/browser/client-BCzNDSlW.d.ts +711 -0
  25. package/dist/browser/client-BCzNDSlW.d.ts.map +1 -0
  26. package/dist/browser/index.d.ts +813 -0
  27. package/dist/browser/index.d.ts.map +1 -0
  28. package/dist/browser/index.js +1 -0
  29. package/dist/browser/src-B6dHZXqB.js +2303 -0
  30. package/dist/browser/src-B6dHZXqB.js.map +1 -0
  31. package/dist/cli/cli.d.ts +6 -0
  32. package/dist/cli/cli.d.ts.map +1 -0
  33. package/dist/cli/cli.js +227 -0
  34. package/dist/cli/cli.js.map +1 -0
  35. package/dist/cli/definition.js +330 -0
  36. package/dist/cli/definition.js.map +1 -0
  37. package/dist/cli/diagnostics.js +93 -0
  38. package/dist/cli/diagnostics.js.map +1 -0
  39. package/dist/cli/index.js +13 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/mcp-api.js +87 -0
  42. package/dist/cli/mcp-api.js.map +1 -0
  43. package/dist/cli/mcp-types.js +100 -0
  44. package/dist/cli/mcp-types.js.map +1 -0
  45. package/dist/cli/oauth-provider.js +113 -0
  46. package/dist/cli/oauth-provider.js.map +1 -0
  47. package/dist/cli/routes.js +743 -0
  48. package/dist/cli/routes.js.map +1 -0
  49. package/dist/cli/schema.js +13 -0
  50. package/dist/cli/schema.js.map +1 -0
  51. package/dist/cli/services.js +330 -0
  52. package/dist/cli/services.js.map +1 -0
  53. package/dist/node/definition.d.ts +260 -0
  54. package/dist/node/definition.d.ts.map +1 -0
  55. package/dist/node/definition.js +330 -0
  56. package/dist/node/definition.js.map +1 -0
  57. package/dist/node/diagnostics.js +93 -0
  58. package/dist/node/diagnostics.js.map +1 -0
  59. package/dist/node/index.d.ts +694 -0
  60. package/dist/node/index.d.ts.map +1 -0
  61. package/dist/node/index.js +26 -0
  62. package/dist/node/index.js.map +1 -0
  63. package/dist/node/mcp-api.d.ts +2 -0
  64. package/dist/node/mcp-api.js +87 -0
  65. package/dist/node/mcp-api.js.map +1 -0
  66. package/dist/node/mcp-types.d.ts +146 -0
  67. package/dist/node/mcp-types.d.ts.map +1 -0
  68. package/dist/node/mcp-types.js +100 -0
  69. package/dist/node/mcp-types.js.map +1 -0
  70. package/dist/node/oauth-provider.d.ts +24 -0
  71. package/dist/node/oauth-provider.d.ts.map +1 -0
  72. package/dist/node/oauth-provider.js +113 -0
  73. package/dist/node/oauth-provider.js.map +1 -0
  74. package/dist/node/routes.d.ts +466 -0
  75. package/dist/node/routes.d.ts.map +1 -0
  76. package/dist/node/routes.js +743 -0
  77. package/dist/node/routes.js.map +1 -0
  78. package/dist/node/schema.d.ts +9 -0
  79. package/dist/node/schema.d.ts.map +1 -0
  80. package/dist/node/schema.js +13 -0
  81. package/dist/node/schema.js.map +1 -0
  82. package/dist/node/services.d.ts +40 -0
  83. package/dist/node/services.d.ts.map +1 -0
  84. package/dist/node/services.js +330 -0
  85. package/dist/node/services.js.map +1 -0
  86. package/dist/node/testing/mcp-test-server.d.ts +42 -0
  87. package/dist/node/testing/mcp-test-server.d.ts.map +1 -0
  88. package/dist/node/testing/mcp-test-server.js +218 -0
  89. package/dist/node/testing/mcp-test-server.js.map +1 -0
  90. package/package.json +130 -3
@@ -0,0 +1,260 @@
1
+ import { McpFragmentConfig as McpFragmentConfig$1 } from "./mcp-types.js";
2
+ import { AuthPersistenceChanges } from "./services.js";
3
+ import { HookContext, HookFn } from "@fragno-dev/db";
4
+ //#region src/definition.d.ts
5
+ export interface McpServerConfigurationChangedPayload {
6
+ serverId: string;
7
+ current: {
8
+ tools: unknown[];
9
+ };
10
+ }
11
+ export interface McpServerConfigurationDeletedPayload {
12
+ serverId: string;
13
+ }
14
+ export interface McpServerReadinessChangedPayload {
15
+ serverId: string;
16
+ /** Whether stored auth can authorize operations; the server can still reject it. */
17
+ ready: boolean;
18
+ }
19
+ /**
20
+ * A readiness change as delivered. The server is read at delivery rather than stored with the hook,
21
+ * so it is the current configuration, or null after it was deleted.
22
+ */
23
+ export interface McpServerReadinessChange extends McpServerReadinessChangedPayload {
24
+ server: {
25
+ name: string | null;
26
+ authMode: string;
27
+ } | null;
28
+ }
29
+ export interface McpFragmentHooksConfig {
30
+ onServerConfigurationChanged?: (payload: McpServerConfigurationChangedPayload, context: HookContext) => Promise<void> | void;
31
+ onServerConfigurationDeleted?: (payload: McpServerConfigurationDeletedPayload, context: HookContext) => Promise<void> | void;
32
+ /**
33
+ * Fires when a write changes whether the server can authorize operations, including creation
34
+ * and credentials the server invalidates during an operation, and when an access token without a
35
+ * refresh token expires.
36
+ */
37
+ onServerReadinessChanged?: (payload: McpServerReadinessChange, context: HookContext) => Promise<void> | void;
38
+ }
39
+ export type McpFragmentConfig = McpFragmentConfig$1 & McpFragmentHooksConfig;
40
+ export interface McpInternalRefreshServerConfigurationPayload {
41
+ serverId: string;
42
+ }
43
+ /** The token stored when expiry was scheduled; a later write replaces it and reports itself. */
44
+ interface McpInternalAuthExpiredPayload {
45
+ serverId: string;
46
+ expiresAt: string;
47
+ }
48
+ export type McpHooksMap = {
49
+ internalRefreshServerConfiguration: HookFn<McpInternalRefreshServerConfigurationPayload>;
50
+ internalAuthExpired: HookFn<McpInternalAuthExpiredPayload>;
51
+ onServerConfigurationChanged: HookFn<McpServerConfigurationChangedPayload>;
52
+ onServerConfigurationDeleted: HookFn<McpServerConfigurationDeletedPayload>;
53
+ onServerReadinessChanged: HookFn<McpServerReadinessChangedPayload>;
54
+ };
55
+ /** Expiry changes readiness without a write, so a write that starts the countdown schedules it. */
56
+ export declare function scheduleMcpAuthExpiry(uow: {
57
+ triggerHook(name: "internalAuthExpired", payload: McpInternalAuthExpiredPayload, options: {
58
+ processAt: Date;
59
+ }): void;
60
+ }, serverId: string, authMode: string, after: {
61
+ payload: string;
62
+ expiresAt: Date | null;
63
+ }): void;
64
+ export declare const mcpFragmentDefinition: import("@fragno-dev/core").FragmentDefinition<McpFragmentConfig, import("@fragno-dev/db").FragnoPublicConfigWithDatabase, import("@fragno-dev/db").ImplicitDatabaseDependencies<import("@fragno-dev/db/schema").Schema<{
65
+ server_configuration: import("@fragno-dev/db/schema").Table<Record<"id", import("@fragno-dev/db/schema").IdColumn<"varchar(128)", string | import("@fragno-dev/db/schema").FragnoId | null, import("@fragno-dev/db/schema").FragnoId>> & Record<"name", import("@fragno-dev/db/schema").Column<"string", string | null, string | null>> & Record<"endpointUrl", import("@fragno-dev/db/schema").Column<"string", string, string>> & Record<"authMode", import("@fragno-dev/db/schema").Column<"string", string, string>> & Record<"createdAt", import("@fragno-dev/db/schema").Column<"timestamp", (Date | import("@fragno-dev/db").DbNow) | null, Date>> & Record<"updatedAt", import("@fragno-dev/db/schema").Column<"timestamp", (Date | import("@fragno-dev/db").DbNow) | null, Date>>, {}>;
66
+ secret: import("@fragno-dev/db/schema").Table<Record<"id", import("@fragno-dev/db/schema").IdColumn<"varchar(128)", string | import("@fragno-dev/db/schema").FragnoId | null, import("@fragno-dev/db/schema").FragnoId>> & Record<"serverId", import("@fragno-dev/db/schema").Column<"bigint", string | bigint | import("@fragno-dev/db/schema").FragnoId | import("@fragno-dev/db/schema").FragnoReference, import("@fragno-dev/db/schema").FragnoReference>> & Record<"kind", import("@fragno-dev/db/schema").Column<"string", string, string>> & Record<"payload", import("@fragno-dev/db/schema").Column<"text", string, string>> & Record<"expiresAt", import("@fragno-dev/db/schema").Column<"timestamp", (Date | import("@fragno-dev/db").DbNow) | null, Date | null>> & Record<"updatedAt", import("@fragno-dev/db/schema").Column<"timestamp", (Date | import("@fragno-dev/db").DbNow) | null, Date>>, Record<"idx_secret_server_kind", import("@fragno-dev/db/schema").Index<readonly [import("@fragno-dev/db/schema").Column<"bigint", string | bigint | import("@fragno-dev/db/schema").FragnoId | import("@fragno-dev/db/schema").FragnoReference, import("@fragno-dev/db/schema").FragnoReference>, import("@fragno-dev/db/schema").Column<"string", string, string>] & import("@fragno-dev/db/schema").AnyColumn[], readonly ["serverId", "kind"]>>>;
67
+ oauthState: import("@fragno-dev/db/schema").Table<Record<"id", import("@fragno-dev/db/schema").IdColumn<"varchar(128)", string | import("@fragno-dev/db/schema").FragnoId | null, import("@fragno-dev/db/schema").FragnoId>> & Record<"serverId", import("@fragno-dev/db/schema").Column<"bigint", string | bigint | import("@fragno-dev/db/schema").FragnoId | import("@fragno-dev/db/schema").FragnoReference, import("@fragno-dev/db/schema").FragnoReference>> & Record<"codeVerifier", import("@fragno-dev/db/schema").Column<"text", string, string>> & Record<"redirectUri", import("@fragno-dev/db/schema").Column<"string", string, string>> & Record<"scope", import("@fragno-dev/db/schema").Column<"string", string | null, string | null>> & Record<"expiresAt", import("@fragno-dev/db/schema").Column<"timestamp", Date | import("@fragno-dev/db").DbNow, Date>> & Record<"consumedAt", import("@fragno-dev/db/schema").Column<"timestamp", (Date | import("@fragno-dev/db").DbNow) | null, Date | null>> & Record<"authorizationUrl", import("@fragno-dev/db/schema").Column<"text", string | null, string | null>>, Record<"idx_oauth_state_server", import("@fragno-dev/db/schema").Index<readonly [import("@fragno-dev/db/schema").Column<"bigint", string | bigint | import("@fragno-dev/db/schema").FragnoId | import("@fragno-dev/db/schema").FragnoReference, import("@fragno-dev/db/schema").FragnoReference>] & import("@fragno-dev/db/schema").AnyColumn[], readonly ["serverId"]>> & Record<"idx_oauth_state_pending", import("@fragno-dev/db/schema").Index<readonly [import("@fragno-dev/db/schema").Column<"bigint", string | bigint | import("@fragno-dev/db/schema").FragnoId | import("@fragno-dev/db/schema").FragnoReference, import("@fragno-dev/db/schema").FragnoReference>, import("@fragno-dev/db/schema").Column<"timestamp", (Date | import("@fragno-dev/db").DbNow) | null, Date | null>, import("@fragno-dev/db/schema").Column<"timestamp", Date | import("@fragno-dev/db").DbNow, Date>] & import("@fragno-dev/db/schema").AnyColumn[], readonly ["serverId", "consumedAt", "expiresAt"]>>>;
68
+ server_connection_cache: import("@fragno-dev/db/schema").Table<Record<"id", import("@fragno-dev/db/schema").IdColumn<"varchar(128)", string | import("@fragno-dev/db/schema").FragnoId | null, import("@fragno-dev/db/schema").FragnoId>> & Record<"serverId", import("@fragno-dev/db/schema").Column<"bigint", string | bigint | import("@fragno-dev/db/schema").FragnoId | import("@fragno-dev/db/schema").FragnoReference, import("@fragno-dev/db/schema").FragnoReference>> & Record<"protocolVersion", import("@fragno-dev/db/schema").Column<"string", string | null, string | null>> & Record<"serverInfo", import("@fragno-dev/db/schema").Column<"json", unknown, unknown>> & Record<"capabilities", import("@fragno-dev/db/schema").Column<"json", unknown, unknown>> & Record<"tools", import("@fragno-dev/db/schema").Column<"json", unknown, unknown>> & Record<"updatedAt", import("@fragno-dev/db/schema").Column<"timestamp", (Date | import("@fragno-dev/db").DbNow) | null, Date>>, Record<"idx_server_connection_cache_server", import("@fragno-dev/db/schema").Index<readonly [import("@fragno-dev/db/schema").Column<"bigint", string | bigint | import("@fragno-dev/db/schema").FragnoId | import("@fragno-dev/db/schema").FragnoReference, import("@fragno-dev/db/schema").FragnoReference>] & import("@fragno-dev/db/schema").AnyColumn[], readonly ["serverId"]>>>;
69
+ }>>, {
70
+ startOAuth: (input: {
71
+ serverId: string;
72
+ stateId: string;
73
+ redirectUri: string;
74
+ scope?: string;
75
+ clientId?: string;
76
+ clientSecret?: string;
77
+ discardTokens: boolean;
78
+ }) => import("@fragno-dev/db").TxResult<{
79
+ found: true;
80
+ authorizationUrl: string;
81
+ } | {
82
+ found: false;
83
+ authorizationUrl?: undefined;
84
+ }, {
85
+ found: false;
86
+ authorizationUrl?: undefined;
87
+ serverId?: undefined;
88
+ authMode?: undefined;
89
+ secrets?: undefined;
90
+ changes?: undefined;
91
+ } | {
92
+ found: true;
93
+ authorizationUrl: string;
94
+ serverId: string;
95
+ authMode: string;
96
+ secrets: {
97
+ id: import("@fragno-dev/db/schema").FragnoId;
98
+ serverId: import("@fragno-dev/db/schema").FragnoReference;
99
+ kind: string;
100
+ payload: string;
101
+ expiresAt: Date | null;
102
+ updatedAt: Date;
103
+ }[];
104
+ changes: {
105
+ clientChange: {
106
+ action: "keep";
107
+ } | {
108
+ action: "save";
109
+ payload: string;
110
+ } | {
111
+ action: "remove";
112
+ };
113
+ discoveryChange: {
114
+ action: "keep";
115
+ } | {
116
+ action: "save";
117
+ payload: string;
118
+ } | {
119
+ action: "remove";
120
+ };
121
+ authorizationUrl?: URL;
122
+ clientInformation?: import("@modelcontextprotocol/server").OAuthClientInformationMixed;
123
+ tokens?: import("@modelcontextprotocol/server").OAuthTokens;
124
+ discoveryState?: import("@modelcontextprotocol/client").OAuthDiscoveryState;
125
+ oauthState?: {
126
+ id: string;
127
+ codeVerifier: string;
128
+ redirectUri: string;
129
+ scope?: string;
130
+ expiresAt: Date;
131
+ };
132
+ consumeStateId?: string;
133
+ tokensInvalidated?: boolean;
134
+ clientInvalidated?: boolean;
135
+ discoveryInvalidated?: boolean;
136
+ };
137
+ }>;
138
+ completeOAuthCallback: (input: {
139
+ stateId: string;
140
+ code: string;
141
+ iss: string | undefined;
142
+ }) => import("@fragno-dev/db").TxResult<{
143
+ found: true;
144
+ reason?: undefined;
145
+ } | {
146
+ found: false;
147
+ reason: "invalid_state" | "server_not_found";
148
+ }, {
149
+ found: false;
150
+ reason: "invalid_state";
151
+ server?: undefined;
152
+ secrets?: undefined;
153
+ cache?: undefined;
154
+ changes?: undefined;
155
+ } | {
156
+ found: false;
157
+ reason: "server_not_found";
158
+ server?: undefined;
159
+ secrets?: undefined;
160
+ cache?: undefined;
161
+ changes?: undefined;
162
+ } | {
163
+ found: true;
164
+ server: {
165
+ id: import("@fragno-dev/db/schema").FragnoId;
166
+ name: string | null;
167
+ endpointUrl: string;
168
+ authMode: string;
169
+ createdAt: Date;
170
+ updatedAt: Date;
171
+ };
172
+ secrets: {
173
+ id: import("@fragno-dev/db/schema").FragnoId;
174
+ serverId: import("@fragno-dev/db/schema").FragnoReference;
175
+ kind: string;
176
+ payload: string;
177
+ expiresAt: Date | null;
178
+ updatedAt: Date;
179
+ }[];
180
+ cache: {
181
+ id: import("@fragno-dev/db/schema").FragnoId;
182
+ serverId: import("@fragno-dev/db/schema").FragnoReference;
183
+ protocolVersion: string | null;
184
+ serverInfo: unknown;
185
+ capabilities: unknown;
186
+ tools: unknown;
187
+ updatedAt: Date;
188
+ } | null;
189
+ changes: AuthPersistenceChanges;
190
+ reason?: undefined;
191
+ }>;
192
+ prepareMcpOperation: (input: {
193
+ serverId: string;
194
+ }) => import("@fragno-dev/db").TxResult<{
195
+ found: true;
196
+ endpointUrl: string;
197
+ token: string | undefined;
198
+ secrets: {
199
+ id: import("@fragno-dev/db/schema").FragnoId;
200
+ serverId: import("@fragno-dev/db/schema").FragnoReference;
201
+ kind: string;
202
+ payload: string;
203
+ expiresAt: Date | null;
204
+ updatedAt: Date;
205
+ }[];
206
+ cache: {
207
+ id: import("@fragno-dev/db/schema").FragnoId;
208
+ serverId: import("@fragno-dev/db/schema").FragnoReference;
209
+ protocolVersion: string | null;
210
+ serverInfo: unknown;
211
+ capabilities: unknown;
212
+ tools: unknown;
213
+ updatedAt: Date;
214
+ } | null;
215
+ authChanges: AuthPersistenceChanges | undefined;
216
+ serverId: string;
217
+ } | {
218
+ found: false;
219
+ endpointUrl?: undefined;
220
+ token?: undefined;
221
+ secrets?: undefined;
222
+ cache?: undefined;
223
+ authChanges?: undefined;
224
+ serverId?: undefined;
225
+ }, {
226
+ found: false;
227
+ serverId?: undefined;
228
+ endpointUrl?: undefined;
229
+ token?: undefined;
230
+ secrets?: undefined;
231
+ cache?: undefined;
232
+ authChanges?: undefined;
233
+ } | {
234
+ found: true;
235
+ serverId: string;
236
+ endpointUrl: string;
237
+ token: string | undefined;
238
+ secrets: {
239
+ id: import("@fragno-dev/db/schema").FragnoId;
240
+ serverId: import("@fragno-dev/db/schema").FragnoReference;
241
+ kind: string;
242
+ payload: string;
243
+ expiresAt: Date | null;
244
+ updatedAt: Date;
245
+ }[];
246
+ cache: {
247
+ id: import("@fragno-dev/db/schema").FragnoId;
248
+ serverId: import("@fragno-dev/db/schema").FragnoReference;
249
+ protocolVersion: string | null;
250
+ serverInfo: unknown;
251
+ capabilities: unknown;
252
+ tools: unknown;
253
+ updatedAt: Date;
254
+ } | null;
255
+ authChanges: AuthPersistenceChanges | undefined;
256
+ }>;
257
+ }, {}, {}, {}, import("@fragno-dev/db").DatabaseServiceContext<McpHooksMap>, import("@fragno-dev/db").DatabaseRequestContext<McpHooksMap>, import("@fragno-dev/db/fragment-definition-builder").DatabaseRequestStorage, []>;
258
+ //#endregion
259
+ export {};
260
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","names":["BaseMcpFragmentConfig"],"sources":["../../src/definition.ts"],"mappings":";;;;iBAmBiB;EACf;EACA;IACE;;;iBAIa;EACf;;iBAGe;EACf;;EAEA;;;;;;iBAOe,iCAAiC;EAChD;IAAU;IAAqB;;;iBAGhB;EACf,gCACE,SAAS,sCACT,SAAS,gBACN;EACL,gCACE,SAAS,sCACT,SAAS,gBACN;;;;;;EAML,4BACE,SAAS,0BACT,SAAS,gBACN;;YAGK,oBAAoBA,sBAAwB;iBAEvC;EACf;;;UAIQ;EACR;EACA;;YAGU;EACV,oCAAoC,OAAO;EAC3C,qBAAqB,OAAO;EAC5B,8BAA8B,OAAO;EACrC,8BAA8B,OAAO;EACrC,0BAA0B,OAAO;;;wBAInB,sBAEd;EACE,YACE,6BACA,SAAS,+BACT;IAAW,WAAW;;GAG1B,kBACA,kBACA;EAAS;EAAiB,WAAW;;qBAY1B,kDAAqB,mBAAA,4CAAA,yDAAA,6DAAA;;;;;;EAoLC,aAAA;IAC3B;IACA;IACA;IACA;IACA;IACA;IACA;iCACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAnQsB;;;;;;;;;EA+WiB,wBAAA;IACtC;IACA;IACA;iCACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwGqC,sBAAA;IAAE;iCAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wCA8CtD,uBAAA,uCAAA,uBAAA,mEAAA"}
@@ -0,0 +1,330 @@
1
+ import { listMcpTools } from "./mcp-api.js";
2
+ import { mcpSchema } from "./schema.js";
3
+ import { createMcpOperationAuth, createOAuthCallbackSnapshot, createOAuthStartSnapshot, isMcpAuthReady, mcpAuthReadyUntil, resolveMcpOperationAuth, resolveOAuthStartClient, withoutOAuthConsent, writeOAuthSecretChanges } from "./services.js";
4
+ import { defineFragment } from "@fragno-dev/core";
5
+ import { withDatabase } from "@fragno-dev/db";
6
+ //#region src/definition.ts
7
+ /** Expiry changes readiness without a write, so a write that starts the countdown schedules it. */
8
+ function scheduleMcpAuthExpiry(uow, serverId, authMode, after) {
9
+ const readyUntil = mcpAuthReadyUntil(authMode, after);
10
+ if (readyUntil && after.expiresAt && isMcpAuthReady(authMode, after)) uow.triggerHook("internalAuthExpired", {
11
+ serverId,
12
+ expiresAt: after.expiresAt.toISOString()
13
+ }, { processAt: readyUntil });
14
+ }
15
+ const mcpFragmentDefinition = defineFragment("mcp-fragment").extend(withDatabase(mcpSchema)).provideHooks(({ defineHook, config }) => ({
16
+ internalRefreshServerConfiguration: defineHook(async function({ serverId }) {
17
+ let prepared;
18
+ const result = await this.handlerTx().retrieve(({ forSchema }) => forSchema(mcpSchema).findFirst("server_configuration", (b) => b.whereIndex("primary", (eb) => eb("id", "=", serverId))).find("secret", (b) => b.whereIndex("idx_secret_server_kind", (eb) => eb("serverId", "=", serverId))).findFirst("server_connection_cache", (b) => b.whereIndex("primary", (eb) => eb("id", "=", serverId)))).afterRetrieve(async (_uow, [server, secrets]) => {
19
+ if (!server) return;
20
+ const auth = await createMcpOperationAuth({
21
+ config,
22
+ server,
23
+ secrets
24
+ });
25
+ const toolsOperation = await listMcpTools({
26
+ endpointUrl: server.endpointUrl,
27
+ auth,
28
+ fetchImplementation: config.fetch
29
+ });
30
+ prepared = {
31
+ authChanges: toolsOperation.authChanges,
32
+ toolsOperation
33
+ };
34
+ }).mutate(({ forSchema, retrieveResult: [server, secrets, cache] }) => {
35
+ if (!server) return { action: "missing" };
36
+ if (!prepared) throw new Error("MCP refresh operation was not prepared");
37
+ const preparedOperation = prepared;
38
+ const uow = forSchema(mcpSchema);
39
+ const upsertSecret = (kind, payload, expiresAt) => {
40
+ const existing = secrets.find((secret) => secret.kind === kind);
41
+ if (existing) {
42
+ uow.update("secret", existing.id, (b) => b.set({
43
+ payload,
44
+ expiresAt,
45
+ updatedAt: b.now()
46
+ }).check());
47
+ return;
48
+ }
49
+ uow.create("secret", {
50
+ id: `${serverId}:${kind}`,
51
+ serverId,
52
+ kind,
53
+ payload,
54
+ expiresAt
55
+ });
56
+ };
57
+ if (preparedOperation.authChanges) writeOAuthSecretChanges(preparedOperation.authChanges, {
58
+ upsert: (kind, payload) => {
59
+ upsertSecret(kind, payload, null);
60
+ },
61
+ remove: (kind) => {
62
+ const existing = secrets.find((secret) => secret.kind === kind);
63
+ if (existing) uow.delete("secret", existing.id);
64
+ }
65
+ });
66
+ if (preparedOperation.authChanges?.authPayload) {
67
+ const after = {
68
+ payload: preparedOperation.authChanges.authPayload,
69
+ expiresAt: preparedOperation.authChanges.authExpiresAt ?? null
70
+ };
71
+ upsertSecret("auth", after.payload, after.expiresAt);
72
+ const before = secrets.find((secret) => secret.kind === "auth");
73
+ const ready = isMcpAuthReady(server.authMode, after);
74
+ if (ready !== isMcpAuthReady(server.authMode, before)) uow.triggerHook("onServerReadinessChanged", {
75
+ serverId,
76
+ ready
77
+ });
78
+ scheduleMcpAuthExpiry(uow, serverId, server.authMode, after);
79
+ }
80
+ if (!preparedOperation.toolsOperation.ok) return {
81
+ action: "error",
82
+ error: preparedOperation.toolsOperation.error instanceof Error ? preparedOperation.toolsOperation.error.message : String(preparedOperation.toolsOperation.error)
83
+ };
84
+ const tools = Array.isArray(preparedOperation.toolsOperation.result.tools) ? preparedOperation.toolsOperation.result.tools : [];
85
+ const previousTools = Array.isArray(cache?.tools) ? cache.tools : null;
86
+ if (!previousTools || JSON.stringify(previousTools) !== JSON.stringify(tools)) uow.triggerHook("onServerConfigurationChanged", {
87
+ serverId,
88
+ current: { tools }
89
+ });
90
+ uow.delete("server_connection_cache", serverId);
91
+ uow.create("server_connection_cache", {
92
+ id: serverId,
93
+ serverId,
94
+ protocolVersion: preparedOperation.toolsOperation.metadata.protocolVersion ?? null,
95
+ serverInfo: preparedOperation.toolsOperation.metadata.serverInfo ?? null,
96
+ capabilities: preparedOperation.toolsOperation.metadata.capabilities ?? null,
97
+ tools
98
+ });
99
+ return { action: "refreshed" };
100
+ }).execute();
101
+ if (result.action === "error") throw new Error(result.error);
102
+ }),
103
+ onServerConfigurationChanged: defineHook(async function(payload) {
104
+ await config.onServerConfigurationChanged?.(payload, this);
105
+ }),
106
+ onServerConfigurationDeleted: defineHook(async function(payload) {
107
+ await config.onServerConfigurationDeleted?.(payload, this);
108
+ }),
109
+ onServerReadinessChanged: defineHook(async function(payload) {
110
+ const server = await this.handlerTx().retrieve(({ forSchema }) => forSchema(mcpSchema).findFirst("server_configuration", (b) => b.whereIndex("primary", (eb) => eb("id", "=", payload.serverId)))).transformRetrieve(([server]) => server && {
111
+ name: server.name,
112
+ authMode: server.authMode
113
+ }).execute();
114
+ await config.onServerReadinessChanged?.({
115
+ ...payload,
116
+ server
117
+ }, this);
118
+ }),
119
+ internalAuthExpired: defineHook(async function({ serverId, expiresAt }) {
120
+ const expired = await this.handlerTx().retrieve(({ forSchema }) => forSchema(mcpSchema).findFirst("server_configuration", (b) => b.whereIndex("primary", (eb) => eb("id", "=", serverId))).findFirst("secret", (b) => b.whereIndex("idx_secret_server_kind", (eb) => eb.and(eb("serverId", "=", serverId), eb("kind", "=", "auth"))))).transformRetrieve(([server, secret]) => server !== null && secret !== null && secret.expiresAt?.getTime() === Date.parse(expiresAt) && mcpAuthReadyUntil(server.authMode, secret) !== null ? {
121
+ name: server.name,
122
+ authMode: server.authMode
123
+ } : null).execute();
124
+ if (expired) await config.onServerReadinessChanged?.({
125
+ serverId,
126
+ ready: false,
127
+ server: expired
128
+ }, this);
129
+ })
130
+ })).providesBaseService(({ defineService, config }) => defineService({
131
+ startOAuth: function(input) {
132
+ return this.serviceTx(mcpSchema).retrieve((uow) => uow.findFirst("server_configuration", (b) => b.whereIndex("primary", (eb) => eb("id", "=", input.serverId))).find("secret", (b) => b.whereIndex("idx_secret_server_kind", (eb) => eb("serverId", "=", input.serverId)))).transformRetrieve(async ([server, secrets]) => {
133
+ if (!server) return { found: false };
134
+ const { authorizationUrl, changes } = await createOAuthStartSnapshot({
135
+ config,
136
+ server,
137
+ secrets,
138
+ stateId: input.stateId,
139
+ redirectUri: input.redirectUri,
140
+ ...resolveOAuthStartClient(secrets, input)
141
+ });
142
+ return {
143
+ found: true,
144
+ authorizationUrl: authorizationUrl.toString(),
145
+ serverId: server.id.toString(),
146
+ authMode: server.authMode,
147
+ secrets,
148
+ changes
149
+ };
150
+ }).mutate(({ uow, retrieveResult }) => {
151
+ if (!retrieveResult.found) return { found: false };
152
+ const upsertSecret = (kind, payload, expiresAt) => {
153
+ const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);
154
+ if (existing) {
155
+ uow.update("secret", existing.id, (b) => b.set({
156
+ payload,
157
+ expiresAt,
158
+ updatedAt: b.now()
159
+ }).check());
160
+ return;
161
+ }
162
+ uow.create("secret", {
163
+ id: `${retrieveResult.serverId}:${kind}`,
164
+ serverId: retrieveResult.serverId,
165
+ kind,
166
+ payload,
167
+ expiresAt
168
+ });
169
+ };
170
+ writeOAuthSecretChanges(retrieveResult.changes, {
171
+ upsert: (kind, payload) => {
172
+ upsertSecret(kind, payload, null);
173
+ },
174
+ remove: (kind) => {
175
+ const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);
176
+ if (existing) uow.delete("secret", existing.id);
177
+ }
178
+ });
179
+ const authSecret = retrieveResult.secrets.find((secret) => secret.kind === "auth");
180
+ if (input.discardTokens && authSecret) {
181
+ const payload = withoutOAuthConsent(authSecret.payload);
182
+ uow.update("secret", authSecret.id, (b) => b.set({
183
+ payload,
184
+ expiresAt: null,
185
+ updatedAt: b.now()
186
+ }).check());
187
+ const { authMode } = retrieveResult;
188
+ const ready = isMcpAuthReady(authMode, {
189
+ payload,
190
+ expiresAt: null
191
+ });
192
+ if (ready !== isMcpAuthReady(authMode, authSecret)) uow.triggerHook("onServerReadinessChanged", {
193
+ serverId: retrieveResult.serverId,
194
+ ready
195
+ });
196
+ }
197
+ if (retrieveResult.changes.oauthState) uow.create("oauthState", {
198
+ id: retrieveResult.changes.oauthState.id,
199
+ serverId: retrieveResult.serverId,
200
+ authorizationUrl: retrieveResult.authorizationUrl,
201
+ codeVerifier: retrieveResult.changes.oauthState.codeVerifier,
202
+ redirectUri: retrieveResult.changes.oauthState.redirectUri,
203
+ scope: retrieveResult.changes.oauthState.scope ?? null,
204
+ expiresAt: retrieveResult.changes.oauthState.expiresAt,
205
+ consumedAt: null
206
+ });
207
+ return { found: true };
208
+ }).transform(({ retrieveResult }) => retrieveResult.found ? {
209
+ found: true,
210
+ authorizationUrl: retrieveResult.authorizationUrl
211
+ } : { found: false }).build();
212
+ },
213
+ completeOAuthCallback: function(input) {
214
+ const serverId = input.stateId.split(":")[0] ?? "";
215
+ return this.serviceTx(mcpSchema).retrieve((uow) => uow.findFirst("oauthState", (b) => b.whereIndex("primary", (eb) => eb("id", "=", input.stateId))).findFirst("server_configuration", (b) => b.whereIndex("primary", (eb) => eb("id", "=", serverId))).find("secret", (b) => b.whereIndex("idx_secret_server_kind", (eb) => eb("serverId", "=", serverId))).findFirst("server_connection_cache", (b) => b.whereIndex("primary", (eb) => eb("id", "=", serverId)))).transformRetrieve(async ([state, server, secrets, cache]) => {
216
+ if (!state || state.consumedAt || new Date(state.expiresAt).getTime() < Date.now()) return {
217
+ found: false,
218
+ reason: "invalid_state"
219
+ };
220
+ if (!server) return {
221
+ found: false,
222
+ reason: "server_not_found"
223
+ };
224
+ return {
225
+ found: true,
226
+ server,
227
+ secrets,
228
+ cache,
229
+ changes: await createOAuthCallbackSnapshot({
230
+ config,
231
+ stateId: input.stateId,
232
+ code: input.code,
233
+ iss: input.iss,
234
+ state,
235
+ server,
236
+ secrets
237
+ })
238
+ };
239
+ }).mutate(({ uow, retrieveResult }) => {
240
+ if (!retrieveResult.found) return {
241
+ found: false,
242
+ reason: retrieveResult.reason
243
+ };
244
+ const serverId = retrieveResult.server.id.toString();
245
+ const upsertSecret = (kind, payload, expiresAt) => {
246
+ const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);
247
+ if (existing) {
248
+ uow.update("secret", existing.id, (b) => b.set({
249
+ payload,
250
+ expiresAt,
251
+ updatedAt: b.now()
252
+ }).check());
253
+ return;
254
+ }
255
+ uow.create("secret", {
256
+ id: `${serverId}:${kind}`,
257
+ serverId,
258
+ kind,
259
+ payload,
260
+ expiresAt
261
+ });
262
+ };
263
+ writeOAuthSecretChanges(retrieveResult.changes, {
264
+ upsert: (kind, payload) => {
265
+ upsertSecret(kind, payload, null);
266
+ },
267
+ remove: (kind) => {
268
+ const existing = retrieveResult.secrets.find((secret) => secret.kind === kind);
269
+ if (existing) uow.delete("secret", existing.id);
270
+ }
271
+ });
272
+ if (retrieveResult.changes.authPayload) {
273
+ const after = {
274
+ payload: retrieveResult.changes.authPayload,
275
+ expiresAt: retrieveResult.changes.authExpiresAt ?? null
276
+ };
277
+ upsertSecret("auth", after.payload, after.expiresAt);
278
+ uow.update("server_configuration", retrieveResult.server.id, (b) => b.set({
279
+ authMode: "oauth",
280
+ updatedAt: b.now()
281
+ }).check());
282
+ const before = retrieveResult.secrets.find((secret) => secret.kind === "auth");
283
+ const ready = isMcpAuthReady("oauth", after);
284
+ if (ready !== isMcpAuthReady(retrieveResult.server.authMode, before)) uow.triggerHook("onServerReadinessChanged", {
285
+ serverId,
286
+ ready
287
+ });
288
+ scheduleMcpAuthExpiry(uow, serverId, "oauth", after);
289
+ if (retrieveResult.cache) uow.delete("server_connection_cache", retrieveResult.cache.id);
290
+ uow.triggerHook("internalRefreshServerConfiguration", { serverId });
291
+ }
292
+ if (retrieveResult.changes.consumeStateId) uow.update("oauthState", input.stateId, (b) => b.set({ consumedAt: b.now() }));
293
+ return { found: true };
294
+ }).transform(({ retrieveResult }) => retrieveResult.found ? { found: true } : {
295
+ found: false,
296
+ reason: retrieveResult.reason
297
+ }).build();
298
+ },
299
+ prepareMcpOperation: function(input) {
300
+ return this.serviceTx(mcpSchema).retrieve((uow) => uow.findFirst("server_configuration", (b) => b.whereIndex("primary", (eb) => eb("id", "=", input.serverId))).find("secret", (b) => b.whereIndex("idx_secret_server_kind", (eb) => eb("serverId", "=", input.serverId))).findFirst("server_connection_cache", (b) => b.whereIndex("primary", (eb) => eb("id", "=", input.serverId)))).transformRetrieve(async ([server, secrets, cache]) => {
301
+ if (!server) return { found: false };
302
+ const resolved = await resolveMcpOperationAuth({
303
+ config,
304
+ server,
305
+ secrets
306
+ });
307
+ return {
308
+ found: true,
309
+ serverId: server.id.toString(),
310
+ endpointUrl: server.endpointUrl,
311
+ token: resolved.token,
312
+ secrets,
313
+ cache,
314
+ authChanges: resolved.authChanges
315
+ };
316
+ }).transform(({ retrieveResult }) => retrieveResult.found ? {
317
+ found: true,
318
+ endpointUrl: retrieveResult.endpointUrl,
319
+ token: retrieveResult.token,
320
+ secrets: retrieveResult.secrets,
321
+ cache: retrieveResult.cache,
322
+ authChanges: retrieveResult.authChanges,
323
+ serverId: retrieveResult.serverId
324
+ } : { found: false }).build();
325
+ }
326
+ })).build();
327
+ //#endregion
328
+ export { mcpFragmentDefinition, scheduleMcpAuthExpiry };
329
+
330
+ //# sourceMappingURL=definition.js.map