agents 0.0.0-d2e8c0e → 0.0.0-d40512c

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 (44) hide show
  1. package/README.md +22 -22
  2. package/dist/ai-chat-agent.d.ts +5 -4
  3. package/dist/ai-chat-agent.js +64 -26
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/ai-react.d.ts +10 -9
  6. package/dist/ai-react.js +27 -27
  7. package/dist/ai-react.js.map +1 -1
  8. package/dist/{chunk-Y67CHZBI.js → chunk-4RBEYCWK.js} +23 -18
  9. package/dist/chunk-4RBEYCWK.js.map +1 -0
  10. package/dist/{chunk-QSGN3REV.js → chunk-KUH345EY.js} +8 -15
  11. package/dist/chunk-KUH345EY.js.map +1 -0
  12. package/dist/{chunk-J6T74FUS.js → chunk-LU2RSO54.js} +207 -80
  13. package/dist/chunk-LU2RSO54.js.map +1 -0
  14. package/dist/{chunk-BZXOAZUX.js → chunk-PVQZBKN7.js} +5 -5
  15. package/dist/chunk-PVQZBKN7.js.map +1 -0
  16. package/dist/client.d.ts +8 -2
  17. package/dist/client.js +1 -1
  18. package/dist/index-CITGJflw.d.ts +486 -0
  19. package/dist/index.d.ts +25 -405
  20. package/dist/index.js +4 -4
  21. package/dist/mcp/client.d.ts +281 -9
  22. package/dist/mcp/client.js +1 -1
  23. package/dist/mcp/do-oauth-client-provider.js +1 -1
  24. package/dist/mcp/index.d.ts +9 -9
  25. package/dist/mcp/index.js +53 -49
  26. package/dist/mcp/index.js.map +1 -1
  27. package/dist/observability/index.d.ts +12 -0
  28. package/dist/observability/index.js +10 -0
  29. package/dist/observability/index.js.map +1 -0
  30. package/dist/react.d.ts +51 -36
  31. package/dist/react.js +16 -6
  32. package/dist/react.js.map +1 -1
  33. package/dist/schedule.d.ts +6 -6
  34. package/dist/schedule.js +4 -4
  35. package/dist/schedule.js.map +1 -1
  36. package/dist/serializable.d.ts +32 -0
  37. package/dist/serializable.js +1 -0
  38. package/dist/serializable.js.map +1 -0
  39. package/package.json +75 -72
  40. package/src/index.ts +227 -112
  41. package/dist/chunk-BZXOAZUX.js.map +0 -1
  42. package/dist/chunk-J6T74FUS.js.map +0 -1
  43. package/dist/chunk-QSGN3REV.js.map +0 -1
  44. package/dist/chunk-Y67CHZBI.js.map +0 -1
package/src/index.ts CHANGED
@@ -1,35 +1,31 @@
1
- import {
2
- Server,
3
- routePartykitRequest,
4
- type PartyServerOptions,
5
- getServerByName,
6
- type Connection,
7
- type ConnectionContext,
8
- type WSMessage,
9
- } from "partyserver";
10
-
11
- import { parseCronExpression } from "cron-schedule";
12
- import { nanoid } from "nanoid";
13
-
14
1
  import { AsyncLocalStorage } from "node:async_hooks";
15
- import { MCPClientManager } from "./mcp/client";
16
- import {
17
- DurableObjectOAuthClientProvider,
18
- type AgentsOAuthProvider,
19
- } from "./mcp/do-oauth-client-provider";
2
+ import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
+ import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js";
4
+
20
5
  import type {
21
- Tool,
22
- Resource,
23
6
  Prompt,
7
+ Resource,
24
8
  ServerCapabilities,
9
+ Tool
25
10
  } from "@modelcontextprotocol/sdk/types.js";
26
-
27
- import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
28
- import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js";
29
-
11
+ import { parseCronExpression } from "cron-schedule";
12
+ import { nanoid } from "nanoid";
13
+ import {
14
+ type Connection,
15
+ type ConnectionContext,
16
+ getServerByName,
17
+ type PartyServerOptions,
18
+ routePartykitRequest,
19
+ Server,
20
+ type WSMessage
21
+ } from "partyserver";
30
22
  import { camelCaseToKebabCase } from "./client";
23
+ import { MCPClientManager } from "./mcp/client";
24
+ // import type { MCPClientConnection } from "./mcp/client-connection";
25
+ import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider";
26
+ import { genericObservability, type Observability } from "./observability";
31
27
 
