agents 0.5.1 → 0.6.0

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.
@@ -1,5 +1,6 @@
1
- import { t as MCPObservabilityEvent } from "./mcp-DA0kDE7K.js";
1
+ import { n as MCPObservabilityEvent } from "./agent-BHM7Gp_m.js";
2
2
  import { AgentMcpOAuthProvider } from "./mcp/do-oauth-client-provider.js";
3
+ import { McpAgent } from "./mcp/index.js";
3
4
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
4
5
  import {
5
6
  SSEClientTransport,
@@ -12,12 +13,24 @@ import {
12
13
  import {
13
14
  ElicitRequest,
14
15
  ElicitResult,
16
+ InitializeRequestParams,
17
+ JSONRPCMessage,
18
+ MessageExtraInfo,
15
19
  Prompt,
20
+ RequestId,
16
21
  Resource,
17
22
  ResourceTemplate,
18
23
  ServerCapabilities,
19
24
  Tool
20
25
  } from "@modelcontextprotocol/sdk/types.js";
26
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
27
+ import {
28
+ Transport,
29
+ TransportSendOptions
30
+ } from "@modelcontextprotocol/sdk/shared/transport.js";
31
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
32
+ import { Client as Client$1 } from "@modelcontextprotocol/sdk/client";
33
+ import { EventStore } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
21
34
 
22
35
  //#region src/core/events.d.ts
23
36
  interface Disposable {
@@ -33,7 +46,8 @@ declare class Emitter<T> implements Disposable {
33
46
  //#endregion
34
47
  //#region src/mcp/types.d.ts
35
48
  type MaybePromise<T> = T | Promise<T>;
36
- type BaseTransportType = "sse" | "streamable-http";
49
+ type HttpTransportType = "sse" | "streamable-http";
50
+ type BaseTransportType = HttpTransportType | "rpc";
37
51
  type TransportType = BaseTransportType | "auto";
38
52
  interface CORSOptions {
39
53
  origin?: string;
@@ -48,6 +62,221 @@ interface ServeOptions {
48
62
  transport?: BaseTransportType;
49
63
  jurisdiction?: DurableObjectJurisdiction;
50
64
  }
65
+ type McpClientOptions = ConstructorParameters<typeof Client$1>[1];
66
+ //#endregion
67
+ //#region src/mcp/client-transports.d.ts
68
+ /**
69
+ * @deprecated Use SSEClientTransport from @modelcontextprotocol/sdk/client/sse.js instead. This alias will be removed in the next major version.
70
+ */
71
+ declare class SSEEdgeClientTransport extends SSEClientTransport {
72
+ constructor(url: URL, options: SSEClientTransportOptions);
73
+ }
74
+ /**
75
+ * @deprecated Use StreamableHTTPClientTransport from @modelcontextprotocol/sdk/client/streamableHttp.js instead. This alias will be removed in the next major version.
76
+ */
77
+ declare class StreamableHTTPEdgeClientTransport extends StreamableHTTPClientTransport {
78
+ constructor(url: URL, options: StreamableHTTPClientTransportOptions);
79
+ }
80
+ //#endregion
81
+ //#region src/mcp/worker-transport.d.ts
82
+ interface MCPStorageApi {
83
+ get(): Promise<TransportState | undefined> | TransportState | undefined;
84
+ set(state: TransportState): Promise<void> | void;
85
+ }
86
+ interface TransportState {
87
+ sessionId?: string;
88
+ initialized: boolean;
89
+ initializeParams?: InitializeRequestParams;
90
+ }
91
+ interface WorkerTransportOptions {
92
+ /**
93
+ * Function that generates a session ID for the transport.
94
+ * The session ID SHOULD be globally unique and cryptographically secure.
95
+ * Return undefined to disable session management (stateless mode).
96
+ */
97
+ sessionIdGenerator?: () => string;
98
+ /**
99
+ * Enable traditional Request/Response mode, this will disable streaming.
100
+ */
101
+ enableJsonResponse?: boolean;
102
+ /**
103
+ * Callback fired when a new session is initialized.
104
+ */
105
+ onsessioninitialized?: (sessionId: string) => void;
106
+ /**
107
+ * Callback fired when a session is closed via DELETE request.
108
+ */
109
+ onsessionclosed?: (sessionId: string) => void;
110
+ corsOptions?: CORSOptions;
111
+ /**
112
+ * Optional storage api for persisting transport state.
113
+ * Use this to store session state in Durable Object/Agent storage
114
+ * so it survives hibernation/restart.
115
+ */
116
+ storage?: MCPStorageApi;
117
+ /**
118
+ * Event store for resumability support.
119
+ * If provided, enables clients to reconnect and resume messages using Last-Event-ID.
120
+ */
121
+ eventStore?: EventStore;
122
+ /**
123
+ * Retry interval in milliseconds to suggest to clients in SSE retry field.
124
+ * Controls client reconnection timing for polling behavior.
125
+ */
126
+ retryInterval?: number;
127
+ }
128
+ declare class WorkerTransport implements Transport {
129
+ started: boolean;
130
+ private initialized;
131
+ private sessionIdGenerator?;
132
+ private enableJsonResponse;
133
+ private onsessioninitialized?;
134
+ private onsessionclosed?;
135
+ private standaloneSseStreamId;
136
+ private streamMapping;
137
+ private requestToStreamMapping;
138
+ private requestResponseMap;
139
+ private corsOptions?;
140
+ private storage?;
141
+ private stateRestored;
142
+ private eventStore?;
143
+ private retryInterval?;
144
+ private initializeParams?;
145
+ sessionId?: string;
146
+ onclose?: () => void;
147
+ onerror?: (error: Error) => void;
148
+ onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void;
149
+ constructor(options?: WorkerTransportOptions);
150
+ /**
151
+ * Restore transport state from persistent storage.
152
+ * This is automatically called on start.
153
+ */
154
+ private restoreState;
155
+ /**
156
+ * Persist current transport state to storage.
157
+ */
158
+ private saveState;
159
+ start(): Promise<void>;
160
+ /**
161
+ * Validates the MCP-Protocol-Version header on incoming requests.
162
+ *
163
+ * This performs a simple check: if a version header is present, it must be
164
+ * in the SUPPORTED_PROTOCOL_VERSIONS list. We do not track the negotiated
165
+ * version or enforce version consistency across requests - the SDK handles
166
+ * version negotiation during initialization, and we simply reject any
167
+ * explicitly unsupported versions.
168
+ *
169
+ * - Header present and supported: Accept
170
+ * - Header present and unsupported: 400 Bad Request
171
+ * - Header missing: Accept (version validation is optional)
172
+ */
173
+ private validateProtocolVersion;
174
+ private getHeaders;
175
+ handleRequest(request: Request, parsedBody?: unknown): Promise<Response>;
176
+ private handleGetRequest;
177
+ private handlePostRequest;
178
+ private handleDeleteRequest;
179
+ private handleOptionsRequest;
180
+ private handleUnsupportedRequest;
181
+ private validateSession;
182
+ close(): Promise<void>;
183
+ /**
184
+ * Close an SSE stream for a specific request, triggering client reconnection.
185
+ * Use this to implement polling behavior during long-running operations -
186
+ * client will reconnect after the retry interval specified in the priming event.
187
+ */
188
+ closeSSEStream(requestId: RequestId): void;
189
+ send(message: JSONRPCMessage, options?: TransportSendOptions): Promise<void>;
190
+ }
191
+ //#endregion
192
+ //#region src/mcp/auth-context.d.ts
193
+ interface McpAuthContext {
194
+ props: Record<string, unknown>;
195
+ }
196
+ declare function getMcpAuthContext(): McpAuthContext | undefined;
197
+ //#endregion
198
+ //#region src/mcp/handler.d.ts
199
+ interface CreateMcpHandlerOptions extends WorkerTransportOptions {
200
+ /**
201
+ * The route path that this MCP handler should respond to.
202
+ * If specified, the handler will only process requests that match this route.
203
+ * @default "/mcp"
204
+ */
205
+ route?: string;
206
+ /**
207
+ * An optional auth context to use for handling MCP requests.
208
+ * If not provided, the handler will look for props in the execution context.
209
+ */
210
+ authContext?: McpAuthContext;
211
+ /**
212
+ * An optional transport to use for handling MCP requests.
213
+ * If not provided, a WorkerTransport will be created with the provided WorkerTransportOptions.
214
+ */
215
+ transport?: WorkerTransport;
216
+ }
217
+ declare function createMcpHandler(
218
+ server: McpServer | Server,
219
+ options?: CreateMcpHandlerOptions
220
+ ): (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;
221
+ /**
222
+ * @deprecated This has been renamed to createMcpHandler, and experimental_createMcpHandler will be removed in the next major version
223
+ */
224
+ declare function experimental_createMcpHandler(
225
+ server: McpServer | Server,
226
+ options?: CreateMcpHandlerOptions
227
+ ): (request: Request, env: unknown, ctx: ExecutionContext) => Promise<Response>;
228
+ //#endregion
229
+ //#region src/mcp/rpc.d.ts
230
+ declare const RPC_DO_PREFIX = "rpc:";
231
+ interface RPCClientTransportOptions<T extends McpAgent = McpAgent> {
232
+ namespace: DurableObjectNamespace<T>;
233
+ name: string;
234
+ props?: Record<string, unknown>;
235
+ }
236
+ declare class RPCClientTransport implements Transport {
237
+ private _namespace;
238
+ private _name;
239
+ private _props?;
240
+ private _stub?;
241
+ private _started;
242
+ private _protocolVersion?;
243
+ sessionId?: string;
244
+ onclose?: () => void;
245
+ onerror?: (error: Error) => void;
246
+ onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void;
247
+ constructor(options: RPCClientTransportOptions<McpAgent>);
248
+ setProtocolVersion(version: string): void;
249
+ getProtocolVersion(): string | undefined;
250
+ start(): Promise<void>;
251
+ close(): Promise<void>;
252
+ send(
253
+ message: JSONRPCMessage | JSONRPCMessage[],
254
+ options?: TransportSendOptions
255
+ ): Promise<void>;
256
+ }
257
+ interface RPCServerTransportOptions {
258
+ timeout?: number;
259
+ }
260
+ declare class RPCServerTransport implements Transport {
261
+ private _started;
262
+ private _pendingResponse;
263
+ private _responseResolver;
264
+ private _protocolVersion?;
265
+ private _timeout;
266
+ sessionId?: string;
267
+ onclose?: () => void;
268
+ onerror?: (error: Error) => void;
269
+ onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void;
270
+ constructor(options?: RPCServerTransportOptions);
271
+ setProtocolVersion(version: string): void;
272
+ getProtocolVersion(): string | undefined;
273
+ start(): Promise<void>;
274
+ close(): Promise<void>;
275
+ send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void>;
276
+ handle(
277
+ message: JSONRPCMessage | JSONRPCMessage[]
278
+ ): Promise<JSONRPCMessage | JSONRPCMessage[] | undefined>;
279
+ }
51
280
  //#endregion
52
281
  //#region src/mcp/client-connection.d.ts
53
282
  /**
@@ -71,9 +300,14 @@ declare const MCPConnectionState: {
71
300
  */
72
301
  type MCPConnectionState =
73
302
  (typeof MCPConnectionState)[keyof typeof MCPConnectionState];
303
+ /**
304
+ * Transport options for MCP client connections.
305
+ * Combines transport-specific options with auth provider and type selection.
306
+ */
74
307
  type MCPTransportOptions = (
75
308
  | SSEClientTransportOptions
76
309
  | StreamableHTTPClientTransportOptions
310
+ | RPCClientTransportOptions
77
311
  ) & {
78
312
  authProvider?: AgentMcpOAuthProvider;
79
313
  type?: TransportType;
@@ -91,7 +325,7 @@ declare class MCPClientConnection {
91
325
  url: URL;
92
326
  options: {
93
327
  transport: MCPTransportOptions;
94
- client: ConstructorParameters<typeof Client>[1];
328
+ client: McpClientOptions;
95
329
  };
96
330
  client: Client;
97
331
  connectionState: MCPConnectionState;
@@ -112,7 +346,7 @@ declare class MCPClientConnection {
112
346
  info: ConstructorParameters<typeof Client>[0],
113
347
  options?: {
114
348
  transport: MCPTransportOptions;
115
- client: ConstructorParameters<typeof Client>[1];
349
+ client: McpClientOptions;
116
350
  }
117
351
  );
118
352
  /**
@@ -320,7 +554,7 @@ declare class MCPClientConnection {
320
554
  */
321
555
  getTransport(
322
556
  transportType: BaseTransportType
323
- ): StreamableHTTPClientTransport | SSEClientTransport;
557
+ ): StreamableHTTPClientTransport | SSEClientTransport | RPCClientTransport;
324
558
  private tryConnect;
325
559
  private _capabilityErrorHandler;
326
560
  }
@@ -340,16 +574,31 @@ type MCPServerRow = {
340
574
  };
341
575
  //#endregion
342
576
  export {
343
- BaseTransportType as a,
344
- ServeOptions as c,
345
- Event as d,
577
+ ServeOptions as C,
578
+ Event as E,
579
+ McpClientOptions as S,
580
+ Emitter as T,
581
+ WorkerTransportOptions as _,
582
+ RPCClientTransport as a,
583
+ BaseTransportType as b,
584
+ RPCServerTransportOptions as c,
585
+ createMcpHandler as d,
586
+ experimental_createMcpHandler as f,
587
+ WorkerTransport as g,
588
+ TransportState as h,
346
589
  MCPTransportOptions as i,
347
- TransportType as l,
590
+ RPC_DO_PREFIX as l,
591
+ getMcpAuthContext as m,
348
592
  MCPClientConnection as n,
349
- CORSOptions as o,
593
+ RPCClientTransportOptions as o,
594
+ McpAuthContext as p,
350
595
  MCPConnectionState as r,
351
- MaybePromise as s,
596
+ RPCServerTransport as s,
352
597
  MCPServerRow as t,
353
- Emitter as u
598
+ CreateMcpHandlerOptions as u,
599
+ SSEEdgeClientTransport as v,
600
+ TransportType as w,
601
+ MaybePromise as x,
602
+ StreamableHTTPEdgeClientTransport as y
354
603
  };
355
- //# sourceMappingURL=client-storage-D633wI1S.d.ts.map
604
+ //# sourceMappingURL=client-storage-D5nDLKMW.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import { RetryOptions } from "../retries.js";
2
- import "../client-storage-D633wI1S.js";
2
+ import "../client-storage-D5nDLKMW.js";
3
3
  import { Agent, Schedule } from "../index.js";
4
4
 
5
5
  //#region src/experimental/forever.d.ts
package/dist/index.d.ts CHANGED
@@ -5,14 +5,15 @@ import {
5
5
  import { EmailResolver, createHeaderBasedEmailResolver } from "./email.js";
6
6
  import { RetryOptions } from "./retries.js";
7
7
  import {
8
- l as TransportType,
9
- r as MCPConnectionState
10
- } from "./client-storage-D633wI1S.js";
8
+ r as MCPConnectionState,
9
+ w as TransportType
10
+ } from "./client-storage-D5nDLKMW.js";
11
11
  import {
12
12
  AgentMcpOAuthProvider,
13
13
  AgentsOAuthProvider,
14
14
  DurableObjectOAuthClientProvider
15
15
  } from "./mcp/do-oauth-client-provider.js";
16
+ import { McpAgent } from "./mcp/index.js";
16
17
  import { MCPClientManager } from "./mcp/client.js";
17
18
  import {
18
19
  RunWorkflowOptions,
@@ -204,6 +205,12 @@ type AddMcpServerOptions = {
204
205
  } /** Retry options for connection and reconnection attempts */;
205
206
  retry?: RetryOptions;
206
207
  };
208
+ /**
209
+ * Options for adding an MCP server via RPC (Durable Object binding)
210
+ */
211
+ type AddRpcMcpServerOptions = {
212
+ /** Props to pass to the McpAgent instance */ props?: Record<string, unknown>;
213
+ };
207
214
  /**
208
215
  * Default options for Agent configuration.
209
216
  * Child classes can override specific options without spreading.
@@ -944,6 +951,8 @@ declare class Agent<
944
951
  * Returns undefined if no match found - use options.agentBinding as fallback.
945
952
  */
946
953
  private _findAgentBindingName;
954
+ private _findBindingNameForNamespace;
955
+ private _restoreRpcMcpServers;
947
956
  /**
948
957
  * Handle a callback from a workflow.
949
958
  * Called when the Agent receives a callback at /_workflow/callback.
@@ -1023,29 +1032,30 @@ declare class Agent<
1023
1032
  state?: unknown
1024
1033
  ): void;
1025
1034
  /**
1026
- * Connect to a new MCP Server
1035
+ * Connect to a new MCP Server via RPC (Durable Object binding)
1027
1036
  *
1028
- * @example
1029
- * // Simple usage
1030
- * await this.addMcpServer("github", "https://mcp.github.com");
1037
+ * The binding name and props are persisted to storage so the connection
1038
+ * is automatically restored after Durable Object hibernation.
1031
1039
  *
1032
1040
  * @example
1033
- * // With options (preferred for custom headers, transport, etc.)
1034
- * await this.addMcpServer("github", "https://mcp.github.com", {
1035
- * transport: { headers: { "Authorization": "Bearer ..." } }
1036
- * });
1041
+ * await this.addMcpServer("counter", env.MY_MCP);
1042
+ * await this.addMcpServer("counter", env.MY_MCP, { props: { userId: "123" } });
1043
+ */
1044
+ addMcpServer<T extends McpAgent>(
1045
+ serverName: string,
1046
+ binding: DurableObjectNamespace<T>,
1047
+ options?: AddRpcMcpServerOptions
1048
+ ): Promise<{
1049
+ id: string;
1050
+ state: typeof MCPConnectionState.READY;
1051
+ }>;
1052
+ /**
1053
+ * Connect to a new MCP Server via HTTP (SSE or Streamable HTTP)
1037
1054
  *
1038
1055
  * @example
1039
- * // Legacy 5-parameter signature (still supported)
1040
- * await this.addMcpServer("github", url, callbackHost, agentsPrefix, options);
1041
- *
1042
- * @param serverName Name of the MCP server
1043
- * @param url MCP Server URL
1044
- * @param callbackHostOrOptions Options object, or callback host string (legacy)
1045
- * @param agentsPrefix agents routing prefix if not using `agents` (legacy)
1046
- * @param options MCP client and transport options (legacy)
1047
- * @returns Server id and state - either "authenticating" with authUrl, or "ready"
1048
- * @throws If connection or discovery fails
1056
+ * await this.addMcpServer("github", "https://mcp.github.com");
1057
+ * await this.addMcpServer("github", "https://mcp.github.com", { transport: { type: "sse" } });
1058
+ * await this.addMcpServer("github", url, callbackHost, agentsPrefix, options); // legacy
1049
1059
  */
1050
1060
  addMcpServer(
1051
1061
  serverName: string,
@@ -1068,7 +1078,6 @@ declare class Agent<
1068
1078
  | {
1069
1079
  id: string;
1070
1080
  state: typeof MCPConnectionState.READY;
1071
- authUrl?: undefined;
1072
1081
  }
1073
1082
  >;
1074
1083
  removeMcpServer(id: string): Promise<void>;
@@ -1223,6 +1232,7 @@ declare class StreamingResponse {
1223
1232
  //#endregion
1224
1233
  export {
1225
1234
  AddMcpServerOptions,
1235
+ AddRpcMcpServerOptions,
1226
1236
  Agent,
1227
1237
  AgentContext,
1228
1238
  type AgentMcpOAuthProvider,
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { camelCaseToKebabCase } from "./utils.js";
3
3
  import { createHeaderBasedEmailResolver, signAgentHeaders } from "./email.js";
4
4
  import { __DO_NOT_USE_WILL_BREAK__agentContext } from "./internal_context.js";
5
5
  import { isErrorRetryable, tryN, validateRetryOptions } from "./retries.js";
6
- import { i as DisposableStore, n as MCPConnectionState } from "./client-connection-CGMuV62J.js";
6
+ import { a as RPC_DO_PREFIX, n as MCPConnectionState, s as DisposableStore } from "./client-connection-BqngKttp.js";
7
7
  import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider.js";
8
8
  import { MCPClientManager } from "./mcp/client.js";
9
9
  import { genericObservability } from "./observability/index.js";
@@ -66,6 +66,7 @@ const unstable_callable = (metadata = {}) => {
66
66
  function getNextCronTime(cron) {
67
67
  return parseCronExpression(cron).getNextDate();
68
68
  }
69
+ let _didWarnRpcExperimental = false;
69
70
  const STATE_ROW_ID = "cf_state_row_id";
70
71
  const STATE_WAS_CHANGED = "cf_state_was_changed";
71
72
  const DEFAULT_STATE = {};
@@ -606,6 +607,7 @@ var Agent = class Agent extends Server {
606
607
  }, async () => {
607
608
  await this._tryCatch(async () => {
608
609
  await this.mcp.restoreConnectionsFromStorage(this.name);
610
+ await this._restoreRpcMcpServers();
609
611
  this.broadcastMcpServers();
610
612
  this._checkOrphanedWorkflows();
611
613
  return _onStart(props);
@@ -2096,6 +2098,37 @@ var Agent = class Agent extends Server {
2096
2098
  if (key === className || camelCaseToKebabCase(key) === camelCaseToKebabCase(className)) return key;
2097
2099
  }
2098
2100
  }
2101
+ _findBindingNameForNamespace(namespace) {
2102
+ for (const [key, value] of Object.entries(this.env)) if (value === namespace) return key;
2103
+ }
2104
+ async _restoreRpcMcpServers() {
2105
+ const rpcServers = this.mcp.getRpcServersFromStorage();
2106
+ for (const server of rpcServers) {
2107
+ if (this.mcp.mcpConnections[server.id]) continue;
2108
+ const opts = server.server_options ? JSON.parse(server.server_options) : {};
2109
+ const namespace = this.env[opts.bindingName];
2110
+ if (!namespace) {
2111
+ console.warn(`[Agent] Cannot restore RPC MCP server "${server.name}": binding "${opts.bindingName}" not found in env`);
2112
+ continue;
2113
+ }
2114
+ const normalizedName = server.server_url.replace(RPC_DO_PREFIX, "");
2115
+ try {
2116
+ await this.mcp.connect(`${RPC_DO_PREFIX}${normalizedName}`, {
2117
+ reconnect: { id: server.id },
2118
+ transport: {
2119
+ type: "rpc",
2120
+ namespace,
2121
+ name: normalizedName,
2122
+ props: opts.props
2123
+ }
2124
+ });
2125
+ const conn = this.mcp.mcpConnections[server.id];
2126
+ if (conn && conn.connectionState === MCPConnectionState.CONNECTED) await this.mcp.discoverIfConnected(server.id);
2127
+ } catch (error) {
2128
+ console.error(`[Agent] Error restoring RPC MCP server "${server.name}":`, error);
2129
+ }
2130
+ }
2131
+ }
2099
2132
  /**
2100
2133
  * Handle a callback from a workflow.
2101
2134
  * Called when the Agent receives a callback at /_workflow/callback.
@@ -2202,63 +2235,90 @@ var Agent = class Agent extends Server {
2202
2235
  });
2203
2236
  } else if (action === "reset") this.setState(this.initialState);
2204
2237
  }
2205
- /**
2206
- * Connect to a new MCP Server
2207
- *
2208
- * @example
2209
- * // Simple usage
2210
- * await this.addMcpServer("github", "https://mcp.github.com");
2211
- *
2212
- * @example
2213
- * // With options (preferred for custom headers, transport, etc.)
2214
- * await this.addMcpServer("github", "https://mcp.github.com", {
2215
- * transport: { headers: { "Authorization": "Bearer ..." } }
2216
- * });
2217
- *
2218
- * @example
2219
- * // Legacy 5-parameter signature (still supported)
2220
- * await this.addMcpServer("github", url, callbackHost, agentsPrefix, options);
2221
- *
2222
- * @param serverName Name of the MCP server
2223
- * @param url MCP Server URL
2224
- * @param callbackHostOrOptions Options object, or callback host string (legacy)
2225
- * @param agentsPrefix agents routing prefix if not using `agents` (legacy)
2226
- * @param options MCP client and transport options (legacy)
2227
- * @returns Server id and state - either "authenticating" with authUrl, or "ready"
2228
- * @throws If connection or discovery fails
2229
- */
2230
- async addMcpServer(serverName, url, callbackHostOrOptions, agentsPrefix, options) {
2238
+ async addMcpServer(serverName, urlOrBinding, callbackHostOrOptions, agentsPrefix, options) {
2239
+ const existingServer = this.mcp.listServers().find((s) => s.name === serverName);
2240
+ if (existingServer && this.mcp.mcpConnections[existingServer.id]) {
2241
+ const conn = this.mcp.mcpConnections[existingServer.id];
2242
+ if (conn.connectionState === MCPConnectionState.AUTHENTICATING && conn.options.transport.authProvider?.authUrl) return {
2243
+ id: existingServer.id,
2244
+ state: MCPConnectionState.AUTHENTICATING,
2245
+ authUrl: conn.options.transport.authProvider.authUrl
2246
+ };
2247
+ if (conn.connectionState === MCPConnectionState.FAILED) throw new Error(`MCP server "${serverName}" is in failed state: ${conn.connectionError}`);
2248
+ return {
2249
+ id: existingServer.id,
2250
+ state: MCPConnectionState.READY
2251
+ };
2252
+ }
2253
+ if (typeof urlOrBinding !== "string") {
2254
+ if (!_didWarnRpcExperimental) {
2255
+ _didWarnRpcExperimental = true;
2256
+ console.warn("[agents] addMcpServer with a Durable Object binding (RPC transport) is experimental. The API may change between releases. We'd love your feedback: https://github.com/cloudflare/agents/issues/548");
2257
+ }
2258
+ const rpcOpts = callbackHostOrOptions;
2259
+ const normalizedName = serverName.toLowerCase().replace(/\s+/g, "-");
2260
+ const reconnectId = existingServer?.id;
2261
+ const { id } = await this.mcp.connect(`${RPC_DO_PREFIX}${normalizedName}`, {
2262
+ reconnect: reconnectId ? { id: reconnectId } : void 0,
2263
+ transport: {
2264
+ type: "rpc",
2265
+ namespace: urlOrBinding,
2266
+ name: normalizedName,
2267
+ props: rpcOpts?.props
2268
+ }
2269
+ });
2270
+ const conn = this.mcp.mcpConnections[id];
2271
+ if (conn && conn.connectionState === MCPConnectionState.CONNECTED) {
2272
+ const discoverResult = await this.mcp.discoverIfConnected(id);
2273
+ if (discoverResult && !discoverResult.success) throw new Error(`Failed to discover MCP server capabilities: ${discoverResult.error}`);
2274
+ } else if (conn && conn.connectionState === MCPConnectionState.FAILED) throw new Error(`Failed to connect to MCP server "${serverName}" via RPC: ${conn.connectionError}`);
2275
+ const bindingName = this._findBindingNameForNamespace(urlOrBinding);
2276
+ if (bindingName) this.mcp.saveRpcServerToStorage(id, serverName, normalizedName, bindingName, rpcOpts?.props);
2277
+ return {
2278
+ id,
2279
+ state: MCPConnectionState.READY
2280
+ };
2281
+ }
2282
+ const url = urlOrBinding;
2283
+ const httpOptions = callbackHostOrOptions;
2231
2284
  let resolvedCallbackHost;
2232
2285
  let resolvedAgentsPrefix;
2233
2286
  let resolvedOptions;
2234
2287
  let resolvedCallbackPath;
2235
- if (typeof callbackHostOrOptions === "object" && callbackHostOrOptions !== null) {
2236
- resolvedCallbackHost = callbackHostOrOptions.callbackHost;
2237
- resolvedCallbackPath = callbackHostOrOptions.callbackPath;
2238
- resolvedAgentsPrefix = callbackHostOrOptions.agentsPrefix ?? "agents";
2288
+ if (typeof httpOptions === "object" && httpOptions !== null) {
2289
+ resolvedCallbackHost = httpOptions.callbackHost;
2290
+ resolvedCallbackPath = httpOptions.callbackPath;
2291
+ resolvedAgentsPrefix = httpOptions.agentsPrefix ?? "agents";
2239
2292
  resolvedOptions = {
2240
- client: callbackHostOrOptions.client,
2241
- transport: callbackHostOrOptions.transport,
2242
- retry: callbackHostOrOptions.retry
2293
+ client: httpOptions.client,
2294
+ transport: httpOptions.transport,
2295
+ retry: httpOptions.retry
2243
2296
  };
2244
2297
  } else {
2245
- resolvedCallbackHost = callbackHostOrOptions;
2298
+ resolvedCallbackHost = httpOptions;
2246
2299
  resolvedAgentsPrefix = agentsPrefix ?? "agents";
2247
2300
  resolvedOptions = options;
2248
2301
  }
2249
- if (!this._resolvedOptions.sendIdentityOnConnect && !resolvedCallbackPath) throw new Error("callbackPath is required in addMcpServer options when sendIdentityOnConnect is false — the default callback URL would expose the instance name. Provide a callbackPath and route the callback request to this agent via getAgentByName.");
2302
+ if (!this._resolvedOptions.sendIdentityOnConnect && resolvedCallbackHost && !resolvedCallbackPath) throw new Error("callbackPath is required in addMcpServer options when sendIdentityOnConnect is false — the default callback URL would expose the instance name. Provide a callbackPath and route the callback request to this agent via getAgentByName.");
2250
2303
  if (!resolvedCallbackHost) {
2251
2304
  const { request } = getCurrentAgent();
2252
- if (!request) throw new Error("callbackHost is required when not called within a request context");
2253
- const requestUrl = new URL(request.url);
2254
- resolvedCallbackHost = `${requestUrl.protocol}//${requestUrl.host}`;
2305
+ if (request) {
2306
+ const requestUrl = new URL(request.url);
2307
+ resolvedCallbackHost = `${requestUrl.protocol}//${requestUrl.host}`;
2308
+ }
2309
+ }
2310
+ let callbackUrl;
2311
+ if (resolvedCallbackHost) {
2312
+ const normalizedHost = resolvedCallbackHost.replace(/\/$/, "");
2313
+ callbackUrl = resolvedCallbackPath ? `${normalizedHost}/${resolvedCallbackPath.replace(/^\//, "")}` : `${normalizedHost}/${resolvedAgentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
2255
2314
  }
2256
- const normalizedHost = resolvedCallbackHost.replace(/\/$/, "");
2257
- const callbackUrl = resolvedCallbackPath ? `${normalizedHost}/${resolvedCallbackPath.replace(/^\//, "")}` : `${normalizedHost}/${resolvedAgentsPrefix}/${camelCaseToKebabCase(this._ParentClass.name)}/${this.name}/callback`;
2258
2315
  await this.mcp.ensureJsonSchema();
2259
2316
  const id = nanoid(8);
2260
- const authProvider = this.createMcpOAuthProvider(callbackUrl);
2261
- authProvider.serverId = id;
2317
+ let authProvider;
2318
+ if (callbackUrl) {
2319
+ authProvider = this.createMcpOAuthProvider(callbackUrl);
2320
+ authProvider.serverId = id;
2321
+ }
2262
2322
  const transportType = resolvedOptions?.transport?.type ?? "auto";
2263
2323
  let headerTransportOpts = {};
2264
2324
  if (resolvedOptions?.transport?.headers) headerTransportOpts = {
@@ -2282,11 +2342,14 @@ var Agent = class Agent extends Server {
2282
2342
  });
2283
2343
  const result = await this.mcp.connectToServer(id);
2284
2344
  if (result.state === MCPConnectionState.FAILED) throw new Error(`Failed to connect to MCP server at ${url}: ${result.error}`);
2285
- if (result.state === MCPConnectionState.AUTHENTICATING) return {
2286
- id,
2287
- state: result.state,
2288
- authUrl: result.authUrl
2289
- };
2345
+ if (result.state === MCPConnectionState.AUTHENTICATING) {
2346
+ if (!callbackUrl) throw new Error("This MCP server requires OAuth authentication. Provide callbackHost in addMcpServer options to enable the OAuth flow.");
2347
+ return {
2348
+ id,
2349
+ state: result.state,
2350
+ authUrl: result.authUrl
2351
+ };
2352
+ }
2290
2353
  const discoverResult = await this.mcp.discoverIfConnected(id);
2291
2354
  if (discoverResult && !discoverResult.success) throw new Error(`Failed to discover MCP server capabilities: ${discoverResult.error}`);
2292
2355
  return {