@zackbart/connecta 0.7.9 → 0.8.1

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 (199) hide show
  1. package/CHANGELOG.md +135 -0
  2. package/README.md +47 -148
  3. package/dist/activity.d.ts +0 -8
  4. package/dist/activity.d.ts.map +1 -1
  5. package/dist/activity.js +0 -1
  6. package/dist/activity.js.map +1 -1
  7. package/dist/auth/bearer.d.ts +1 -7
  8. package/dist/auth/bearer.d.ts.map +1 -1
  9. package/dist/auth/bearer.js +3 -24
  10. package/dist/auth/bearer.js.map +1 -1
  11. package/dist/auth/clerk.d.ts +2 -11
  12. package/dist/auth/clerk.d.ts.map +1 -1
  13. package/dist/auth/clerk.js +31 -46
  14. package/dist/auth/clerk.js.map +1 -1
  15. package/dist/call-admission.d.ts.map +1 -1
  16. package/dist/call-admission.js +9 -4
  17. package/dist/call-admission.js.map +1 -1
  18. package/dist/catalog-fingerprint.d.ts +20 -0
  19. package/dist/catalog-fingerprint.d.ts.map +1 -0
  20. package/dist/catalog-fingerprint.js +34 -0
  21. package/dist/catalog-fingerprint.js.map +1 -0
  22. package/dist/catalog-limits.d.ts +10 -0
  23. package/dist/catalog-limits.d.ts.map +1 -0
  24. package/dist/catalog-limits.js +10 -0
  25. package/dist/catalog-limits.js.map +1 -0
  26. package/dist/catalog-service.d.ts +137 -0
  27. package/dist/catalog-service.d.ts.map +1 -0
  28. package/dist/catalog-service.js +401 -0
  29. package/dist/catalog-service.js.map +1 -0
  30. package/dist/catalog.d.ts +6 -0
  31. package/dist/catalog.d.ts.map +1 -1
  32. package/dist/catalog.js +53 -2
  33. package/dist/catalog.js.map +1 -1
  34. package/dist/concurrency.d.ts +4 -0
  35. package/dist/concurrency.d.ts.map +1 -0
  36. package/dist/concurrency.js +31 -0
  37. package/dist/concurrency.js.map +1 -0
  38. package/dist/connectors/api.d.ts.map +1 -1
  39. package/dist/connectors/api.js +22 -12
  40. package/dist/connectors/api.js.map +1 -1
  41. package/dist/connectors/remote-mcp.d.ts.map +1 -1
  42. package/dist/connectors/remote-mcp.js +53 -41
  43. package/dist/connectors/remote-mcp.js.map +1 -1
  44. package/dist/credentials.d.ts +3 -2
  45. package/dist/credentials.d.ts.map +1 -1
  46. package/dist/errors.d.ts +19 -1
  47. package/dist/errors.d.ts.map +1 -1
  48. package/dist/errors.js.map +1 -1
  49. package/dist/execute.d.ts +10 -16
  50. package/dist/execute.d.ts.map +1 -1
  51. package/dist/execute.js +143 -330
  52. package/dist/execute.js.map +1 -1
  53. package/dist/executor-result.d.ts +0 -3
  54. package/dist/executor-result.d.ts.map +1 -1
  55. package/dist/executor-result.js +3 -3
  56. package/dist/executor-result.js.map +1 -1
  57. package/dist/executors/quickjs-child.js +3 -3
  58. package/dist/executors/quickjs-child.js.map +1 -1
  59. package/dist/executors/quickjs-protocol.d.ts +4 -1
  60. package/dist/executors/quickjs-protocol.d.ts.map +1 -1
  61. package/dist/executors/quickjs-runtime.d.ts.map +1 -1
  62. package/dist/executors/quickjs-runtime.js +7 -2
  63. package/dist/executors/quickjs-runtime.js.map +1 -1
  64. package/dist/executors/quickjs.d.ts.map +1 -1
  65. package/dist/executors/quickjs.js +4 -1
  66. package/dist/executors/quickjs.js.map +1 -1
  67. package/dist/favicon.js +2 -2
  68. package/dist/favicon.js.map +1 -1
  69. package/dist/index.d.ts +8 -82
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +58 -104
  72. package/dist/index.js.map +1 -1
  73. package/dist/invocation.d.ts +101 -0
  74. package/dist/invocation.d.ts.map +1 -0
  75. package/dist/invocation.js +405 -0
  76. package/dist/invocation.js.map +1 -0
  77. package/dist/meta-tools.d.ts +9 -95
  78. package/dist/meta-tools.d.ts.map +1 -1
  79. package/dist/meta-tools.js +235 -725
  80. package/dist/meta-tools.js.map +1 -1
  81. package/dist/operator-ui/generated.d.ts +3 -0
  82. package/dist/operator-ui/generated.d.ts.map +1 -0
  83. package/dist/operator-ui/generated.js +5 -0
  84. package/dist/operator-ui/generated.js.map +1 -0
  85. package/dist/operator-ui/model.d.ts +73 -0
  86. package/dist/operator-ui/model.d.ts.map +1 -0
  87. package/dist/operator-ui/model.js +28 -0
  88. package/dist/operator-ui/model.js.map +1 -0
  89. package/dist/registry.d.ts +33 -184
  90. package/dist/registry.d.ts.map +1 -1
  91. package/dist/registry.js +345 -330
  92. package/dist/registry.js.map +1 -1
  93. package/dist/retired-toolkits.d.ts +3 -0
  94. package/dist/retired-toolkits.d.ts.map +1 -0
  95. package/dist/retired-toolkits.js +9 -0
  96. package/dist/retired-toolkits.js.map +1 -0
  97. package/dist/routes/activity.d.ts +3 -0
  98. package/dist/routes/activity.d.ts.map +1 -0
  99. package/dist/routes/activity.js +170 -0
  100. package/dist/routes/activity.js.map +1 -0
  101. package/dist/routes/credentials.d.ts +3 -0
  102. package/dist/routes/credentials.d.ts.map +1 -0
  103. package/dist/routes/credentials.js +170 -0
  104. package/dist/routes/credentials.js.map +1 -0
  105. package/dist/routes/mcp.d.ts +8 -0
  106. package/dist/routes/mcp.d.ts.map +1 -0
  107. package/dist/routes/mcp.js +270 -0
  108. package/dist/routes/mcp.js.map +1 -0
  109. package/dist/routes/oauth.d.ts +4 -0
  110. package/dist/routes/oauth.d.ts.map +1 -0
  111. package/dist/routes/oauth.js +263 -0
  112. package/dist/routes/oauth.js.map +1 -0
  113. package/dist/routes/shared.d.ts +76 -0
  114. package/dist/routes/shared.d.ts.map +1 -0
  115. package/dist/routes/shared.js +140 -0
  116. package/dist/routes/shared.js.map +1 -0
  117. package/dist/routes/ui.d.ts +3 -0
  118. package/dist/routes/ui.d.ts.map +1 -0
  119. package/dist/routes/ui.js +116 -0
  120. package/dist/routes/ui.js.map +1 -0
  121. package/dist/server.d.ts +9 -40
  122. package/dist/server.d.ts.map +1 -1
  123. package/dist/server.js +62 -1322
  124. package/dist/server.js.map +1 -1
  125. package/dist/skills.d.ts +3 -21
  126. package/dist/skills.d.ts.map +1 -1
  127. package/dist/skills.js +15 -43
  128. package/dist/skills.js.map +1 -1
  129. package/dist/storage/file.d.ts.map +1 -1
  130. package/dist/storage/file.js +3 -1
  131. package/dist/storage/file.js.map +1 -1
  132. package/dist/storage/memory.d.ts.map +1 -1
  133. package/dist/storage/memory.js +3 -1
  134. package/dist/storage/memory.js.map +1 -1
  135. package/dist/timeout.d.ts.map +1 -1
  136. package/dist/timeout.js +2 -4
  137. package/dist/timeout.js.map +1 -1
  138. package/dist/types.d.ts +9 -59
  139. package/dist/types.d.ts.map +1 -1
  140. package/dist/ui.d.ts +3 -94
  141. package/dist/ui.d.ts.map +1 -1
  142. package/dist/ui.js +30 -1427
  143. package/dist/ui.js.map +1 -1
  144. package/dist/version.d.ts +1 -1
  145. package/dist/version.js +1 -1
  146. package/package.json +15 -8
  147. package/src/activity.ts +0 -9
  148. package/src/auth/bearer.ts +4 -33
  149. package/src/auth/clerk.ts +35 -48
  150. package/src/call-admission.ts +8 -6
  151. package/src/catalog-fingerprint.ts +52 -0
  152. package/src/catalog-limits.ts +11 -0
  153. package/src/catalog-service.ts +601 -0
  154. package/src/catalog.ts +57 -2
  155. package/src/concurrency.ts +39 -0
  156. package/src/connectors/api.ts +22 -12
  157. package/src/connectors/remote-mcp.ts +63 -45
  158. package/src/credentials.ts +2 -2
  159. package/src/errors.ts +21 -1
  160. package/src/execute.ts +193 -423
  161. package/src/executor-result.ts +3 -3
  162. package/src/executors/quickjs-child.ts +8 -4
  163. package/src/executors/quickjs-protocol.ts +1 -1
  164. package/src/executors/quickjs-runtime.ts +5 -1
  165. package/src/executors/quickjs.ts +11 -8
  166. package/src/favicon.ts +2 -2
  167. package/src/index.ts +70 -222
  168. package/src/invocation.ts +580 -0
  169. package/src/meta-tools.ts +393 -985
  170. package/src/operator-ui/browser.css +360 -0
  171. package/src/operator-ui/browser.ts +987 -0
  172. package/src/operator-ui/generated.ts +4 -0
  173. package/src/operator-ui/model.ts +105 -0
  174. package/src/registry.ts +459 -439
  175. package/src/retired-toolkits.ts +14 -0
  176. package/src/routes/activity.ts +215 -0
  177. package/src/routes/credentials.ts +254 -0
  178. package/src/routes/mcp.ts +339 -0
  179. package/src/routes/oauth.ts +322 -0
  180. package/src/routes/shared.ts +240 -0
  181. package/src/routes/ui.ts +143 -0
  182. package/src/server.ts +64 -1731
  183. package/src/skills.ts +15 -43
  184. package/src/storage/file.ts +3 -1
  185. package/src/storage/memory.ts +3 -1
  186. package/src/timeout.ts +2 -4
  187. package/src/types.ts +8 -60
  188. package/src/ui.ts +60 -1538
  189. package/src/version.ts +1 -1
  190. package/dist/credential-health.d.ts +0 -227
  191. package/dist/credential-health.d.ts.map +0 -1
  192. package/dist/credential-health.js +0 -606
  193. package/dist/credential-health.js.map +0 -1
  194. package/dist/toolkits.d.ts +0 -146
  195. package/dist/toolkits.d.ts.map +0 -1
  196. package/dist/toolkits.js +0 -322
  197. package/dist/toolkits.js.map +0 -1
  198. package/src/credential-health.ts +0 -832
  199. package/src/toolkits.ts +0 -461