32
- export type { Connection, WSMessage, ConnectionContext } from "partyserver";
28
+ export type { Connection, ConnectionContext, WSMessage } from "partyserver";
33
29
 
34
30
  /**
35
31
  * RPC request message from client
@@ -122,6 +118,7 @@ const callableMetadata = new Map<Function, CallableMetadata>();
122
118
  export function unstable_callable(metadata: CallableMetadata = {}) {
123
119
  return function callableDecorator<This, Args extends unknown[], Return>(
124
120
  target: (this: This, ...args: Args) => Return,
121
+ // biome-ignore lint/correctness/noUnusedFunctionParameters: later
125
122
  context: ClassMethodDecoratorContext
126
123
  ) {
127
124
  if (!callableMetadata.has(target)) {
@@ -194,6 +191,9 @@ export type MCPServer = {
194
191
  name: string;
195
192
  server_url: string;
196
193
  auth_url: string | null;
194
+ // This state is specifically about the temporary process of getting a token (if needed).
195
+ // Scope outside of that can't be relied upon because when the DO sleeps, there's no way
196
+ // to communicate a change to a non-ready state.
197
197
  state: "authenticating" | "connecting" | "ready" | "discovering" | "failed";
198
198
  instructions: string | null;
199
199
  capabilities: ServerCapabilities | null;
@@ -224,7 +224,7 @@ const agentContext = new AsyncLocalStorage<{
224
224
  }>();
225
225
 
226
226
  export function getCurrentAgent<
227
- T extends Agent<unknown, unknown> = Agent<unknown, unknown>,
227
+ T extends Agent<unknown, unknown> = Agent<unknown, unknown>
228
228
  >(): {
229
229
  agent: T | undefined;
230
230
  connection: Connection | undefined;
@@ -241,7 +241,7 @@ export function getCurrentAgent<
241
241
  return {
242
242
  agent: undefined,
243
243
  connection: undefined,
244
- request: undefined,
244
+ request: undefined
245
245
  };
246
246
  }
247
247
  return store;
@@ -314,9 +314,14 @@ export class Agent<Env, State = unknown> extends Server<Env> {
314
314
  */
315
315
  static options = {
316
316
  /** Whether the Agent should hibernate when inactive */
317
- hibernate: true, // default to hibernate
317
+ hibernate: true // default to hibernate
318
318
  };
319
319
 
