agents 0.0.0-197e86a → 0.0.0-1bd0c75

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 (71) hide show
  1. package/README.md +129 -7
  2. package/dist/_esm-LV5FJ3HK.js +3922 -0
  3. package/dist/_esm-LV5FJ3HK.js.map +1 -0
  4. package/dist/ai-chat-agent.d.ts +10 -8
  5. package/dist/ai-chat-agent.js +444 -60
  6. package/dist/ai-chat-agent.js.map +1 -1
  7. package/dist/ai-chat-v5-migration.d.ts +152 -0
  8. package/dist/ai-chat-v5-migration.js +20 -0
  9. package/dist/ai-chat-v5-migration.js.map +1 -0
  10. package/dist/ai-react.d.ts +66 -70
  11. package/dist/ai-react.js +252 -99
  12. package/dist/ai-react.js.map +1 -1
  13. package/dist/ai-types.d.ts +37 -19
  14. package/dist/ai-types.js +7 -0
  15. package/dist/ccip-CMBYN64O.js +15 -0
  16. package/dist/ccip-CMBYN64O.js.map +1 -0
  17. package/dist/chunk-5Y6BEZDY.js +276 -0
  18. package/dist/chunk-5Y6BEZDY.js.map +1 -0
  19. package/dist/chunk-BER7KXUJ.js +18 -0
  20. package/dist/chunk-BER7KXUJ.js.map +1 -0
  21. package/dist/{chunk-PVQZBKN7.js → chunk-C2OEBJZ2.js} +14 -7
  22. package/dist/chunk-C2OEBJZ2.js.map +1 -0
  23. package/dist/chunk-JJBFIGUC.js +5202 -0
  24. package/dist/chunk-JJBFIGUC.js.map +1 -0
  25. package/dist/chunk-PR4QN5HX.js +43 -0
  26. package/dist/chunk-PR4QN5HX.js.map +1 -0
  27. package/dist/{chunk-KUH345EY.js → chunk-QEVM4BVL.js} +5 -5
  28. package/dist/chunk-QEVM4BVL.js.map +1 -0
  29. package/dist/chunk-TYAY6AU6.js +159 -0
  30. package/dist/chunk-TYAY6AU6.js.map +1 -0
  31. package/dist/chunk-UJVEAURM.js +150 -0
  32. package/dist/chunk-UJVEAURM.js.map +1 -0
  33. package/dist/{chunk-JXN5WZFQ.js → chunk-XGMKNUJA.js} +173 -117
  34. package/dist/chunk-XGMKNUJA.js.map +1 -0
  35. package/dist/{chunk-HY7ZLHJB.js → chunk-ZMMHNOMZ.js} +415 -71
  36. package/dist/chunk-ZMMHNOMZ.js.map +1 -0
  37. package/dist/{client-DgyzBU_8.d.ts → client-DVoPb3-C.d.ts} +555 -36
  38. package/dist/client.js +3 -1
  39. package/dist/codemode/ai.d.ts +25 -0
  40. package/dist/codemode/ai.js +5109 -0
  41. package/dist/codemode/ai.js.map +1 -0
  42. package/dist/index.d.ts +548 -32
  43. package/dist/index.js +8 -4
  44. package/dist/mcp/client.d.ts +2 -1
  45. package/dist/mcp/client.js +2 -1
  46. package/dist/mcp/do-oauth-client-provider.d.ts +1 -0
  47. package/dist/mcp/do-oauth-client-provider.js +2 -1
  48. package/dist/mcp/index.d.ts +50 -83
  49. package/dist/mcp/index.js +904 -760
  50. package/dist/mcp/index.js.map +1 -1
  51. package/dist/mcp/x402.d.ts +39 -0
  52. package/dist/mcp/x402.js +3195 -0
  53. package/dist/mcp/x402.js.map +1 -0
  54. package/dist/mcp-BH1fJeiU.d.ts +58 -0
  55. package/dist/observability/index.d.ts +34 -14
  56. package/dist/observability/index.js +6 -4
  57. package/dist/react.d.ts +13 -7
  58. package/dist/react.js +107 -7
  59. package/dist/react.js.map +1 -1
  60. package/dist/schedule.d.ts +79 -5
  61. package/dist/schedule.js +17 -2
  62. package/dist/schedule.js.map +1 -1
  63. package/dist/secp256k1-M22GZP2U.js +2193 -0
  64. package/dist/secp256k1-M22GZP2U.js.map +1 -0
  65. package/package.json +30 -7
  66. package/src/index.ts +251 -137
  67. package/dist/chunk-HY7ZLHJB.js.map +0 -1
  68. package/dist/chunk-JXN5WZFQ.js.map +0 -1
  69. package/dist/chunk-KUH345EY.js.map +0 -1
  70. package/dist/chunk-PVQZBKN7.js.map +0 -1
  71. package/dist/index-BCJclX6q.d.ts +0 -615