@@ -0,0 +1,270 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
3
+ import { registerExecuteTool } from "../execute.js";
4
+ import { ExecutorAdmissionError, } from "../executor-admission.js";
5
+ import { registerMetaTools } from "../meta-tools.js";
6
+ import { CONNECTA_INSTRUCTIONS } from "../skills.js";
7
+ import { authorize, } from "./shared.js";
8
+ export const MCP_CORS_HEADERS = {
9
+ "Access-Control-Allow-Origin": "*",
10
+ "Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
11
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, mcp-protocol-version, mcp-session-id",
12
+ };
13
+ // Browser-based MCP clients call /mcp cross-origin. Without CORS on every
14
+ // response — errors included — the browser hides the 401, the client cannot
15
+ // read WWW-Authenticate, and OAuth discovery silently never starts.
16
+ function withMcpCors(response) {
17
+ const headers = new Headers(response.headers);
18
+ for (const [name, value] of Object.entries(MCP_CORS_HEADERS)) {
19
+ headers.set(name, value);
20
+ }
21
+ headers.set("Access-Control-Expose-Headers", "WWW-Authenticate, Retry-After, mcp-session-id, mcp-protocol-version");
22
+ return new Response(response.body, {
23
+ status: response.status,
24
+ statusText: response.statusText,
25
+ headers,
26
+ });
27
+ }
28
+ function requestAdmissionFailure(error) {
29
+ const overloaded = error.code === "executor_overloaded";
30
+ const data = {
31
+ code: overloaded ? "server_overloaded" : "server_shutting_down",
32
+ retryable: overloaded,
33
+ ...(overloaded && error.retryAfterMs !== undefined
34
+ ? { retryAfterMs: error.retryAfterMs }
35
+ : {}),
36
+ };
37
+ const headers = new Headers({
38
+ "Content-Type": "application/json",
39
+ "Cache-Control": "no-store",
40
+ });
41
+ if (overloaded && error.retryAfterMs !== undefined) {
42
+ headers.set("Retry-After", String(Math.max(1, Math.ceil(error.retryAfterMs / 1_000))));
43
+ }
44
+ return new Response(JSON.stringify({
45
+ jsonrpc: "2.0",
46
+ id: null,
47
+ error: {
48
+ code: overloaded ? -32001 : -32002,
49
+ message: overloaded
50
+ ? "Server capacity is exhausted. Retry later."
51
+ : "Server is shutting down.",
52
+ data,
53
+ },
54
+ }), { status: 503, headers });
55
+ }
56
+ /**
57
+ * A request owns its permit through the response body, not merely until the
58
+ * handler returns. This is what makes slow clients and response-stream failure
59
+ * part of the same bounded lifecycle as success, error, and cancellation.
60
+ */
61
+ function releaseAdmissionWithResponse(response, lease, signal) {
62
+ let released = false;
63
+ let onAbort = () => { };
64
+ const release = () => {
65
+ if (released)
66
+ return;
67
+ released = true;
68
+ signal.removeEventListener("abort", onAbort);
69
+ lease.release();
70
+ };
71
+ if (!response.body) {
72
+ release();
73
+ return response;
74
+ }
75
+ const reader = response.body.getReader();
76
+ onAbort = () => {
77
+ // `cancel()` belongs to an operator/auth/SDK-provided stream and may
78
+ // reject. Consume both outcomes: `.finally(release)` would release the
79
+ // permit but preserve the rejection as an unhandled promise.
80
+ void reader.cancel(signal.reason).then(release, release);
81
+ };
82
+ signal.addEventListener("abort", onAbort, { once: true });
83
+ if (signal.aborted)
84
+ onAbort();
85
+ const body = new ReadableStream({
86
+ async pull(controller) {
87
+ try {
88
+ const next = await reader.read();
89
+ if (next.done) {
90
+ release();
91
+ controller.close();
92
+ }
93
+ else {
94
+ controller.enqueue(next.value);
95
+ }
96
+ }
97
+ catch (error) {
98
+ release();
99
+ controller.error(error);
100
+ }
101
+ },
102
+ async cancel(reason) {
103
+ try {
104
+ await reader.cancel(reason);
105
+ }
106
+ finally {
107
+ release();
108
+ }
109
+ },
110
+ });
111
+ return new Response(body, {
112
+ status: response.status,
113
+ statusText: response.statusText,
114
+ headers: response.headers,
115
+ });
116
+ }
117
+ /**
118
+ * 404 for any `?toolkit=` value, kept after the feature's retirement (#178).
119
+ *
120
+ * Toolkits are gone, but the URLs that named them are not: clients were handed
121
+ * MCP endpoint URLs with `?toolkit=` baked in, and nothing about upgrading the
122
+ * server rotates them. Silently serving those clients the full registry would
123
+ * turn a former scoping boundary into fail-open — so a request still sending
124
+ * the param gets the same explicit 404 an unknown toolkit got before, plus an
125
+ * operator-side log line, which (as ever — issue #47) is the channel that
126
+ * actually reaches a human.
127
+ */
128
+ function toolkitRetired(logger) {
129
+ logger.warn("[connecta] rejected an /mcp connection carrying ?toolkit= with 404: " +
130
+ "toolkits were retired in issue #178 (see ethos.md) — one deployment " +
131
+ "serves one audience. The client sees a transport-level failure and " +
132
+ "never the reason, so remove the ?toolkit= value from its MCP endpoint " +
133
+ "URL, or point it at the deployment for its audience.");
134
+ return new Response(JSON.stringify({
135
+ jsonrpc: "2.0",
136
+ id: null,
137
+ error: {
138
+ code: -32600,
139
+ message: "This deployment does not accept ?toolkit=. Toolkits were retired " +
140
+ "in issue #178 — remove the ?toolkit= value from the MCP endpoint " +
141
+ "URL, or ask the operator for the deployment serving this audience.",
142
+ },
143
+ }), {
144
+ status: 404,
145
+ headers: {
146
+ "Content-Type": "application/json",
147
+ "Cache-Control": "no-store",
148
+ },
149
+ });
150
+ }
151
+ async function serveMcp(request, opts, baseUrl, actor, registry, runtimeContext) {
152
+ // Fresh McpServer + transport per request (SDK ≥1.26 requirement), stateless.
153
+ const server = new McpServer(opts.serverInfo, {
154
+ instructions: CONNECTA_INSTRUCTIONS,
155
+ });
156
+ const activity = opts.activity
157
+ ? {
158
+ sink: opts.activity,
159
+ actor,
160
+ requestId: crypto.randomUUID(),
161
+ serverInfo: opts.serverInfo,
162
+ ...(opts.activityDeploymentId
163
+ ? { deploymentId: opts.activityDeploymentId }
164
+ : {}),
165
+ ...(runtimeContext?.waitUntil
166
+ ? { defer: runtimeContext.waitUntil.bind(runtimeContext) }
167
+ : {}),
168
+ logger: opts.logger,
169
+ }
170
+ : undefined;
171
+ registerMetaTools(server, registry, {
172
+ baseUrl,
173
+ ...(activity ? { activity } : {}),
174
+ ...(opts.defaultToolTimeoutMs !== undefined
175
+ ? { defaultToolTimeoutMs: opts.defaultToolTimeoutMs }
176
+ : {}),
177
+ ...(opts.probeTimeoutMs !== undefined
178
+ ? { probeTimeoutMs: opts.probeTimeoutMs }
179
+ : {}),
180
+ ...(opts.discoveryConcurrency !== undefined
181
+ ? { discoveryConcurrency: opts.discoveryConcurrency }
182
+ : {}),
183
+ requestSignal: request.signal,
184
+ ...(runtimeContext
185
+ ? { defer: runtimeContext.waitUntil.bind(runtimeContext) }
186
+ : {}),
187
+ });
188
+ if (opts.executor) {
189
+ registerExecuteTool(server, registry, {
190
+ baseUrl,
191
+ executor: opts.executor,
192
+ logger: opts.logger,
193
+ ...(activity ? { activity } : {}),
194
+ requestSignal: request.signal,
195
+ ...(opts.discoveryConcurrency !== undefined
196
+ ? { discoveryConcurrency: opts.discoveryConcurrency }
197
+ : {}),
198
+ });
199
+ }
200
+ const transport = new WebStandardStreamableHTTPServerTransport({
201
+ enableJsonResponse: true,
202
+ });
203
+ await server.connect(transport);
204
+ return transport.handleRequest(request);
205
+ }
206
+ export function createMcpRoute(opts) {
207
+ let lastAdmissionWarningAt = 0;
208
+ let suppressedAdmissionWarnings = 0;
209
+ const warnAdmissionRejected = (error) => {
210
+ const now = Date.now();
211
+ if (now - lastAdmissionWarningAt < 1_000) {
212
+ suppressedAdmissionWarnings++;
213
+ return;
214
+ }
215
+ opts.logger.warn("[connecta] MCP request admission rejected", {
216
+ retryAfterMs: error.retryAfterMs,
217
+ active: opts.requestAdmission.activeCount,
218
+ queued: opts.requestAdmission.queuedCount,
219
+ suppressedSinceLastWarning: suppressedAdmissionWarnings,
220
+ });
221
+ lastAdmissionWarningAt = now;
222
+ suppressedAdmissionWarnings = 0;
223
+ };
224
+ return async function routeMcp(context) {
225
+ const { path, request, baseUrl, runtimeContext, } = context;
226
+ if (path !== "/mcp")
227
+ return null;
228
+ let admission;
229
+ try {
230
+ admission = await opts.requestAdmission.acquire({
231
+ signal: request.signal,
232
+ });
233
+ if (admission.waitMs > 0) {
234
+ opts.logger.debug("[connecta] MCP request admitted after queue wait", {
235
+ waitMs: admission.waitMs,
236
+ active: opts.requestAdmission.activeCount,
237
+ queued: opts.requestAdmission.queuedCount,
238
+ });
239
+ }
240
+ }
241
+ catch (error) {
242
+ if (error instanceof ExecutorAdmissionError &&
243
+ error.code === "executor_cancelled") {
244
+ throw request.signal.reason ?? error;
245
+ }
246
+ if (error instanceof ExecutorAdmissionError) {
247
+ if (error.code === "executor_overloaded") {
248
+ warnAdmissionRejected(error);
249
+ }
250
+ return withMcpCors(requestAdmissionFailure(error));
251
+ }
252
+ throw error;
253
+ }
254
+ try {
255
+ const authz = await authorize(request, baseUrl, opts.auth);
256
+ if (!authz.ok) {
257
+ return releaseAdmissionWithResponse(withMcpCors(authz.response), admission, request.signal);
258
+ }
259
+ if (new URL(request.url).searchParams.has("toolkit")) {
260
+ return releaseAdmissionWithResponse(withMcpCors(toolkitRetired(opts.logger)), admission, request.signal);
261
+ }
262
+ return releaseAdmissionWithResponse(withMcpCors(await serveMcp(request, opts, baseUrl, authz.actor, opts.registry, runtimeContext)), admission, request.signal);
263
+ }
264
+ catch (error) {
265
+ admission.release();
266
+ throw error;
267
+ }
268
+ };
269
+ }
270
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/routes/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type RouteContext } from "./shared.js";
2
+ export declare function routeOAuthManagement(context: RouteContext): Promise<Response | null>;
3
+ export declare function routeOAuthCallback(context: RouteContext): Promise<Response | null>;
4
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/routes/oauth.ts"],"names":[],"mappings":"AAQA,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAgGrB,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAS1B;AAyHD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA4E1B"}
@@ -0,0 +1,263 @@
1
+ import { oauthValueStorageKey } from "../auth/downstream-oauth.js";
2
+ import { closeConnectorScope } from "../connector-scope.js";
3
+ import { isSafeHttpUrl, resolveBranding } from "../ui.js";
4
+ import { authorizeUiAdmin, isSameOrigin, loggableValue, msg, privateJson, } from "./shared.js";
5
+ async function handleOAuthManagementRequest(context, connectorId) {
6
+ const { request, baseUrl, opts, defer } = context;
7
+ if (!isSameOrigin(request, baseUrl)) {
8
+ return privateJson({ error: "same-origin request required" }, { status: 403 });
9
+ }
10
+ const admin = await authorizeUiAdmin(request, baseUrl, opts.auth, "OAuth management");
11
+ if (!admin.ok)
12
+ return admin.response;
13
+ const connector = opts.registry.getConnector(connectorId);
14
+ if (!connector?.disconnectAuth || !connector.startAuth) {
15
+ return privateJson({ error: "unknown OAuth connector" }, { status: 404 });
16
+ }
17
+ if (request.method !== "DELETE" && request.method !== "POST") {
18
+ return privateJson({ error: "method not allowed" }, { status: 405 });
19
+ }
20
+ const requestScope = {};
21
+ const ctx = opts.registry.contextFor(connectorId, baseUrl, requestScope);
22
+ try {
23
+ let result;
24
+ let operationError;
25
+ try {
26
+ if (request.method === "DELETE") {
27
+ await connector.disconnectAuth(ctx);
28
+ }
29
+ else {
30
+ result = await connector.startAuth(ctx, { force: true });
31
+ }
32
+ }
33
+ catch (error) {
34
+ operationError = error;
35
+ }
36
+ // The old grant and its cached catalog are invalid after either operation,
37
+ // including a partially failed physical cleanup whose epoch fence succeeded.
38
+ try {
39
+ await opts.registry.invalidateStored(connectorId);
40
+ }
41
+ catch (error) {
42
+ operationError ??= error;
43
+ }
44
+ if (operationError) {
45
+ return privateJson({ error: msg(operationError) }, { status: 400 });
46
+ }
47
+ if (request.method === "DELETE") {
48
+ return new Response(null, {
49
+ status: 204,
50
+ headers: {
51
+ "Cache-Control": "no-store",
52
+ "Referrer-Policy": "no-referrer",
53
+ },
54
+ });
55
+ }
56
+ const authorizationUrl = isSafeHttpUrl(result.authorizationUrl)
57
+ ? result.authorizationUrl
58
+ : undefined;
59
+ if (result.state === "error") {
60
+ return privateJson({ error: result.message || "OAuth authorization could not start" }, { status: 502 });
61
+ }
62
+ if (result.state === "auth_required" && !authorizationUrl) {
63
+ return privateJson({
64
+ error: result.message ||
65
+ "OAuth authorization requires consent but no safe URL is available",
66
+ }, { status: 502 });
67
+ }
68
+ return privateJson({
69
+ state: result.state,
70
+ ...(result.message ? { message: result.message } : {}),
71
+ ...(authorizationUrl ? { authorizationUrl } : {}),
72
+ });
73
+ }
74
+ finally {
75
+ await closeConnectorScope(connector, ctx, defer);
76
+ }
77
+ }
78
+ export async function routeOAuthManagement(context) {
79
+ const match = /^\/ui\/oauth\/([a-z0-9_-]+)$/.exec(context.path);
80
+ if (!match)
81
+ return null;
82
+ const connectorId = match[1];
83
+ if (!connectorId)
84
+ return null;
85
+ if (context.request.method === "OPTIONS") {
86
+ return privateJson({ error: "method not allowed" }, { status: 405 });
87
+ }
88
+ return handleOAuthManagementRequest(context, connectorId);
89
+ }
90
+ function escapeHtml(value) {
91
+ return value
92
+ .replaceAll("&", "&amp;")
93
+ .replaceAll("<", "&lt;")
94
+ .replaceAll(">", "&gt;")
95
+ .replaceAll('"', "&quot;");
96
+ }
97
+ /** `body` is escaped — callback params and error messages are attacker-influenced. */
98
+ function html(body, status = 200, branding) {
99
+ const brand = resolveBranding(branding);
100
+ const title = brand.pageTitle;
101
+ const owner = brand.ownerName
102
+ ? brand.ownerUrl
103
+ ? `<a class="brand" href="${escapeHtml(brand.ownerUrl)}">${escapeHtml(brand.ownerName)}</a>`
104
+ : `<span class="brand">${escapeHtml(brand.ownerName)}</span>`
105
+ : brand.productUrl
106
+ ? `<a class="brand" href="${escapeHtml(brand.productUrl)}">${escapeHtml(brand.productName)}</a>`
107
+ : `<span class="brand">${escapeHtml(brand.productName)}</span>`;
108
+ const product = brand.ownerName
109
+ ? brand.productUrl
110
+ ? `<a class="product" href="${escapeHtml(brand.productUrl)}">${escapeHtml(brand.productName)}</a>`
111
+ : `<span class="product">${escapeHtml(brand.productName)}</span>`
112
+ : "";
113
+ return new Response(`<!doctype html>
114
+ <html lang="en">
115
+ <head>
116
+ <meta charset="utf-8">
117
+ <meta name="viewport" content="width=device-width,initial-scale=1">
118
+ <meta name="theme-color" content="${escapeHtml(brand.themeColor)}">
119
+ <link rel="icon" href="${escapeHtml(brand.faviconHref)}" type="image/svg+xml">
120
+ <link rel="shortcut icon" href="/favicon.ico">
121
+ <title>${escapeHtml(title)}</title>
122
+ <style>
123
+ * { border-radius: 0; box-sizing: border-box; }
124
+ html { color: #000; background: #fff; font: 16px/1.5 "Helvetica Neue",
125
+ Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
126
+ body { margin: 0; min-height: 100vh; }
127
+ ::selection { color: #fff; background: #000; }
128
+ .shell { margin: 0 auto; max-width: 70rem; padding: 1rem; }
129
+ .grid { display: grid; gap: 1rem 1.5rem;
130
+ grid-template-columns: repeat(3, minmax(0, 1fr)); }
131
+ .brand { font-weight: 500; grid-column: 1; text-decoration: none; }
132
+ .product { grid-column: 2 / -1; }
133
+ main { margin-top: 5rem; }
134
+ h1, p { font: inherit; margin: 0; }
135
+ h1 { grid-column: 1; }
136
+ .copy { grid-column: 2 / -1; max-width: 34em; }
137
+ .copy > * + * { margin-top: 1.5rem; }
138
+ a { color: inherit; text-decoration: underline; text-decoration-thickness: 1.5px;
139
+ text-underline-offset: .22em; }
140
+ a:hover { text-decoration-color: transparent; }
141
+ a:focus-visible { outline: 1px solid #000; outline-offset: 2px; }
142
+ @media (max-width: 36.99rem) {
143
+ .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
144
+ .product { grid-column: 2; }
145
+ main { margin-top: 3rem; }
146
+ h1, .copy { grid-column: 1 / -1; }
147
+ }
148
+ </style>
149
+ </head>
150
+ <body>
151
+ <header class="shell grid">
152
+ ${owner}
153
+ ${product}
154
+ </header>
155
+ <main class="shell grid">
156
+ <h1>Connection status</h1>
157
+ <div class="copy">
158
+ <p>${escapeHtml(body)}</p>
159
+ <p><a href="/">Return to ${escapeHtml(brand.productName)}</a></p>
160
+ </div>
161
+ </main>
162
+ </body>
163
+ </html>`, { status, headers: { "Content-Type": "text/html; charset=utf-8" } });
164
+ }
165
+ /**
166
+ * Pay the storage read a real downstream-OAuth refusal pays, on the refusal
167
+ * paths that would otherwise pay nothing.
168
+ *
169
+ * Identical bodies do not hide a connector id if the clock still sorts them.
170
+ * `KvOAuthProvider.verifyState` reads `oauth:state` and its generation before
171
+ * it can reject a mismatched value, so a configured id costs two storage round
172
+ * trips on the ordinary path while an id naming nothing used to touch no I/O.
173
+ * That gap is an oracle: sample the two and a wordlist recovers the connector
174
+ * list the flat 400 was meant to withhold. So zero-I/O refusals read the same
175
+ * keys in the same `conn:<id>:` namespace, where an unconfigured id gets misses.
176
+ *
177
+ * This is deliberately *not* a constant-time claim, and documentation/connectors.md says
178
+ * so in prose: a hit and a miss are not identical in a KV store, and a connector
179
+ * shipping its own `verifyState` may do more or less work. What it
180
+ * removes is the order-of-magnitude "no I/O versus a round trip" difference,
181
+ * which is the only part of the signal that makes enumeration cheap.
182
+ *
183
+ * A throwing read is swallowed: the refusal is the answer either way, and
184
+ * turning it into a 500 would hand back exactly the distinguishable response
185
+ * this whole path exists to deny.
186
+ */
187
+ async function equalizeRefusalCost(context) {
188
+ try {
189
+ const generation = await context.storage.get("oauth:generation");
190
+ await context.storage.get(oauthValueStorageKey("oauth:state", generation));
191
+ }
192
+ catch {
193
+ // Deliberately ignored — see above.
194
+ }
195
+ }
196
+ export async function routeOAuthCallback(context) {
197
+ const { path, url, baseUrl, opts } = context;
198
+ if (!path.startsWith("/oauth/callback/"))
199
+ return null;
200
+ const error = url.searchParams.get("error");
201
+ if (error)
202
+ return html(`Authorization denied: ${error}`, 400, opts.branding);
203
+ const code = url.searchParams.get("code");
204
+ if (!code)
205
+ return html("Missing authorization code.", 400, opts.branding);
206
+ const id = path.slice("/oauth/callback/".length);
207
+ const connector = opts.registry.getConnector(id);
208
+ // Safe to build before we know the id names anything: `contextFor` is a pure
209
+ // constructor — a namespaced storage view over `conn:<id>:` and, only for a
210
+ // connector that declares one, a lazy credential accessor. It neither throws
211
+ // nor touches storage for an unknown id, which is what lets the refusals
212
+ // below borrow it to equalize their cost.
213
+ const connectorContext = opts.registry.contextFor(id, baseUrl);
214
+ const refused = () => html("Authorization could not be completed. Re-run authorization from " +
215
+ "connecta and try again.", 400, opts.branding);
216
+ if (!connector || !connector.finishAuth) {
217
+ await equalizeRefusalCost(connectorContext);
218
+ return refused();
219
+ }
220
+ // CSRF / login-fixation guard: this route is intentionally public, so verify
221
+ // the `state` matches the flow connecta started BEFORE exchanging the code.
222
+ if (!connector.verifyState) {
223
+ await equalizeRefusalCost(connectorContext);
224
+ opts.logger.warn(`[connecta] refused an OAuth callback for connector ` +
225
+ `${loggableValue(id)} with 400: it implements finishAuth but no ` +
226
+ "verifyState, so connecta cannot establish that it started this flow. " +
227
+ "No authorization code was exchanged. Implement verifyState before " +
228
+ "trying again.");
229
+ return refused();
230
+ }
231
+ const state = url.searchParams.get("state");
232
+ let stateMatches;
233
+ try {
234
+ stateMatches = await connector.verifyState(state, connectorContext);
235
+ }
236
+ catch (err) {
237
+ opts.logger.warn(`[connecta] refused an OAuth callback for connector ` +
238
+ `${loggableValue(id)} with 400: verifyState threw ` +
239
+ `${loggableValue(msg(err))}. No authorization code was exchanged. ` +
240
+ "Re-run authorization from connecta and check the verifier if it " +
241
+ "fails again.");
242
+ return refused();
243
+ }
244
+ if (!stateMatches) {
245
+ opts.logger.warn(`[connecta] refused an OAuth callback for connector ` +
246
+ `${loggableValue(id)} with 400: ` +
247
+ (state === null
248
+ ? "the state parameter was missing"
249
+ : "the state did not match the pending authorization flow") +
250
+ ". No authorization code was exchanged. Re-run authorization from " +
251
+ "connecta and try again.");
252
+ return refused();
253
+ }
254
+ try {
255
+ await connector.finishAuth(code, connectorContext);
256
+ await opts.registry.invalidateStored(id);
257
+ return html(`Connected "${id}". You can close this window.`, 200, opts.branding);
258
+ }
259
+ catch (err) {
260
+ return html(`Authorization failed: ${msg(err)}`, 500, opts.branding);
261
+ }
262
+ }
263
+ //# sourceMappingURL=oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/routes/oauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ActivityActor, ActivityReadGate, ActivityStore } from "../activity.js";
3
+ import type { CredentialVault } from "../credentials.js";
4
+ import type { DeferredWork } from "../connector-scope.js";
5
+ import type { AdmissionController } from "../executor-admission.js";
6
+ import type { Registry } from "../registry.js";
7
+ import type { ConnectaBranding, Executor, InboundAuth, Logger } from "../types.js";
8
+ export interface ServerOptions {
9
+ registry: Registry;
10
+ auth: InboundAuth[];
11
+ publicUrl?: string;
12
+ serverInfo: ConstructorParameters<typeof McpServer>[0];
13
+ logger: Logger;
14
+ activity?: ActivityStore;
15
+ activityReadGate?: ActivityReadGate;
16
+ activityDeploymentId?: string;
17
+ deploymentInfo?: Record<string, unknown>;
18
+ /** Deadline for call_tool/batch_call calls that pass no timeoutMs. Off when unset. */
19
+ defaultToolTimeoutMs?: number;
20
+ /** Per-connector deadline for the list/search/describe probe fan-out. Default 30_000. */
21
+ probeTimeoutMs?: number;
22
+ /** Maximum simultaneous connector discovery operations. Default 4. */
23
+ discoveryConcurrency?: number;
24
+ /** When set, the execute_code meta-tool is registered on top of the nine. */
25
+ executor?: Executor;
26
+ /** Global FIFO boundary for all non-preflight `/mcp` requests. */
27
+ requestAdmission: AdmissionController;
28
+ /** Encrypted connector-credential storage backing the Credentials page. */
29
+ credentialVault?: CredentialVault;
30
+ /** Optional browser UI and OAuth result-page labels. */
31
+ branding?: ConnectaBranding;
32
+ }
33
+ export interface RuntimeExecutionContext {
34
+ waitUntil(promise: Promise<unknown>): void;
35
+ }
36
+ export interface RouteContext {
37
+ request: Request;
38
+ url: URL;
39
+ path: string;
40
+ baseUrl: string;
41
+ opts: ServerOptions;
42
+ defer: DeferredWork | undefined;
43
+ runtimeContext: RuntimeExecutionContext | undefined;
44
+ }
45
+ export declare function msg(err: unknown): string;
46
+ export declare function privateJson(body: unknown, init?: ResponseInit): Response;
47
+ /**
48
+ * Bounded, escaped form of a caller-influenced value (an identity id or OAuth
49
+ * callback connector id) for the operator log. Goes
50
+ * through JSON.stringify so a caller-controlled newline or control character
51
+ * cannot forge a log line, plus a hand-rolled escape for U+2028/U+2029, which
52
+ * JSON.stringify leaves raw even though a log reader treats them as line
53
+ * terminators. Truncated to a small shared cap so an oversized value cannot
54
+ * flood the log either.
55
+ */
56
+ export declare function loggableValue(requested: string): string;
57
+ export declare function activityActorNamespace(provider: InboundAuth): string | undefined;
58
+ export declare function authorize(request: Request, baseUrl: string, auth: InboundAuth[]): Promise<{
59
+ ok: true;
60
+ actor: ActivityActor;
61
+ /** True only when the admitting provider can also authorize UI mutation. */
62
+ uiAdminEligible?: boolean;
63
+ } | {
64
+ ok: false;
65
+ response: Response;
66
+ }>;
67
+ export declare function authorizeUiAdmin(request: Request, baseUrl: string, auth: InboundAuth[], purpose?: string): Promise<{
68
+ ok: true;
69
+ userId: string;
70
+ } | {
71
+ ok: false;
72
+ response: Response;
73
+ }>;
74
+ export declare function isSameOrigin(request: Request, baseUrl: string): boolean;
75
+ export declare function withSecurityHeaders(response: Response, requestUrl: URL, path: string): Response;
76
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/routes/shared.ts"],"names":[],"mappings":"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"}