320
+ /**
321
+ * The observability implementation to use for the Agent
322
+ */
323
+ observability?: Observability = genericObservability;
324
+
320
325
  /**
321
326
  * Execute SQL queries against the Agent's database
322
327
  * @template T Type of the returned rows
@@ -397,15 +402,15 @@ export class Agent<Env, State = unknown> extends Server<Env> {
397
402
  // after the MCP connection handshake, we can send updated mcp state
398
403
  this.broadcast(
399
404
  JSON.stringify({
400
- type: "cf_agent_mcp_servers",
401
405
  mcp: this.getMcpServers(),
406
+ type: "cf_agent_mcp_servers"
402
407
  })
403
408
  );
404
409
 
405
410
  // We probably should let the user configure this response/redirect, but this is fine for now.
406
411
  return new Response("<script>window.close();</script>", {
407
- status: 200,
408
412
  headers: { "content-type": "text/html" },
413
+ status: 200
409
414
  });
410
415
  }
411
416
 
@@ -426,7 +431,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
426
431
  let parsed: unknown;
427
432
  try {
428
433
  parsed = JSON.parse(message);
429
- } catch (e) {
434
+ } catch (_e) {
430
435
  // silently fail and let the onMessage handler handle it
431
436
  return this._tryCatch(() => _onMessage(connection, message));
432
437
  }
@@ -461,22 +466,39 @@ export class Agent<Env, State = unknown> extends Server<Env> {
461
466
 
462
467
  // For regular methods, execute and send response
463
468
  const result = await methodFn.apply(this, args);
469
+
470
+ this.observability?.emit(
471
+ {
472
+ displayMessage: `RPC call to ${method}`,
473
+ id: nanoid(),
474
+ payload: {
475
+ args,
476
+ method,
477
+ streaming: metadata?.streaming,
478
+ success: true
479
+ },
480
+ timestamp: Date.now(),
481
+ type: "rpc"
482
+ },
483
+ this.ctx
484
+ );
485
+
464
486
  const response: RPCResponse = {
465
- type: "rpc",
487
+ done: true,
466
488
  id,
467
- success: true,
468
489
  result,
469
- done: true,
490
+ success: true,
491
+ type: "rpc"
470
492
  };
471
493
  connection.send(JSON.stringify(response));
472
494
  } catch (e) {
473
495
  // Send error response
474
496
  const response: RPCResponse = {
475
- type: "rpc",
476
- id: parsed.id,
477
- success: false,
478
497
  error:
479
498
  e instanceof Error ? e.message : "Unknown error occurred",
499
+ id: parsed.id,
500
+ success: false,
501
+ type: "rpc"
480
502
  };
481
503
  connection.send(JSON.stringify(response));
482
504
  console.error("RPC error:", e);
@@ -500,19 +522,31 @@ export class Agent<Env, State = unknown> extends Server<Env> {
500
522
  if (this.state) {
501
523
  connection.send(
502
524
  JSON.stringify({
503
- type: "cf_agent_state",
504
525
  state: this.state,
526
+ type: "cf_agent_state"
505
527
  })
506
528
  );
507
529
  }
508
530
 
509
531
  connection.send(
510
532
  JSON.stringify({
511
- type: "cf_agent_mcp_servers",
512
533
  mcp: this.getMcpServers(),
534
+ type: "cf_agent_mcp_servers"
513
535
  })
514
536
  );
515
537
 
538
+ this.observability?.emit(
539
+ {
540
+ displayMessage: "Connection established",
541
+ id: nanoid(),
542
+ payload: {
543
+ connectionId: connection.id
544
+ },
545
+ timestamp: Date.now(),
546
+ type: "connect"
547
+ },
548
+ this.ctx
549
+ );
516
550
  return this._tryCatch(() => _onConnect(connection, ctx));
517
551
  }, 20);
518
552
  }
@@ -528,8 +562,8 @@ export class Agent<Env, State = unknown> extends Server<Env> {
528
562
  SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
529
563
  `;
530
564
 
531
- // from DO storage, reconnect to all servers using our saved auth information
532
- await Promise.allSettled(
565
+ // from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
566
+ Promise.allSettled(
533
567
  servers.map((server) => {
534
568
  return this._connectToMcpServerInternal(
535
569
  server.name,
@@ -540,19 +574,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
540
574
  : undefined,
541
575
  {
542
576
  id: server.id,
543
- oauthClientId: server.client_id ?? undefined,
577
+ oauthClientId: server.client_id ?? undefined
544
578
  }
545
579
  );
546
580
  })
547
- );
548
-
549
- this.broadcast(
550
- JSON.stringify({
551
- type: "cf_agent_mcp_servers",
552
- mcp: this.getMcpServers(),
553
- })
554
- );
555
-
581
+ ).then((_results) => {
582
+ this.broadcast(
583
+ JSON.stringify({
584
+ mcp: this.getMcpServers(),
585
+ type: "cf_agent_mcp_servers"
586
+ })
587
+ );
588
+ });
556
589
  await this._tryCatch(() => _onStart());
557
590
  }
558
591
  );
@@ -563,6 +596,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
563
596
  state: State,
564
597
  source: Connection | "server" = "server"
565
598
  ) {
599
+ const previousState = this._state;
566
600
  this._state = state;
567
601
  this.sql`
568
602
  INSERT OR REPLACE INTO cf_agents_state (id, state)
@@ -574,8 +608,8 @@ export class Agent<Env, State = unknown> extends Server<Env> {
574
608
  `;
575
609
  this.broadcast(
576
610
  JSON.stringify({
577
- type: "cf_agent_state",
578
611
  state: state,
612
+ type: "cf_agent_state"
579
613
  }),
580
614
  source !== "server" ? [source.id] : []
581
615
  );
@@ -584,6 +618,19 @@ export class Agent<Env, State = unknown> extends Server<Env> {
584
618
  return agentContext.run(
585
619
  { agent: this, connection, request },
586
620
  async () => {
621
+ this.observability?.emit(
622
+ {
623
+ displayMessage: "State updated",
624
+ id: nanoid(),
625
+ payload: {
626
+ previousState,
627
+ state
628
+ },
629
+ timestamp: Date.now(),
630
+ type: "state:update"
631
+ },
632
+ this.ctx
633
+ );
587
634
  return this.onStateUpdate(state, source);
588
635
  }
589
636
  );
@@ -603,6 +650,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
603
650
  * @param state Updated state
604
651
  * @param source Source of the state update ("server" or a client connection)
605
652
  */