package/src/index.ts CHANGED
@@ -22,10 +22,13 @@ import {
22
22
  routePartykitRequest
23
23
  } from "partyserver";
24
24
  import { camelCaseToKebabCase } from "./client";
25
- import { MCPClientManager } from "./mcp/client";
26
- // import type { MCPClientConnection } from "./mcp/client-connection";
25
+ import { MCPClientManager, type MCPClientOAuthResult } from "./mcp/client";
26
+ import type { MCPConnectionState } from "./mcp/client-connection";
27
27
  import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider";
28
+ import type { TransportType } from "./mcp/types";
28
29
  import { genericObservability, type Observability } from "./observability";
30
+ import { DisposableStore } from "./core/events";
31
+ import { MessageType } from "./ai-types";
29
32
 
30
33
  export type { Connection, ConnectionContext, WSMessage } from "partyserver";
31
34
 
@@ -43,7 +46,7 @@ export type RPCRequest = {
43
46
  * State update message from client
44
47
  */
45
48
  export type StateUpdateMessage = {
46
- type: "cf_agent_state";
49
+ type: MessageType.CF_AGENT_STATE;
47
50
  state: unknown;
48
51
  };
49
52
 
@@ -51,7 +54,7 @@ export type StateUpdateMessage = {
51
54
  * RPC response message to client
52
55
  */
53
56
  export type RPCResponse = {
54
- type: "rpc";
57
+ type: MessageType.RPC;
55
58
  id: string;
56
59
  } & (
57
60
  | {
@@ -78,7 +81,7 @@ function isRPCRequest(msg: unknown): msg is RPCRequest {
78
81
  typeof msg === "object" &&
79
82
  msg !== null &&
80
83
  "type" in msg &&
81
- msg.type === "rpc" &&
84
+ msg.type === MessageType.RPC &&
82
85
  "id" in msg &&
83
86
  typeof msg.id === "string" &&
84
87
  "method" in msg &&
@@ -96,7 +99,7 @@ function isStateUpdateMessage(msg: unknown): msg is StateUpdateMessage {
96
99
  typeof msg === "object" &&
97
100
  msg !== null &&
98
101
  "type" in msg &&
99
- msg.type === "cf_agent_state" &&
102
+ msg.type === MessageType.CF_AGENT_STATE &&
100
103
  "state" in msg
101
104
  );
102
105
  }
@@ -117,7 +120,7 @@ const callableMetadata = new Map<Function, CallableMetadata>();
117
120
  * Decorator that marks a method as callable by clients
118
121
  * @param metadata Optional metadata about the callable method
119
122
  */
120
- export function unstable_callable(metadata: CallableMetadata = {}) {
123
+ export function callable(metadata: CallableMetadata = {}) {
121
124
  return function callableDecorator<This, Args extends unknown[], Return>(
122
125
  target: (this: This, ...args: Args) => Return,
123
126
  // biome-ignore lint/correctness/noUnusedFunctionParameters: later
@@ -131,6 +134,23 @@ export function unstable_callable(metadata: CallableMetadata = {}) {
131
134
  };
132
135
  }
133
136
 
137
+ let didWarnAboutUnstableCallable = false;
138
+
139
+ /**
140
+ * Decorator that marks a method as callable by clients
141
+ * @deprecated this has been renamed to callable, and unstable_callable will be removed in the next major version
142
+ * @param metadata Optional metadata about the callable method
143
+ */
144
+ export const unstable_callable = (metadata: CallableMetadata = {}) => {
145
+ if (!didWarnAboutUnstableCallable) {
146
+ didWarnAboutUnstableCallable = true;
147
+ console.warn(
148
+ "unstable_callable is deprecated, use callable instead. unstable_callable will be removed in the next major version."
149
+ );
150
+ }
151
+ callable(metadata);
152
+ };
153
+
134
154
  export type QueueItem<T = string> = {
135
155
  id: string;
136
156
  payload: T;
@@ -179,11 +199,13 @@ function getNextCronTime(cron: string) {
179
199
  return interval.getNextDate();
180
200
  }
181
201
 
202
+ export type { TransportType } from "./mcp/types";
203
+
182
204
  /**
183
205
  * MCP Server state update message from server -> Client
184
206
  */
185
207
  export type MCPServerMessage = {
186
- type: "cf_agent_mcp_servers";
208
+ type: MessageType.CF_AGENT_MCP_SERVERS;
187
209
  mcp: MCPServersState;
188
210
  };
189
211
 
@@ -203,7 +225,7 @@ export type MCPServer = {
203
225
  // This state is specifically about the temporary process of getting a token (if needed).
204
226
  // Scope outside of that can't be relied upon because when the DO sleeps, there's no way
205
227
  // to communicate a change to a non-ready state.
206
- state: "authenticating" | "connecting" | "ready" | "discovering" | "failed";
228
+ state: MCPConnectionState;
207
229
  instructions: string | null;
208
230
  capabilities: ServerCapabilities | null;
209
231
  };
@@ -272,7 +294,13 @@ function withAgentContext<T extends (...args: any[]) => any>(
272
294
  method: T
273
295
  ): (this: Agent<unknown, unknown>, ...args: Parameters<T>) => ReturnType<T> {
274
296
  return function (...args: Parameters<T>): ReturnType<T> {
275
- const { connection, request, email } = getCurrentAgent();
297
+ const { connection, request, email, agent } = getCurrentAgent();
298
+
299
+ if (agent === this) {
300
+ // already wrapped, so we can just call the method
301
+ return method.apply(this, args);
302
+ }
303
+ // not wrapped, so we need to wrap it
276
304
  return agentContext.run({ agent: this, connection, request, email }, () => {
277
305
  return method.apply(this, args);
278
306
  });
@@ -284,13 +312,21 @@ function withAgentContext<T extends (...args: any[]) => any>(
284
312
  * @template Env Environment type containing bindings
285
313
  * @template State State type to store within the Agent
286
314
  */
287
- export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
315
+ export class Agent<
316
+ Env = typeof env,
317
+ State = unknown,
318
+ Props extends Record<string, unknown> = Record<string, unknown>
319
+ > extends Server<Env, Props> {
288
320
  private _state = DEFAULT_STATE as State;
321
+ private _disposables = new DisposableStore();
289
322
 
290
323
  private _ParentClass: typeof Agent<Env, State> =
291
324
  Object.getPrototypeOf(this).constructor;
292
325
 
293
- mcp: MCPClientManager = new MCPClientManager(this._ParentClass.name, "0.0.1");
326
+ readonly mcp: MCPClientManager = new MCPClientManager(
327
+ this._ParentClass.name,
328
+ "0.0.1"
329
+ );
294
330
 
295
331
  /**
296
332
  * Initial state for the Agent
@@ -383,8 +419,25 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
383
419
  constructor(ctx: AgentContext, env: Env) {
384
420
  super(ctx, env);
385
421
 
386
- // Auto-wrap custom methods with agent context
387
- this._autoWrapCustomMethods();
422
+ if (!wrappedClasses.has(this.constructor)) {
423
+ // Auto-wrap custom methods with agent context
424
+ this._autoWrapCustomMethods();
425
+ wrappedClasses.add(this.constructor);
426
+ }
427
+
428
+ // Broadcast server state after background connects (for OAuth servers)
429
+ this._disposables.add(
430
+ this.mcp.onConnected(async () => {
431
+ this.broadcastMcpServers();
432
+ })
433
+ );
434
+
435
+ // Emit MCP observability events
436
+ this._disposables.add(
437
+ this.mcp.onObservabilityEvent((event) => {
438
+ this.observability?.emit(event);
439
+ })
440
+ );
388
441
 
389
442
  this.sql`
390
443
  CREATE TABLE IF NOT EXISTS cf_agents_state (
@@ -441,21 +494,24 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
441
494
  { agent: this, connection: undefined, request, email: undefined },
442
495
  async () => {
443
496
  if (this.mcp.isCallbackRequest(request)) {
444
- await this.mcp.handleCallbackRequest(request);
445
-
446
- // after the MCP connection handshake, we can send updated mcp state
447
- this.broadcast(
448
- JSON.stringify({
449
- mcp: this.getMcpServers(),
450
- type: "cf_agent_mcp_servers"
451
- })
452
- );
497
+ const result = await this.mcp.handleCallbackRequest(request);
498
+ this.broadcastMcpServers();
499
+
500
+ if (result.authSuccess) {
501
+ // Start background connection if auth was successful
502
+ this.mcp
503
+ .establishConnection(result.serverId)
504
+ .catch((error) => {
505
+ console.error("Background connection failed:", error);
506
+ })
507
+ .finally(() => {
508
+ // Broadcast after background connection resolves (success/failure)
509
+ this.broadcastMcpServers();
510
+ });
511
+ }
453
512
 
454
- // We probably should let the user configure this response/redirect, but this is fine for now.
455
- return new Response("<script>window.close();</script>", {
456
- headers: { "content-type": "text/html" },
457
- status: 200
458
- });
513
+ // Handle OAuth callback response using MCPClientManager configuration
514
+ return this.handleOAuthCallbackResponse(result, request);
459
515
  }
460
516
 
461
517
  return this._tryCatch(() => _onRequest(request));
@@ -516,10 +572,8 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
516
572
  displayMessage: `RPC call to ${method}`,
517
573
  id: nanoid(),
518
574
  payload: {
519
- args,
520
575
  method,
521
- streaming: metadata?.streaming,
522
- success: true
576
+ streaming: metadata?.streaming
523
577
  },
524
578
  timestamp: Date.now(),
525
579
  type: "rpc"
@@ -532,7 +586,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
532
586
  id,
533
587
  result,
534
588
  success: true,
535
- type: "rpc"
589
+ type: MessageType.RPC
536
590
  };
537
591
  connection.send(JSON.stringify(response));
538
592
  } catch (e) {
@@ -542,7 +596,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
542
596
  e instanceof Error ? e.message : "Unknown error occurred",
543
597
  id: parsed.id,
544
598
  success: false,
545
- type: "rpc"
599
+ type: MessageType.RPC
546
600
  };
547
601
  connection.send(JSON.stringify(response));
548
602
  console.error("RPC error:", e);
@@ -561,44 +615,42 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
561
615
  // must fix this
562
616
  return agentContext.run(
563
617
  { agent: this, connection, request: ctx.request, email: undefined },
564
- async () => {
565
- setTimeout(() => {
566
- if (this.state) {
567
- connection.send(
568
- JSON.stringify({
569
- state: this.state,
570
- type: "cf_agent_state"
571
- })
572
- );
573
- }
574
-
618
+ () => {
619
+ if (this.state) {
575
620
  connection.send(
576
621
  JSON.stringify({
577
- mcp: this.getMcpServers(),
578
- type: "cf_agent_mcp_servers"
622
+ state: this.state,
623
+ type: MessageType.CF_AGENT_STATE
579
624
  })
580
625
  );
626
+ }
581
627
 
582
- this.observability?.emit(
583
- {
584
- displayMessage: "Connection established",
585
- id: nanoid(),
586
- payload: {
587
- connectionId: connection.id
588
- },
589
- timestamp: Date.now(),
590
- type: "connect"
628
+ connection.send(
629
+ JSON.stringify({
630
+ mcp: this.getMcpServers(),
631
+ type: MessageType.CF_AGENT_MCP_SERVERS
632
+ })
633
+ );
634
+
635
+ this.observability?.emit(
636
+ {
637
+ displayMessage: "Connection established",
638
+ id: nanoid(),
639
+ payload: {
640
+ connectionId: connection.id
591
641
  },
592
- this.ctx
593
- );
594
- return this._tryCatch(() => _onConnect(connection, ctx));
595
- }, 20);
642
+ timestamp: Date.now(),
643
+ type: "connect"
644
+ },
645
+ this.ctx
646
+ );
647
+ return this._tryCatch(() => _onConnect(connection, ctx));
596
648
  }
597
649
  );
598
650
  };
599
651
 
600
652
  const _onStart = this.onStart.bind(this);
601
- this.onStart = async () => {
653
+ this.onStart = async (props?: Props) => {
602
654
  return agentContext.run(
603
655
  {
604
656
  agent: this,
@@ -612,15 +664,20 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
612
664
  SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
613
665
  `;
614
666
 
615
- this.broadcast(
616
- JSON.stringify({
617
- mcp: this.getMcpServers(),
618
- type: "cf_agent_mcp_servers"
619
- })
620
- );
667
+ this.broadcastMcpServers();
621
668
 
622
669
  // from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
623
670
  if (servers && Array.isArray(servers) && servers.length > 0) {
671
+ // Restore callback URLs for OAuth-enabled servers
672
+ servers.forEach((server) => {
673
+ if (server.callback_url) {
674
+ // Register the full redirect URL including serverId to avoid ambiguous matches
675
+ this.mcp.registerCallbackUrl(
676
+ `${server.callback_url}/${server.id}`
677
+ );
678
+ }
679
+ });
680
+
624
681
  servers.forEach((server) => {
625
682
  this._connectToMcpServerInternal(
626
683
  server.name,
@@ -636,12 +693,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
636
693
  )
637
694
  .then(() => {
638
695
  // Broadcast updated MCP servers state after each server connects
639
- this.broadcast(
640
- JSON.stringify({
641
- mcp: this.getMcpServers(),
642
- type: "cf_agent_mcp_servers"
643
- })
644
- );
696
+ this.broadcastMcpServers();
645
697
  })
646
698
  .catch((error) => {
647
699
  console.error(
@@ -649,16 +701,11 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
649
701
  error
650
702
  );
651
703
  // Still broadcast even if connection fails, so clients know about the failure
652
- this.broadcast(
653
- JSON.stringify({
654
- mcp: this.getMcpServers(),
655
- type: "cf_agent_mcp_servers"
656
- })
657
- );
704
+ this.broadcastMcpServers();
658
705
  });
659
706
  });
660
707
  }
661
- return _onStart();
708
+ return _onStart(props);
662
709
  });
663
710
  }
664
711
  );
@@ -669,7 +716,6 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
669
716
  state: State,
670
717
  source: Connection | "server" = "server"
671
718
  ) {
672
- const previousState = this._state;
673
719
  this._state = state;
674
720
  this.sql`
675
721
  INSERT OR REPLACE INTO cf_agents_state (id, state)
@@ -682,7 +728,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
682
728
  this.broadcast(
683
729
  JSON.stringify({
684
730
  state: state,
685
- type: "cf_agent_state"
731
+ type: MessageType.CF_AGENT_STATE
686
732
  }),
687
733
  source !== "server" ? [source.id] : []
688
734
  );
@@ -695,10 +741,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
695
741
  {
696
742
  displayMessage: "State updated",
697
743
  id: nanoid(),
698
- payload: {
699
- previousState,
700
- state
701
- },
744
+ payload: {},
702
745
  timestamp: Date.now(),
703
746
  type: "state:update"
704
747
  },
@@ -838,41 +881,37 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
838
881
  while (proto && proto !== Object.prototype && depth < 10) {
839
882
  const methodNames = Object.getOwnPropertyNames(proto);
840
883
  for (const methodName of methodNames) {
841
- // Skip if it's a private method or not a function
884
+ const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
885
+
886
+ // Skip if it's a private method, a base method, a getter, or not a function,
842
887
  if (
843
888
  baseMethods.has(methodName) ||
844
889
  methodName.startsWith("_") ||
845
- typeof this[methodName as keyof this] !== "function"
890
+ !descriptor ||
891
+ !!descriptor.get ||
892
+ typeof descriptor.value !== "function"
846
893
  ) {
847
894
  continue;
848
895
  }
849
- // If the method doesn't exist in base prototypes, it's a custom method
850
- if (!baseMethods.has(methodName)) {
851
- const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
852
- if (descriptor && typeof descriptor.value === "function") {
853
- // Wrap the custom method with context
854
-
855
- const wrappedFunction = withAgentContext(
856
- // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
857
- this[methodName as keyof this] as (...args: any[]) => any
858
- // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
859
- ) as any;
860
-
861
- // if the method is callable, copy the metadata from the original method
862
- if (this._isCallable(methodName)) {
863
- callableMetadata.set(
864
- wrappedFunction,
865
- callableMetadata.get(
866
- this[methodName as keyof this] as Function
867
- )!
868
- );
869
- }
870
896
 
871
- // set the wrapped function on the prototype
872
- this.constructor.prototype[methodName as keyof this] =
873
- wrappedFunction;
874
- }
897
+ // Now, methodName is confirmed to be a custom method/function
898
+ // Wrap the custom method with context
899
+ const wrappedFunction = withAgentContext(
900
+ // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
901
+ this[methodName as keyof this] as (...args: any[]) => any
902
+ // biome-ignore lint/suspicious/noExplicitAny: I can't typescript
903
+ ) as any;
904
+
905
+ // if the method is callable, copy the metadata from the original method
906
+ if (this._isCallable(methodName)) {
907
+ callableMetadata.set(
908
+ wrappedFunction,
909
+ callableMetadata.get(this[methodName as keyof this] as Function)!
910
+ );
875
911
  }
912
+
913
+ // set the wrapped function on the prototype
914
+ this.constructor.prototype[methodName as keyof this] = wrappedFunction;
876
915
  }
877
916
 
878
917
  proto = Object.getPrototypeOf(proto);
@@ -1059,7 +1098,10 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1059
1098
  {
1060
1099
  displayMessage: `Schedule ${schedule.id} created`,
1061
1100
  id: nanoid(),
1062
- payload: schedule,
1101
+ payload: {
1102
+ callback: callback as string,
1103
+ id: id
1104
+ },
1063
1105
  timestamp: Date.now(),
1064
1106
  type: "schedule:create"
1065
1107
  },
@@ -1229,7 +1271,10 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1229
1271
  {
1230
1272
  displayMessage: `Schedule ${id} cancelled`,
1231
1273
  id: nanoid(),
1232
- payload: schedule,
1274
+ payload: {
1275
+ callback: schedule.callback,
1276
+ id: schedule.id
1277
+ },
1233
1278
  timestamp: Date.now(),
1234
1279
  type: "schedule:cancel"
1235
1280
  },
@@ -1294,7 +1339,10 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1294
1339
  {
1295
1340
  displayMessage: `Schedule ${row.id} executed`,
1296
1341
  id: nanoid(),
1297
- payload: row,
1342
+ payload: {
1343
+ callback: row.callback,
1344
+ id: row.id
1345
+ },
1298
1346
  timestamp: Date.now(),
1299
1347
  type: "schedule:execute"
1300
1348
  },
@@ -1346,6 +1394,8 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1346
1394
  // delete all alarms
1347
1395
  await this.ctx.storage.deleteAlarm();
1348
1396
  await this.ctx.storage.deleteAll();
1397
+ this._disposables.dispose();
1398
+ await this.mcp.dispose?.();
1349
1399
  this.ctx.abort("destroyed"); // enforce that the agent is evicted
1350
1400
 
1351
1401
  this.observability?.emit(
@@ -1371,25 +1421,42 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1371
1421
  /**
1372
1422
  * Connect to a new MCP Server
1373
1423
  *
1424
+ * @param serverName Name of the MCP server
1374
1425
  * @param url MCP Server SSE URL
1375
- * @param callbackHost Base host for the agent, used for the redirect URI.
1426
+ * @param callbackHost Base host for the agent, used for the redirect URI. If not provided, will be derived from the current request.
1376
1427
  * @param agentsPrefix agents routing prefix if not using `agents`
1377
- * @param options MCP client and transport (header) options
1428
+ * @param options MCP client and transport options
1378
1429
  * @returns authUrl
1379
1430
  */
1380
1431
  async addMcpServer(
1381
1432
  serverName: string,
1382
1433
  url: string,
1383
- callbackHost: string,
1434
+ callbackHost?: string,
1384
1435
  agentsPrefix = "agents",
1385
1436
  options?: {
1386
1437
  client?: ConstructorParameters<typeof Client>[1];
1387
1438
  transport?: {
1388
- headers: HeadersInit;
1439
+ headers?: HeadersInit;
1440
+ type?: TransportType;
1389
1441
  };
1390
1442
  }
1391
1443
  ): Promise<{ id: string; authUrl: string | undefined }> {
1392
- const callbackUrl = `${callbackHost}/${agentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
1444
+ // If callbackHost is not provided, derive it from the current request
1445
+ let resolvedCallbackHost = callbackHost;
1446
+ if (!resolvedCallbackHost) {
1447
+ const { request } = getCurrentAgent();
1448
+ if (!request) {
1449
+ throw new Error(
1450
+ "callbackHost is required when not called within a request context"
1451
+ );
1452
+ }
1453
+
1454
+ // Extract the origin from the request
1455
+ const requestUrl = new URL(request.url);
1456
+ resolvedCallbackHost = `${requestUrl.protocol}//${requestUrl.host}`;
1457
+ }
1458
+
1459
+ const callbackUrl = `${resolvedCallbackHost}/${agentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
1393
1460
 
1394
1461
  const result = await this._connectToMcpServerInternal(
1395
1462
  serverName,
@@ -1397,6 +1464,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1397
1464
  callbackUrl,
1398
1465
  options
1399
1466
  );
1467
+
1400
1468
  this.sql`
1401
1469
  INSERT
1402
1470
  OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
@@ -1411,17 +1479,12 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1411
1479
  );
1412
1480
  `;
1413
1481
 
1414
- this.broadcast(
1415
- JSON.stringify({
1416
- mcp: this.getMcpServers(),
1417
- type: "cf_agent_mcp_servers"
1418
- })
1419
- );
1482
+ this.broadcastMcpServers();
1420
1483
 
1421
1484
  return result;
1422
1485
  }
1423
1486
 
1424
- async _connectToMcpServerInternal(
1487
+ private async _connectToMcpServerInternal(
1425
1488
  _serverName: string,
1426
1489
  url: string,
1427
1490
  callbackUrl: string,
@@ -1437,6 +1500,7 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1437
1500
  */
1438
1501
  transport?: {
1439
1502
  headers?: HeadersInit;
1503
+ type?: TransportType;
1440
1504
  };
1441
1505
  },
1442
1506
  reconnect?: {
@@ -1461,6 +1525,9 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1461
1525
  }
1462
1526
  }
1463
1527
 
1528
+ // Use the transport type specified in options, or default to "auto"
1529
+ const transportType: TransportType = options?.transport?.type ?? "auto";
1530
+
1464
1531
  // allows passing through transport headers if necessary
1465
1532
  // this handles some non-standard bearer auth setups (i.e. MCP server behind CF access instead of OAuth)
1466
1533
  let headerTransportOpts: SSEClientTransportOptions = {};
@@ -1484,7 +1551,8 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1484
1551
  reconnect,
1485
1552
  transport: {
1486
1553
  ...headerTransportOpts,
1487
- authProvider
1554
+ authProvider,
1555
+ type: transportType
1488
1556
  }
1489
1557
  });
1490
1558
 
@@ -1497,15 +1565,11 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1497
1565
 
1498
1566
  async removeMcpServer(id: string) {
1499
1567
  this.mcp.closeConnection(id);
1568
+ this.mcp.unregisterCallbackUrl(id);
1500
1569
  this.sql`
1501
1570
  DELETE FROM cf_agents_mcp_servers WHERE id = ${id};
1502
1571
  `;
1503
- this.broadcast(
1504
- JSON.stringify({
1505
- mcp: this.getMcpServers(),
1506
- type: "cf_agent_mcp_servers"
1507
- })
1508
- );
1572
+ this.broadcastMcpServers();
1509
1573
  }
1510
1574
 
1511
1575
  getMcpServers(): MCPServersState {
@@ -1537,8 +1601,53 @@ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
1537
1601
 
1538
1602
  return mcpState;
1539
1603
  }
1604
+
1605
+ private broadcastMcpServers() {
1606
+ this.broadcast(
1607
+ JSON.stringify({
1608
+ mcp: this.getMcpServers(),
1609
+ type: MessageType.CF_AGENT_MCP_SERVERS
1610
+ })
1611
+ );
1612
+ }
1613
+
1614
+ /**
1615
+ * Handle OAuth callback response using MCPClientManager configuration
1616
+ * @param result OAuth callback result
1617
+ * @param request The original request (needed for base URL)
1618
+ * @returns Response for the OAuth callback
1619
+ */
1620
+ private handleOAuthCallbackResponse(
1621
+ result: MCPClientOAuthResult,
1622
+ request: Request
1623
+ ): Response {
1624
+ const config = this.mcp.getOAuthCallbackConfig();
1625
+
1626
+ // Use custom handler if configured
1627
+ if (config?.customHandler) {
1628
+ return config.customHandler(result);
1629
+ }
1630
+
1631
+ // Use redirect URLs if configured
1632
+ if (config?.successRedirect && result.authSuccess) {
1633
+ return Response.redirect(config.successRedirect);
1634
+ }
1635
+
1636
+ if (config?.errorRedirect && !result.authSuccess) {
1637
+ return Response.redirect(
1638
+ `${config.errorRedirect}?error=${encodeURIComponent(result.authError || "Unknown error")}`
1639
+ );
1640
+ }
1641
+
1642
+ // Default behavior - redirect to base URL
1643
+ const baseUrl = new URL(request.url).origin;
1644
+ return Response.redirect(baseUrl);
1645
+ }
1540
1646
  }
1541
1647
 
1648
+ // A set of classes that have been wrapped with agent context
1649
+ const wrappedClasses = new Set<typeof Agent.prototype.constructor>();
1650
+
1542
1651
  /**
1543
1652
  * Namespace for creating Agent instances
1544
1653
  * @template Agentic Type of the Agent class
@@ -1854,12 +1963,17 @@ export type EmailSendOptions = {
1854
1963
  * @param options Options for Agent creation
1855
1964
  * @returns Promise resolving to an Agent instance stub
1856
1965
  */
1857
- export async function getAgentByName<Env, T extends Agent<Env>>(
1966
+ export async function getAgentByName<
1967
+ Env,
1968
+ T extends Agent<Env>,
1969
+ Props extends Record<string, unknown> = Record<string, unknown>
1970
+ >(
1858
1971
  namespace: AgentNamespace<T>,
1859
1972
  name: string,
1860
1973
  options?: {
1861
1974
  jurisdiction?: DurableObjectJurisdiction;
1862
1975
  locationHint?: DurableObjectLocationHint;
1976
+ props?: Props;
1863
1977
  }
1864
1978
  ) {
1865
1979
  return getServerByName<Env, T>(namespace, name, options);
@@ -1891,7 +2005,7 @@ export class StreamingResponse {
1891
2005
  id: this._id,
1892
2006
  result: chunk,
1893
2007
  success: true,
1894
- type: "rpc"
2008
+ type: MessageType.RPC
1895
2009
  };
1896
2010
  this._connection.send(JSON.stringify(response));
1897
2011
  }
@@ -1910,7 +2024,7 @@ export class StreamingResponse {
1910
2024
  id: this._id,
1911
2025
  result: finalChunk,
1912
2026
  success: true,
1913
- type: "rpc"
2027
+ type: MessageType.RPC
1914
2028
  };
1915
2029
  this._connection.send(JSON.stringify(response));
1916
2030
  }