agents 0.0.0-956c772 → 0.0.0-9688c15

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.
@@ -0,0 +1,133 @@
1
+ import {
2
+ __privateAdd,
3
+ __privateGet,
4
+ __privateSet
5
+ } from "./chunk-HMLY7DHA.js";
6
+
7
+ // src/client.ts
8
+ import {
9
+ PartySocket
10
+ } from "partysocket";
11
+ function camelCaseToKebabCase(str) {
12
+ if (str === str.toUpperCase() && str !== str.toLowerCase()) {
13
+ return str.toLowerCase().replace(/_/g, "-");
14
+ }
15
+ let kebabified = str.replace(
16
+ /[A-Z]/g,
17
+ (letter) => `-${letter.toLowerCase()}`
18
+ );
19
+ kebabified = kebabified.startsWith("-") ? kebabified.slice(1) : kebabified;
20
+ return kebabified.replace(/_/g, "-").replace(/-$/, "");
21
+ }
22
+ var _options, _pendingCalls;
23
+ var AgentClient = class extends PartySocket {
24
+ constructor(options) {
25
+ const agentNamespace = camelCaseToKebabCase(options.agent);
26
+ super({
27
+ prefix: "agents",
28
+ party: agentNamespace,
29
+ room: options.name || "default",
30
+ ...options
31
+ });
32
+ __privateAdd(this, _options);
33
+ __privateAdd(this, _pendingCalls, /* @__PURE__ */ new Map());
34
+ this.agent = agentNamespace;
35
+ this.name = options.name || "default";
36
+ __privateSet(this, _options, options);
37
+ this.addEventListener("message", (event) => {
38
+ if (typeof event.data === "string") {
39
+ let parsedMessage;
40
+ try {
41
+ parsedMessage = JSON.parse(event.data);
42
+ } catch (error) {
43
+ return;
44
+ }
45
+ if (parsedMessage.type === "cf_agent_state") {
46
+ __privateGet(this, _options).onStateUpdate?.(parsedMessage.state, "server");
47
+ return;
48
+ }
49
+ if (parsedMessage.type === "rpc") {
50
+ const response = parsedMessage;
51
+ const pending = __privateGet(this, _pendingCalls).get(response.id);
52
+ if (!pending) return;
53
+ if (!response.success) {
54
+ pending.reject(new Error(response.error));
55
+ __privateGet(this, _pendingCalls).delete(response.id);
56
+ pending.stream?.onError?.(response.error);
57
+ return;
58
+ }
59
+ if ("done" in response) {
60
+ if (response.done) {
61
+ pending.resolve(response.result);
62
+ __privateGet(this, _pendingCalls).delete(response.id);
63
+ pending.stream?.onDone?.(response.result);
64
+ } else {
65
+ pending.stream?.onChunk?.(response.result);
66
+ }
67
+ } else {
68
+ pending.resolve(response.result);
69
+ __privateGet(this, _pendingCalls).delete(response.id);
70
+ }
71
+ }
72
+ }
73
+ });
74
+ }
75
+ /**
76
+ * @deprecated Use agentFetch instead
77
+ */
78
+ static fetch(_opts) {
79
+ throw new Error(
80
+ "AgentClient.fetch is not implemented, use agentFetch instead"
81
+ );
82
+ }
83
+ setState(state) {
84
+ this.send(JSON.stringify({ type: "cf_agent_state", state }));
85
+ __privateGet(this, _options).onStateUpdate?.(state, "client");
86
+ }
87
+ /**
88
+ * Call a method on the Agent
89
+ * @param method Name of the method to call
90
+ * @param args Arguments to pass to the method
91
+ * @param streamOptions Options for handling streaming responses
92
+ * @returns Promise that resolves with the method's return value
93
+ */
94
+ async call(method, args = [], streamOptions) {
95
+ return new Promise((resolve, reject) => {
96
+ const id = Math.random().toString(36).slice(2);
97
+ __privateGet(this, _pendingCalls).set(id, {
98
+ resolve: (value) => resolve(value),
99
+ reject,
100
+ stream: streamOptions,
101
+ type: null
102
+ });
103
+ const request = {
104
+ type: "rpc",
105
+ id,
106
+ method,
107
+ args
108
+ };
109
+ this.send(JSON.stringify(request));
110
+ });
111
+ }
112
+ };
113
+ _options = new WeakMap();
114
+ _pendingCalls = new WeakMap();
115
+ function agentFetch(opts, init) {
116
+ const agentNamespace = camelCaseToKebabCase(opts.agent);
117
+ return PartySocket.fetch(
118
+ {
119
+ prefix: "agents",
120
+ party: agentNamespace,
121
+ room: opts.name || "default",
122
+ ...opts
123
+ },
124
+ init
125
+ );
126
+ }
127
+
128
+ export {
129
+ camelCaseToKebabCase,
130
+ AgentClient,
131
+ agentFetch
132
+ };
133
+ //# sourceMappingURL=chunk-RN4SNE73.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import {\n PartySocket,\n type PartySocketOptions,\n type PartyFetchOptions,\n} from \"partysocket\";\nimport type { RPCRequest, RPCResponse } from \"./\";\n\n/**\n * Options for creating an AgentClient\n */\nexport type AgentClientOptions<State = unknown> = Omit<\n PartySocketOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to */\n agent: string;\n /** Name of the specific Agent instance */\n name?: string;\n /** Called when the Agent's state is updated */\n onStateUpdate?: (state: State, source: \"server\" | \"client\") => void;\n};\n\n/**\n * Options for streaming RPC calls\n */\nexport type StreamOptions = {\n /** Called when a chunk of data is received */\n onChunk?: (chunk: unknown) => void;\n /** Called when the stream ends */\n onDone?: (finalChunk: unknown) => void;\n /** Called when an error occurs */\n onError?: (error: string) => void;\n};\n\n/**\n * Options for the agentFetch function\n */\nexport type AgentClientFetchOptions = Omit<\n PartyFetchOptions,\n \"party\" | \"room\"\n> & {\n /** Name of the agent to connect to */\n agent: string;\n /** Name of the specific Agent instance */\n name?: string;\n};\n\n/**\n * Convert a camelCase string to a kebab-case string\n * @param str The string to convert\n * @returns The kebab-case string\n */\nexport function camelCaseToKebabCase(str: string): string {\n // If string is all uppercase, convert to lowercase\n if (str === str.toUpperCase() && str !== str.toLowerCase()) {\n return str.toLowerCase().replace(/_/g, \"-\");\n }\n\n // Otherwise handle camelCase to kebab-case\n let kebabified = str.replace(\n /[A-Z]/g,\n (letter) => `-${letter.toLowerCase()}`\n );\n kebabified = kebabified.startsWith(\"-\") ? kebabified.slice(1) : kebabified;\n // Convert any remaining underscores to hyphens and remove trailing -'s\n return kebabified.replace(/_/g, \"-\").replace(/-$/, \"\");\n}\n\n/**\n * WebSocket client for connecting to an Agent\n */\nexport class AgentClient<State = unknown> extends PartySocket {\n /**\n * @deprecated Use agentFetch instead\n */\n static fetch(_opts: PartyFetchOptions): Promise<Response> {\n throw new Error(\n \"AgentClient.fetch is not implemented, use agentFetch instead\"\n );\n }\n agent: string;\n name: string;\n #options: AgentClientOptions<State>;\n #pendingCalls = new Map<\n string,\n {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n stream?: StreamOptions;\n type?: unknown;\n }\n >();\n\n constructor(options: AgentClientOptions<State>) {\n const agentNamespace = camelCaseToKebabCase(options.agent);\n super({\n prefix: \"agents\",\n party: agentNamespace,\n room: options.name || \"default\",\n ...options,\n });\n this.agent = agentNamespace;\n this.name = options.name || \"default\";\n this.#options = options;\n\n this.addEventListener(\"message\", (event) => {\n if (typeof event.data === \"string\") {\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(event.data);\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (parsedMessage.type === \"cf_agent_state\") {\n this.#options.onStateUpdate?.(parsedMessage.state as State, \"server\");\n return;\n }\n if (parsedMessage.type === \"rpc\") {\n const response = parsedMessage as RPCResponse;\n const pending = this.#pendingCalls.get(response.id);\n if (!pending) return;\n\n if (!response.success) {\n pending.reject(new Error(response.error));\n this.#pendingCalls.delete(response.id);\n pending.stream?.onError?.(response.error);\n return;\n }\n\n // Handle streaming responses\n if (\"done\" in response) {\n if (response.done) {\n pending.resolve(response.result);\n this.#pendingCalls.delete(response.id);\n pending.stream?.onDone?.(response.result);\n } else {\n pending.stream?.onChunk?.(response.result);\n }\n } else {\n // Non-streaming response\n pending.resolve(response.result);\n this.#pendingCalls.delete(response.id);\n }\n }\n }\n });\n }\n\n setState(state: State) {\n this.send(JSON.stringify({ type: \"cf_agent_state\", state }));\n this.#options.onStateUpdate?.(state, \"client\");\n }\n\n /**\n * Call a method on the Agent\n * @param method Name of the method to call\n * @param args Arguments to pass to the method\n * @param streamOptions Options for handling streaming responses\n * @returns Promise that resolves with the method's return value\n */\n async call<T = unknown>(\n method: string,\n args: unknown[] = [],\n streamOptions?: StreamOptions\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const id = Math.random().toString(36).slice(2);\n this.#pendingCalls.set(id, {\n resolve: (value: unknown) => resolve(value as T),\n reject,\n stream: streamOptions,\n type: null as T,\n });\n\n const request: RPCRequest = {\n type: \"rpc\",\n id,\n method,\n args,\n };\n\n this.send(JSON.stringify(request));\n });\n }\n}\n\n/**\n * Make an HTTP request to an Agent\n * @param opts Connection options\n * @param init Request initialization options\n * @returns Promise resolving to a Response\n */\nexport function agentFetch(opts: AgentClientFetchOptions, init?: RequestInit) {\n const agentNamespace = camelCaseToKebabCase(opts.agent);\n\n return PartySocket.fetch(\n {\n prefix: \"agents\",\n party: agentNamespace,\n room: opts.name || \"default\",\n ...opts,\n },\n init\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,3 +1,12 @@
1
+ import {
2
+ DurableObjectOAuthClientProvider
3
+ } from "./chunk-D6UOOELW.js";
4
+ import {
5
+ camelCaseToKebabCase
6
+ } from "./chunk-RN4SNE73.js";
7
+ import {
8
+ MCPClientManager
9
+ } from "./chunk-25YDMV4H.js";
1
10
  import {
2
11
  __privateAdd,
3
12
  __privateGet,
@@ -14,7 +23,6 @@ import {
14
23
  import { parseCronExpression } from "cron-schedule";
15
24
  import { nanoid } from "nanoid";
16
25
  import { AsyncLocalStorage } from "node:async_hooks";
17
- import { WorkflowEntrypoint as CFWorkflowEntrypoint } from "cloudflare:workers";
18
26
  function isRPCRequest(msg) {
19
27
  return typeof msg === "object" && msg !== null && "type" in msg && msg.type === "rpc" && "id" in msg && typeof msg.id === "string" && "method" in msg && typeof msg.method === "string" && "args" in msg && Array.isArray(msg.args);
20
28
  }
@@ -30,8 +38,6 @@ function unstable_callable(metadata = {}) {
30
38
  return target;
31
39
  };
32
40
  }
33
- var WorkflowEntrypoint = class extends CFWorkflowEntrypoint {
34
- };
35
41
  function getNextCronTime(cron) {
36
42
  const interval = parseCronExpression(cron);
37
43
  return interval.getNextDate();
@@ -39,18 +45,74 @@ function getNextCronTime(cron) {
39
45
  var STATE_ROW_ID = "cf_state_row_id";
40
46
  var STATE_WAS_CHANGED = "cf_state_was_changed";
41
47
  var DEFAULT_STATE = {};
42
- var unstable_context = new AsyncLocalStorage();
43
- var _state, _Agent_instances, setStateInternal_fn, tryCatch_fn, scheduleNextAlarm_fn, isCallable_fn;
48
+ var agentContext = new AsyncLocalStorage();
49
+ function getCurrentAgent() {
50
+ const store = agentContext.getStore();
51
+ if (!store) {
52
+ return {
53
+ agent: void 0,
54
+ connection: void 0,
55
+ request: void 0
56
+ };
57
+ }
58
+ return store;
59
+ }
60
+ var _state, _ParentClass, _Agent_instances, setStateInternal_fn, tryCatch_fn, scheduleNextAlarm_fn, isCallable_fn, connectToMcpServerInternal_fn, getMcpServerStateInternal_fn;
44
61
  var Agent = class extends Server {
45
62
  constructor(ctx, env) {
46
63
  super(ctx, env);
47
64
  __privateAdd(this, _Agent_instances);
48
65
  __privateAdd(this, _state, DEFAULT_STATE);
66
+ __privateAdd(this, _ParentClass, Object.getPrototypeOf(this).constructor);
67
+ this.mcp = new MCPClientManager(__privateGet(this, _ParentClass).name, "0.0.1");
49
68
  /**
50
69
  * Initial state for the Agent
51
70
  * Override to provide default state values
52
71
  */
53
72
  this.initialState = DEFAULT_STATE;
73
+ /**
74
+ * Method called when an alarm fires.
75
+ * Executes any scheduled tasks that are due.
76
+ *
77
+ * @remarks
78
+ * To schedule a task, please use the `this.schedule` method instead.
79
+ * See {@link https://developers.cloudflare.com/agents/api-reference/schedule-tasks/}
80
+ */
81
+ this.alarm = async () => {
82
+ const now = Math.floor(Date.now() / 1e3);
83
+ const result = this.sql`
84
+ SELECT * FROM cf_agents_schedules WHERE time <= ${now}
85
+ `;
86
+ for (const row of result || []) {
87
+ const callback = this[row.callback];
88
+ if (!callback) {
89
+ console.error(`callback ${row.callback} not found`);
90
+ continue;
91
+ }
92
+ await agentContext.run(
93
+ { agent: this, connection: void 0, request: void 0 },
94
+ async () => {
95
+ try {
96
+ await callback.bind(this)(JSON.parse(row.payload), row);
97
+ } catch (e) {
98
+ console.error(`error executing callback "${row.callback}"`, e);
99
+ }
100
+ }
101
+ );
102
+ if (row.type === "cron") {
103
+ const nextExecutionTime = getNextCronTime(row.cron);
104
+ const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
105
+ this.sql`
106
+ UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
107
+ `;
108
+ } else {
109
+ this.sql`
110
+ DELETE FROM cf_agents_schedules WHERE id = ${row.id}
111
+ `;
112
+ }
113
+ }
114
+ await __privateMethod(this, _Agent_instances, scheduleNextAlarm_fn).call(this);
115
+ };
54
116
  this.sql`
55
117
  CREATE TABLE IF NOT EXISTS cf_agents_state (
56
118
  id TEXT PRIMARY KEY NOT NULL,
@@ -74,9 +136,42 @@ var Agent = class extends Server {
74
136
  await this.alarm();
75
137
  });
76
138
  });
139
+ this.sql`
140
+ CREATE TABLE IF NOT EXISTS cf_agents_mcp_servers (
141
+ id TEXT PRIMARY KEY NOT NULL,
142
+ name TEXT NOT NULL,
143
+ server_url TEXT NOT NULL,
144
+ callback_url TEXT NOT NULL,
145
+ client_id TEXT,
146
+ auth_url TEXT,
147
+ server_options TEXT
148
+ )
149
+ `;
150
+ const _onRequest = this.onRequest.bind(this);
151
+ this.onRequest = (request) => {
152
+ return agentContext.run(
153
+ { agent: this, connection: void 0, request },
154
+ async () => {
155
+ if (this.mcp.isCallbackRequest(request)) {
156
+ await this.mcp.handleCallbackRequest(request);
157
+ this.broadcast(
158
+ JSON.stringify({
159
+ type: "cf_agent_mcp_servers",
160
+ mcp: __privateMethod(this, _Agent_instances, getMcpServerStateInternal_fn).call(this)
161
+ })
162
+ );
163
+ return new Response("<script>window.close();</script>", {
164
+ status: 200,
165
+ headers: { "content-type": "text/html" }
166
+ });
167
+ }
168
+ return __privateMethod(this, _Agent_instances, tryCatch_fn).call(this, () => _onRequest(request));
169
+ }
170
+ );
171
+ };
77
172
  const _onMessage = this.onMessage.bind(this);
78
173
  this.onMessage = async (connection, message) => {
79
- return unstable_context.run(
174
+ return agentContext.run(
80
175
  { agent: this, connection, request: void 0 },
81
176
  async () => {
82
177
  if (typeof message !== "string") {
@@ -135,7 +230,7 @@ var Agent = class extends Server {
135
230
  };
136
231
  const _onConnect = this.onConnect.bind(this);
137
232
  this.onConnect = (connection, ctx2) => {
138
- return unstable_context.run(
233
+ return agentContext.run(
139
234
  { agent: this, connection, request: ctx2.request },
140
235
  async () => {
141
236
  setTimeout(() => {
@@ -147,11 +242,43 @@ var Agent = class extends Server {
147
242
  })
148
243
  );
149
244
  }
245
+ connection.send(
246
+ JSON.stringify({
247
+ type: "cf_agent_mcp_servers",
248
+ mcp: __privateMethod(this, _Agent_instances, getMcpServerStateInternal_fn).call(this)
249
+ })
250
+ );
150
251
  return __privateMethod(this, _Agent_instances, tryCatch_fn).call(this, () => _onConnect(connection, ctx2));
151
252
  }, 20);
152
253
  }
153
254
  );
154
255
  };
256
+ const _onStart = this.onStart.bind(this);
257
+ this.onStart = async () => {
258
+ return agentContext.run(
259
+ { agent: this, connection: void 0, request: void 0 },
260
+ async () => {
261
+ const servers = this.sql`
262
+ SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
263
+ `;
264
+ await Promise.allSettled(
265
+ servers.map((server) => {
266
+ return __privateMethod(this, _Agent_instances, connectToMcpServerInternal_fn).call(this, server.name, server.server_url, server.callback_url, server.server_options ? JSON.parse(server.server_options) : void 0, {
267
+ id: server.id,
268
+ oauthClientId: server.client_id ?? void 0
269
+ });
270
+ })
271
+ );
272
+ this.broadcast(
273
+ JSON.stringify({
274
+ type: "cf_agent_mcp_servers",
275
+ mcp: __privateMethod(this, _Agent_instances, getMcpServerStateInternal_fn).call(this)
276
+ })
277
+ );
278
+ await __privateMethod(this, _Agent_instances, tryCatch_fn).call(this, () => _onStart());
279
+ }
280
+ );
281
+ };
155
282
  }
156
283
  /**
157
284
  * Current state of the Agent
@@ -217,7 +344,7 @@ var Agent = class extends Server {
217
344
  * @param email Email message to process
218
345
  */
219
346
  onEmail(email) {
220
- return unstable_context.run(
347
+ return agentContext.run(
221
348
  { agent: this, connection: void 0, request: void 0 },
222
349
  async () => {
223
350
  console.error("onEmail not implemented");
@@ -380,56 +507,51 @@ var Agent = class extends Server {
380
507
  await __privateMethod(this, _Agent_instances, scheduleNextAlarm_fn).call(this);
381
508
  return true;
382
509
  }
383
- /**
384
- * Method called when an alarm fires
385
- * Executes any scheduled tasks that are due
386
- */
387
- async alarm() {
388
- const now = Math.floor(Date.now() / 1e3);
389
- const result = this.sql`
390
- SELECT * FROM cf_agents_schedules WHERE time <= ${now}
391
- `;
392
- for (const row of result || []) {
393
- const callback = this[row.callback];
394
- if (!callback) {
395
- console.error(`callback ${row.callback} not found`);
396
- continue;
397
- }
398
- await unstable_context.run(
399
- { agent: this, connection: void 0, request: void 0 },
400
- async () => {
401
- try {
402
- await callback.bind(this)(JSON.parse(row.payload), row);
403
- } catch (e) {
404
- console.error(`error executing callback "${row.callback}"`, e);
405
- }
406
- }
407
- );
408
- if (row.type === "cron") {
409
- const nextExecutionTime = getNextCronTime(row.cron);
410
- const nextTimestamp = Math.floor(nextExecutionTime.getTime() / 1e3);
411
- this.sql`
412
- UPDATE cf_agents_schedules SET time = ${nextTimestamp} WHERE id = ${row.id}
413
- `;
414
- } else {
415
- this.sql`
416
- DELETE FROM cf_agents_schedules WHERE id = ${row.id}
417
- `;
418
- }
419
- }
420
- await __privateMethod(this, _Agent_instances, scheduleNextAlarm_fn).call(this);
421
- }
422
510
  /**
423
511
  * Destroy the Agent, removing all state and scheduled tasks
424
512
  */
425
513
  async destroy() {
426
514
  this.sql`DROP TABLE IF EXISTS cf_agents_state`;
427
515
  this.sql`DROP TABLE IF EXISTS cf_agents_schedules`;
516
+ this.sql`DROP TABLE IF EXISTS cf_agents_mcp_servers`;
428
517
  await this.ctx.storage.deleteAlarm();
429
518
  await this.ctx.storage.deleteAll();
430
519
  }
520
+ /**
521
+ * Connect to a new MCP Server
522
+ *
523
+ * @param url MCP Server SSE URL
524
+ * @param callbackHost Base host for the agent, used for the redirect URI.
525
+ * @param agentsPrefix agents routing prefix if not using `agents`
526
+ * @param options MCP client and transport (header) options
527
+ * @returns authUrl
528
+ */
529
+ async addMcpServer(serverName, url, callbackHost, agentsPrefix = "agents", options) {
530
+ const callbackUrl = `${callbackHost}/${agentsPrefix}/${camelCaseToKebabCase(__privateGet(this, _ParentClass).name)}/${this.name}/callback`;
531
+ const result = await __privateMethod(this, _Agent_instances, connectToMcpServerInternal_fn).call(this, serverName, url, callbackUrl, options);
532
+ this.broadcast(
533
+ JSON.stringify({
534
+ type: "cf_agent_mcp_servers",
535
+ mcp: __privateMethod(this, _Agent_instances, getMcpServerStateInternal_fn).call(this)
536
+ })
537
+ );
538
+ return result;
539
+ }
540
+ async removeMcpServer(id) {
541
+ this.mcp.closeConnection(id);
542
+ this.sql`
543
+ DELETE FROM cf_agents_mcp_servers WHERE id = ${id};
544
+ `;
545
+ this.broadcast(
546
+ JSON.stringify({
547
+ type: "cf_agent_mcp_servers",
548
+ mcp: __privateMethod(this, _Agent_instances, getMcpServerStateInternal_fn).call(this)
549
+ })
550
+ );
551
+ }
431
552
  };
432
553
  _state = new WeakMap();
554
+ _ParentClass = new WeakMap();
433
555
  _Agent_instances = new WeakSet();
434
556
  setStateInternal_fn = function(state, source = "server") {
435
557
  __privateSet(this, _state, state);
@@ -449,8 +571,8 @@ setStateInternal_fn = function(state, source = "server") {
449
571
  source !== "server" ? [source.id] : []
450
572
  );
451
573
  return __privateMethod(this, _Agent_instances, tryCatch_fn).call(this, () => {
452
- const { connection, request } = unstable_context.getStore() || {};
453
- return unstable_context.run(
574
+ const { connection, request } = agentContext.getStore() || {};
575
+ return agentContext.run(
454
576
  { agent: this, connection, request },
455
577
  async () => {
456
578
  return this.onStateUpdate(state, source);
@@ -485,6 +607,77 @@ scheduleNextAlarm_fn = async function() {
485
607
  isCallable_fn = function(method) {
486
608
  return callableMetadata.has(this[method]);
487
609
  };
610
+ connectToMcpServerInternal_fn = async function(serverName, url, callbackUrl, options, reconnect) {
611
+ const authProvider = new DurableObjectOAuthClientProvider(
612
+ this.ctx.storage,
613
+ this.name,
614
+ callbackUrl
615
+ );
616
+ if (reconnect) {
617
+ authProvider.serverId = reconnect.id;
618
+ if (reconnect.oauthClientId) {
619
+ authProvider.clientId = reconnect.oauthClientId;
620
+ }
621
+ }
622
+ let headerTransportOpts = {};
623
+ if (options?.transport?.headers) {
624
+ headerTransportOpts = {
625
+ eventSourceInit: {
626
+ fetch: (url2, init) => fetch(url2, {
627
+ ...init,
628
+ headers: options?.transport?.headers
629
+ })
630
+ },
631
+ requestInit: {
632
+ headers: options?.transport?.headers
633
+ }
634
+ };
635
+ }
636
+ const { id, authUrl, clientId } = await this.mcp.connect(url, {
637
+ reconnect,
638
+ transport: {
639
+ ...headerTransportOpts,
640
+ authProvider
641
+ },
642
+ client: options?.client
643
+ });
644
+ this.sql`
645
+ INSERT OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
646
+ VALUES (
647
+ ${id},
648
+ ${serverName},
649
+ ${url},
650
+ ${clientId ?? null},
651
+ ${authUrl ?? null},
652
+ ${callbackUrl},
653
+ ${options ? JSON.stringify(options) : null}
654
+ );
655
+ `;
656
+ return {
657
+ id,
658
+ authUrl
659
+ };
660
+ };
661
+ getMcpServerStateInternal_fn = function() {
662
+ const mcpState = {
663
+ servers: {},
664
+ tools: this.mcp.listTools(),
665
+ prompts: this.mcp.listPrompts(),
666
+ resources: this.mcp.listResources()
667
+ };
668
+ const servers = this.sql`
669
+ SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
670
+ `;
671
+ for (const server of servers) {
672
+ mcpState.servers[server.id] = {
673
+ name: server.name,
674
+ server_url: server.server_url,
675
+ auth_url: server.auth_url,
676
+ state: this.mcp.mcpConnections[server.id].connectionState
677
+ };
678
+ }
679
+ return mcpState;
680
+ };
488
681
  /**
489
682
  * Agent configuration options
490
683
  */
@@ -530,7 +723,7 @@ async function routeAgentRequest(request, env, options) {
530
723
  }
531
724
  async function routeAgentEmail(email, env, options) {
532
725
  }
533
- function getAgentByName(namespace, name, options) {
726
+ async function getAgentByName(namespace, name, options) {
534
727
  return getServerByName(namespace, name, options);
535
728
  }
536
729
  var _connection, _id, _closed;
@@ -584,12 +777,11 @@ _closed = new WeakMap();
584
777
 
585
778
  export {
586
779
  unstable_callable,
587
- WorkflowEntrypoint,
588
- unstable_context,
780
+ getCurrentAgent,
589
781
  Agent,
590
782
  routeAgentRequest,
591
783
  routeAgentEmail,
592
784
  getAgentByName,
593
785
  StreamingResponse
594
786
  };
595
- //# sourceMappingURL=chunk-YMUU7QHV.js.map
787
+ //# sourceMappingURL=chunk-YFPCCSZO.js.map