653
+ // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
606
654
  onStateUpdate(state: State | undefined, source: Connection | "server") {
607
655
  // override this to handle state updates
608
656
  }
@@ -611,6 +659,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
611
659
  * Called when the Agent receives an email
612
660
  * @param email Email message to process
613
661
  */
662
+ // biome-ignore lint/correctness/noUnusedFunctionParameters: overridden later
614
663
  onEmail(email: ForwardableEmailMessage) {
615
664
  return agentContext.run(
616
665
  { agent: this, connection: undefined, request: undefined },
@@ -677,6 +726,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
677
726
  ): Promise<Schedule<T>> {
678
727
  const id = nanoid(9);
679
728
 
729
+ const emitScheduleCreate = (schedule: Schedule<T>) =>
730
+ this.observability?.emit(
731
+ {
732
+ displayMessage: `Schedule ${schedule.id} created`,
733
+ id: nanoid(),
734
+ payload: schedule,
735
+ timestamp: Date.now(),
736
+ type: "schedule:create"
737
+ },
738
+ this.ctx
739
+ );
740
+
680
741
  if (typeof callback !== "string") {
681
742
  throw new Error("Callback must be a string");
682
743
  }
@@ -696,13 +757,17 @@ export class Agent<Env, State = unknown> extends Server<Env> {
696
757
 
697
758
  await this._scheduleNextAlarm();
698
759
 
699
- return {
700
- id,
760
+ const schedule: Schedule<T> = {
701
761
  callback: callback,
762
+ id,
702
763
  payload: payload as T,
703
764
  time: timestamp,
704
- type: "scheduled",
765
+ type: "scheduled"
705
766
  };
767
+
768
+ emitScheduleCreate(schedule);
769
+
770
+ return schedule;
706
771
  }
707
772
  if (typeof when === "number") {
708
773
  const time = new Date(Date.now() + when * 1000);
@@ -717,14 +782,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
717
782
 
718
783
  await this._scheduleNextAlarm();
719
784
 
720
- return {
721
- id,
785
+ const schedule: Schedule<T> = {
722
786
  callback: callback,
723
- payload: payload as T,
724
787
  delayInSeconds: when,
788
+ id,
789
+ payload: payload as T,
725
790
  time: timestamp,
726
- type: "delayed",
791
+ type: "delayed"
727
792
  };
793
+
794
+ emitScheduleCreate(schedule);
795
+
796
+ return schedule;
728
797
  }
729
798
  if (typeof when === "string") {
730
799
  const nextExecutionTime = getNextCronTime(when);
@@ -739,14 +808,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
739
808
 
740
809
  await this._scheduleNextAlarm();
741
810
 
742
- return {
743
- id,
811
+ const schedule: Schedule<T> = {
744
812
  callback: callback,
745
- payload: payload as T,
746
813
  cron: when,
814
+ id,
815
+ payload: payload as T,
747
816
  time: timestamp,
748
- type: "cron",
817
+ type: "cron"
749
818
  };
819
+
820
+ emitScheduleCreate(schedule);
821
+
822
+ return schedule;
750
823
  }
751
824
  throw new Error("Invalid schedule type");
752
825
  }
@@ -810,7 +883,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
810
883
  .toArray()
811
884
  .map((row) => ({
812
885
  ...row,
813
- payload: JSON.parse(row.payload as string) as T,
886
+ payload: JSON.parse(row.payload as string) as T
814
887
  })) as Schedule<T>[];
815
888
 
816
889
  return result;
@@ -822,6 +895,19 @@ export class Agent<Env, State = unknown> extends Server<Env> {
822
895
  * @returns true if the task was cancelled, false otherwise
823
896
  */
824
897
  async cancelSchedule(id: string): Promise<boolean> {
898
+ const schedule = await this.getSchedule(id);
899
+ if (schedule) {
900
+ this.observability?.emit(
901
+ {
902
+ displayMessage: `Schedule ${id} cancelled`,
903
+ id: nanoid(),
904
+ payload: schedule,
905
+ timestamp: Date.now(),
906
+ type: "schedule:cancel"
907
+ },
908
+ this.ctx
909
+ );
910
+ }
825
911
  this.sql`DELETE FROM cf_agents_schedules WHERE id = ${id}`;
826
912
 
827
913
  await this._scheduleNextAlarm();
@@ -870,6 +956,17 @@ export class Agent<Env, State = unknown> extends Server<Env> {
870
956
  { agent: this, connection: undefined, request: undefined },
871
957
  async () => {
872
958
  try {
959
+ this.observability?.emit(
960
+ {
961
+ displayMessage: `Schedule ${row.id} executed`,
962
+ id: nanoid(),
963
+ payload: row,
964
+ timestamp: Date.now(),
965
+ type: "schedule:execute"
966
+ },
967
+ this.ctx
968
+ );
969
+
873
970
  await (
874
971
  callback as (
875
972
  payload: unknown,
@@ -913,6 +1010,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
913
1010
  // delete all alarms
914
1011
  await this.ctx.storage.deleteAlarm();
915
1012
  await this.ctx.storage.deleteAll();
1013
+ this.ctx.abort("destroyed"); // enforce that the agent is evicted
1014
+
1015
+ this.observability?.emit(
1016
+ {
1017
+ displayMessage: "Agent destroyed",
1018
+ id: nanoid(),
1019
+ payload: {},
1020
+ timestamp: Date.now(),
1021
+ type: "destroy"
1022
+ },
1023
+ this.ctx
1024
+ );
916
1025
  }
917
1026
 
918
1027
  /**
@@ -952,11 +1061,24 @@ export class Agent<Env, State = unknown> extends Server<Env> {
952
1061
  callbackUrl,
953
1062
  options
954
1063
  );
1064
+ this.sql`
1065
+ INSERT
1066
+ OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
1067
+ VALUES (
1068
+ ${result.id},
1069
+ ${serverName},
1070
+ ${url},
1071
+ ${result.clientId ?? null},
1072
+ ${result.authUrl ?? null},
1073
+ ${callbackUrl},
1074
+ ${options ? JSON.stringify(options) : null}
1075
+ );
1076
+ `;
955
1077
 
956
1078
  this.broadcast(
957
1079
  JSON.stringify({
958
- type: "cf_agent_mcp_servers",
959
1080
  mcp: this.getMcpServers(),
1081
+ type: "cf_agent_mcp_servers"
960
1082
  })
961
1083
  );
962
1084
 
@@ -964,7 +1086,7 @@ export class Agent<Env, State = unknown> extends Server<Env> {
964
1086
  }
965
1087
 
966
1088
  async _connectToMcpServerInternal(
967
- serverName: string,
1089
+ _serverName: string,
968
1090
  url: string,
969
1091
  callbackUrl: string,
970
1092
  // it's important that any options here are serializable because we put them into our sqlite DB for reconnection purposes
@@ -985,7 +1107,11 @@ export class Agent<Env, State = unknown> extends Server<Env> {
985
1107
  id: string;
986
1108
  oauthClientId?: string;
987
1109
  }
988
- ): Promise<{ id: string; authUrl: string | undefined }> {
1110
+ ): Promise<{
1111
+ id: string;
1112
+ authUrl: string | undefined;
1113
+ clientId: string | undefined;
1114
+ }> {
989
1115
  const authProvider = new DurableObjectOAuthClientProvider(
990
1116
  this.ctx.storage,
991
1117
  this.name,
@@ -1008,40 +1134,28 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1008
1134
  fetch: (url, init) =>
1009
1135
  fetch(url, {
1010
1136
  ...init,
1011
- headers: options?.transport?.headers,
1012
- }),
1137
+ headers: options?.transport?.headers
1138
+ })
1013
1139
  },
1014
1140
  requestInit: {
1015
- headers: options?.transport?.headers,
1016
- },
1141
+ headers: options?.transport?.headers
1142
+ }
1017
1143
  };
1018
1144
  }
1019
1145
 
1020
1146
  const { id, authUrl, clientId } = await this.mcp.connect(url, {
1147
+ client: options?.client,
1021
1148
  reconnect,
1022
1149
  transport: {
1023
1150
  ...headerTransportOpts,
1024
- authProvider,
1025
- },
1026
- client: options?.client,
1151
+ authProvider
1152
+ }
1027
1153
  });
1028
1154
 
1029
- this.sql`
1030
- INSERT OR REPLACE INTO cf_agents_mcp_servers (id, name, server_url, client_id, auth_url, callback_url, server_options)
1031
- VALUES (
1032
- ${id},
1033
- ${serverName},
1034
- ${url},
1035
- ${clientId ?? null},
1036
- ${authUrl ?? null},
1037
- ${callbackUrl},
1038
- ${options ? JSON.stringify(options) : null}
1039
- );
1040
- `;
1041
-
1042
1155
  return {
1043
- id,
1044
1156
  authUrl,
1157
+ clientId,
1158
+ id
1045
1159
  };
1046
1160
  }
1047
1161
 
@@ -1052,18 +1166,18 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1052
1166
  `;
1053
1167
  this.broadcast(
1054
1168
  JSON.stringify({
1055
- type: "cf_agent_mcp_servers",
1056
1169
  mcp: this.getMcpServers(),
1170
+ type: "cf_agent_mcp_servers"
1057
1171
  })
1058
1172
  );
1059
1173
  }
1060
1174
 
1061
1175
  getMcpServers(): MCPServersState {
1062
1176
  const mcpState: MCPServersState = {
1063
- servers: {},
1064
- tools: this.mcp.listTools(),
1065
1177
  prompts: this.mcp.listPrompts(),
1066
1178
  resources: this.mcp.listResources(),
1179
+ servers: {},
1180
+ tools: this.mcp.listTools()
1067
1181
  };
1068
1182
 
1069
1183
  const servers = this.sql<MCPServerRow>`
@@ -1071,14 +1185,15 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1071
1185
  `;
1072
1186
 
1073
1187
  for (const server of servers) {
1188
+ const serverConn = this.mcp.mcpConnections[server.id];
1074
1189
  mcpState.servers[server.id] = {
1190
+ auth_url: server.auth_url,
1191
+ capabilities: serverConn?.serverCapabilities ?? null,
1192
+ instructions: serverConn?.instructions ?? null,
1075
1193
  name: server.name,
1076
1194
  server_url: server.server_url,
1077
- auth_url: server.auth_url,
1078
- state: this.mcp.mcpConnections[server.id].connectionState,
1079
- instructions: this.mcp.mcpConnections[server.id].instructions ?? null,
1080
- capabilities:
1081
- this.mcp.mcpConnections[server.id].serverCapabilities ?? null,
1195
+ // mark as "authenticating" because the server isn't automatically connected, so it's pending authenticating
1196
+ state: serverConn?.connectionState ?? "authenticating"
1082
1197
  };
1083
1198
  }
1084
1199
 
@@ -1123,17 +1238,17 @@ export async function routeAgentRequest<Env>(
1123
1238
  const corsHeaders =
1124
1239
  options?.cors === true
1125
1240
  ? {
1126
- "Access-Control-Allow-Origin": "*",
1127
- "Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
1128
1241
  "Access-Control-Allow-Credentials": "true",
1129
- "Access-Control-Max-Age": "86400",
1242
+ "Access-Control-Allow-Methods": "GET, POST, HEAD, OPTIONS",
1243
+ "Access-Control-Allow-Origin": "*",
1244
+ "Access-Control-Max-Age": "86400"
1130
1245
  }
1131
1246
  : options?.cors;
1132
1247
 
1133
1248
  if (request.method === "OPTIONS") {
1134
1249
  if (corsHeaders) {
1135
1250
  return new Response(null, {
1136
- headers: corsHeaders,
1251
+ headers: corsHeaders
1137
1252
  });
1138
1253
  }
1139
1254
  console.warn(
@@ -1146,7 +1261,7 @@ export async function routeAgentRequest<Env>(
1146
1261
  env as Record<string, unknown>,
1147
1262
  {
1148
1263
  prefix: "agents",
1149
- ...(options as PartyServerOptions<Record<string, unknown>>),
1264
+ ...(options as PartyServerOptions<Record<string, unknown>>)
1150
1265
  }
1151
1266
  );
1152
1267
 
@@ -1159,8 +1274,8 @@ export async function routeAgentRequest<Env>(
1159
1274
  response = new Response(response.body, {
1160
1275
  headers: {
1161
1276
  ...response.headers,
1162
- ...corsHeaders,
1163
- },
1277
+ ...corsHeaders
1278
+ }
1164
1279
  });
1165
1280
  }
1166
1281
  return response;
@@ -1173,9 +1288,9 @@ export async function routeAgentRequest<Env>(
1173
1288
  * @param options Routing options
1174
1289
  */
1175
1290
  export async function routeAgentEmail<Env>(
1176
- email: ForwardableEmailMessage,
1177
- env: Env,
1178
- options?: AgentOptions<Env>
1291
+ _email: ForwardableEmailMessage,
1292
+ _env: Env,
1293
+ _options?: AgentOptions<Env>
1179
1294
  ): Promise<void> {}
1180
1295
 
1181
1296
  /**
@@ -1220,11 +1335,11 @@ export class StreamingResponse {
1220
1335
  throw new Error("StreamingResponse is already closed");
1221
1336
  }
1222
1337
  const response: RPCResponse = {
1223
- type: "rpc",
1338
+ done: false,
1224
1339
  id: this._id,
1225
- success: true,
1226
1340
  result: chunk,
1227
- done: false,
1341
+ success: true,
1342
+ type: "rpc"
1228
1343
  };
1229
1344
  this._connection.send(JSON.stringify(response));
1230
1345
  }
@@ -1239,11 +1354,11 @@ export class StreamingResponse {
1239
1354
  }
1240
1355
  this._closed = true;
1241
1356
  const response: RPCResponse = {
1242
- type: "rpc",
1357
+ done: true,
1243
1358
  id: this._id,
1244
- success: true,
1245
1359
  result: finalChunk,
1246
- done: true,
1360
+ success: true,
1361
+ type: "rpc"
1247
1362
  };
1248
1363
  this._connection.send(JSON.stringify(response));
1249
1364
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcp/do-oauth-client-provider.ts"],"sourcesContent":["import type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type {\n OAuthTokens,\n OAuthClientMetadata,\n OAuthClientInformation,\n OAuthClientInformationFull,\n} from \"@modelcontextprotocol/sdk/shared/auth.js\";\n\n// A slight extension to the standard OAuthClientProvider interface because `redirectToAuthorization` doesn't give us the interface we need\n// This allows us to track authentication for a specific server and associated dynamic client registration\nexport interface AgentsOAuthProvider extends OAuthClientProvider {\n authUrl: string | undefined;\n clientId: string | undefined;\n serverId: string | undefined;\n}\n\nexport class DurableObjectOAuthClientProvider implements AgentsOAuthProvider {\n private _authUrl_: string | undefined;\n private _serverId_: string | undefined;\n private _clientId_: string | undefined;\n\n constructor(\n public storage: DurableObjectStorage,\n public clientName: string,\n public baseRedirectUrl: string\n ) {}\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n redirect_uris: [this.redirectUrl],\n token_endpoint_auth_method: \"none\",\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n client_name: this.clientName,\n client_uri: \"example.com\",\n };\n }\n\n get redirectUrl() {\n return `${this.baseRedirectUrl}/${this.serverId}`;\n }\n\n get clientId() {\n if (!this._clientId_) {\n throw new Error(\"Trying to access clientId before it was set\");\n }\n return this._clientId_;\n }\n\n set clientId(clientId_: string) {\n this._clientId_ = clientId_;\n }\n\n get serverId() {\n if (!this._serverId_) {\n throw new Error(\"Trying to access serverId before it was set\");\n }\n return this._serverId_;\n }\n\n set serverId(serverId_: string) {\n this._serverId_ = serverId_;\n }\n\n keyPrefix(clientId: string) {\n return `/${this.clientName}/${this.serverId}/${clientId}`;\n }\n\n clientInfoKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/client_info/`;\n }\n\n async clientInformation(): Promise<OAuthClientInformation | undefined> {\n if (!this._clientId_) {\n return undefined;\n }\n return (\n (await this.storage.get<OAuthClientInformation>(\n this.clientInfoKey(this.clientId)\n )) ?? undefined\n );\n }\n\n async saveClientInformation(\n clientInformation: OAuthClientInformationFull\n ): Promise<void> {\n await this.storage.put(\n this.clientInfoKey(clientInformation.client_id),\n clientInformation\n );\n this.clientId = clientInformation.client_id;\n }\n\n tokenKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/token`;\n }\n\n async tokens(): Promise<OAuthTokens | undefined> {\n if (!this._clientId_) {\n return undefined;\n }\n return (\n (await this.storage.get<OAuthTokens>(this.tokenKey(this.clientId))) ??\n undefined\n );\n }\n\n async saveTokens(tokens: OAuthTokens): Promise<void> {\n await this.storage.put(this.tokenKey(this.clientId), tokens);\n }\n\n get authUrl() {\n return this._authUrl_;\n }\n\n /**\n * Because this operates on the server side (but we need browser auth), we send this url back to the user\n * and require user interact to initiate the redirect flow\n */\n async redirectToAuthorization(authUrl: URL): Promise<void> {\n // We want to track the client ID in state here because the typescript SSE client sometimes does\n // a dynamic client registration AFTER generating this redirect URL.\n const client_id = authUrl.searchParams.get(\"client_id\");\n if (client_id) {\n authUrl.searchParams.append(\"state\", client_id);\n }\n this._authUrl_ = authUrl.toString();\n }\n\n codeVerifierKey(clientId: string) {\n return `${this.keyPrefix(clientId)}/code_verifier`;\n }\n\n async saveCodeVerifier(verifier: string): Promise<void> {\n await this.storage.put(this.codeVerifierKey(this.clientId), verifier);\n }\n\n async codeVerifier(): Promise<string> {\n const codeVerifier = await this.storage.get<string>(\n this.codeVerifierKey(this.clientId)\n );\n if (!codeVerifier) {\n throw new Error(\"No code verifier found\");\n }\n return codeVerifier;\n }\n}\n"],"mappings":";AAgBO,IAAM,mCAAN,MAAsE;AAAA,EAK3E,YACS,SACA,YACA,iBACP;AAHO;AACA;AACA;AAAA,EACN;AAAA,EAEH,IAAI,iBAAsC;AACxC,WAAO;AAAA,MACL,eAAe,CAAC,KAAK,WAAW;AAAA,MAChC,4BAA4B;AAAA,MAC5B,aAAa,CAAC,sBAAsB,eAAe;AAAA,MACnD,gBAAgB,CAAC,MAAM;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,YAAY;AAAA,IACd;AAAA,EACF;AAAA,EAEA,IAAI,cAAc;AAChB,WAAO,GAAG,KAAK,eAAe,IAAI,KAAK,QAAQ;AAAA,EACjD;AAAA,EAEA,IAAI,WAAW;AACb,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAS,WAAmB;AAC9B,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,IAAI,WAAW;AACb,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAS,WAAmB;AAC9B,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,UAAU,UAAkB;AAC1B,WAAO,IAAI,KAAK,UAAU,IAAI,KAAK,QAAQ,IAAI,QAAQ;AAAA,EACzD;AAAA,EAEA,cAAc,UAAkB;AAC9B,WAAO,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,EACpC;AAAA,EAEA,MAAM,oBAAiE;AACrE,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO;AAAA,IACT;AACA,WACG,MAAM,KAAK,QAAQ;AAAA,MAClB,KAAK,cAAc,KAAK,QAAQ;AAAA,IAClC,KAAM;AAAA,EAEV;AAAA,EAEA,MAAM,sBACJ,mBACe;AACf,UAAM,KAAK,QAAQ;AAAA,MACjB,KAAK,cAAc,kBAAkB,SAAS;AAAA,MAC9C;AAAA,IACF;AACA,SAAK,WAAW,kBAAkB;AAAA,EACpC;AAAA,EAEA,SAAS,UAAkB;AACzB,WAAO,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,EACpC;AAAA,EAEA,MAAM,SAA2C;AAC/C,QAAI,CAAC,KAAK,YAAY;AACpB,aAAO;AAAA,IACT;AACA,WACG,MAAM,KAAK,QAAQ,IAAiB,KAAK,SAAS,KAAK,QAAQ,CAAC,KACjE;AAAA,EAEJ;AAAA,EAEA,MAAM,WAAW,QAAoC;AACnD,UAAM,KAAK,QAAQ,IAAI,KAAK,SAAS,KAAK,QAAQ,GAAG,MAAM;AAAA,EAC7D;AAAA,EAEA,IAAI,UAAU;AACZ,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,wBAAwB,SAA6B;AAGzD,UAAM,YAAY,QAAQ,aAAa,IAAI,WAAW;AACtD,QAAI,WAAW;AACb,cAAQ,aAAa,OAAO,SAAS,SAAS;AAAA,IAChD;AACA,SAAK,YAAY,QAAQ,SAAS;AAAA,EACpC;AAAA,EAEA,gBAAgB,UAAkB;AAChC,WAAO,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,EACpC;AAAA,EAEA,MAAM,iBAAiB,UAAiC;AACtD,UAAM,KAAK,QAAQ,IAAI,KAAK,gBAAgB,KAAK,QAAQ,GAAG,QAAQ;AAAA,EACtE;AAAA,EAEA,MAAM,eAAgC;AACpC,UAAM,eAAe,MAAM,KAAK,QAAQ;AAAA,MACtC,KAAK,gBAAgB,KAAK,QAAQ;AAAA,IACpC;AACA,QAAI,CAAC,cAAc;AACjB,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AACF;","names":[]}