UNPKG

agents

Version:
1,506 lines 53 kB
import { t as MessageType } from "../types-BITaDFf-.js";
import "../email-XHsSYsTO.js";
import "../internal_context-D9eKFth1.js";
import "../client-CtC9E06G.js";
import "../do-oauth-client-provider-DDg8QrEA.js";
import { o as getAgentByName, s as getCurrentAgent, t as Agent } from "../src-i_UcyBYf.js";
import { AsyncLocalStorage } from "node:async_hooks";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { ElicitRequestSchema, InitializeRequestSchema, JSONRPCMessageSchema, SUPPORTED_PROTOCOL_VERSIONS, isInitializeRequest, isJSONRPCErrorResponse, isJSONRPCNotification, isJSONRPCRequest, isJSONRPCResultResponse } from "@modelcontextprotocol/sdk/types.js";

//#region src/mcp/utils.ts
/**
* Since we use WebSockets to bridge the client to the
* MCP transport in the Agent, we use this header to signal
* the method of the original request the user made, while
* leaving the WS Upgrade request as GET.
*/
const MCP_HTTP_METHOD_HEADER = "cf-mcp-method";
/**
* Since we use WebSockets to bridge the client to the
* MCP transport in the Agent, we use this header to include
* the original request body.
*/
const MCP_MESSAGE_HEADER = "cf-mcp-message";
const MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024;
const createStreamingHttpHandler = (basePath, namespace, options = {}) => {
	let pathname = basePath;
	if (basePath === "/") pathname = "/*";
	const basePattern = new URLPattern({ pathname });
	return async (request, ctx) => {
		const url = new URL(request.url);
		if (basePattern.test(url)) {
			if (request.method === "POST") {
				const acceptHeader = request.headers.get("accept");
				if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
					const body = JSON.stringify({
						error: {
							code: -32e3,
							message: "Not Acceptable: Client must accept both application/json and text/event-stream"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 406 });
				}
				const ct = request.headers.get("content-type");
				if (!ct || !ct.includes("application/json")) {
					const body = JSON.stringify({
						error: {
							code: -32e3,
							message: "Unsupported Media Type: Content-Type must be application/json"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 415 });
				}
				if (Number.parseInt(request.headers.get("content-length") ?? "0", 10) > MAXIMUM_MESSAGE_SIZE_BYTES) {
					const body = JSON.stringify({
						error: {
							code: -32e3,
							message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 413 });
				}
				let sessionId = request.headers.get("mcp-session-id");
				let rawMessage;
				try {
					rawMessage = await request.json();
				} catch (_error) {
					const body = JSON.stringify({
						error: {
							code: -32700,
							message: "Parse error: Invalid JSON"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 400 });
				}
				let arrayMessage;
				if (Array.isArray(rawMessage)) arrayMessage = rawMessage;
				else arrayMessage = [rawMessage];
				let messages = [];
				for (const msg of arrayMessage) if (!JSONRPCMessageSchema.safeParse(msg).success) {
					const body = JSON.stringify({
						error: {
							code: -32700,
							message: "Parse error: Invalid JSON-RPC message"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 400 });
				}
				messages = arrayMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
				const maybeInitializeRequest = messages.find((msg) => InitializeRequestSchema.safeParse(msg).success);
				if (!!maybeInitializeRequest && sessionId) {
					const body = JSON.stringify({
						error: {
							code: -32600,
							message: "Invalid Request: Initialization requests must not include a sessionId"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 400 });
				}
				if (!!maybeInitializeRequest && messages.length > 1) {
					const body = JSON.stringify({
						error: {
							code: -32600,
							message: "Invalid Request: Only one initialization request is allowed"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 400 });
				}
				if (!maybeInitializeRequest && !sessionId) {
					const body = JSON.stringify({
						error: {
							code: -32e3,
							message: "Bad Request: Mcp-Session-Id header is required"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 400 });
				}
				sessionId = sessionId ?? namespace.newUniqueId().toString();
				const agent = await getAgentByName(namespace, `streamable-http:${sessionId}`, {
					props: ctx.props,
					jurisdiction: options.jurisdiction
				});
				const isInitialized = await agent.getInitializeRequest();
				if (maybeInitializeRequest) await agent.setInitializeRequest(maybeInitializeRequest);
				else if (!isInitialized) {
					const body = JSON.stringify({
						error: {
							code: -32001,
							message: "Session not found"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 404 });
				}
				const { readable, writable } = new TransformStream();
				const writer = writable.getWriter();
				const encoder = new TextEncoder();
				const existingHeaders = {};
				request.headers.forEach((value, key) => {
					existingHeaders[key] = value;
				});
				const req = new Request(request.url, { headers: {
					...existingHeaders,
					[MCP_HTTP_METHOD_HEADER]: "POST",
					[MCP_MESSAGE_HEADER]: Buffer.from(JSON.stringify(messages)).toString("base64"),
					Upgrade: "websocket"
				} });
				if (ctx.props) agent.updateProps(ctx.props);
				const ws = (await agent.fetch(req)).webSocket;
				if (!ws) {
					console.error("Failed to establish WebSocket connection");
					await writer.close();
					const body = JSON.stringify({
						error: {
							code: -32001,
							message: "Failed to establish WebSocket connection"
						},
						id: null,
						jsonrpc: "2.0"
					});
					return new Response(body, { status: 500 });
				}
				ws.accept();
				ws.addEventListener("message", (event) => {
					async function onMessage(event) {
						try {
							const data = typeof event.data === "string" ? event.data : new TextDecoder().decode(event.data);
							const message = JSON.parse(data);
							if (message.type !== MessageType.CF_MCP_AGENT_EVENT) return;
							await writer.write(encoder.encode(message.event));
							if (message.close) {
								ws?.close();
								await writer.close().catch(() => {});
							}
						} catch (error) {
							console.error("Error forwarding message to SSE:", error);
						}
					}
					onMessage(event).catch(console.error);
				});
				ws.addEventListener("error", (error) => {
					async function onError(_error) {
						await writer.close().catch(() => {});
					}
					onError(error).catch(console.error);
				});
				ws.addEventListener("close", () => {
					async function onClose() {
						await writer.close().catch(() => {});
					}
					onClose().catch(console.error);
				});
				if (messages.every((msg) => isJSONRPCNotification(msg) || isJSONRPCResultResponse(msg))) {
					ws.close();
					return new Response(null, {
						headers: corsHeaders(request, options.corsOptions),
						status: 202
					});
				}
				return new Response(readable, {
					headers: {
						"Cache-Control": "no-cache",
						Connection: "keep-alive",
						"Content-Type": "text/event-stream",
						"mcp-session-id": sessionId,
						...corsHeaders(request, options.corsOptions)
					},
					status: 200
				});
			} else if (request.method === "GET") {
				if (!request.headers.get("accept")?.includes("text/event-stream")) {
					const body = JSON.stringify({
						jsonrpc: "2.0",
						error: {
							code: -32e3,
							message: "Not Acceptable: Client must accept text/event-stream"
						},
						id: null
					});
					return new Response(body, { status: 406 });
				}
				const sessionId = request.headers.get("mcp-session-id");
				if (!sessionId) return new Response(JSON.stringify({
					error: {
						code: -32e3,
						message: "Bad Request: Mcp-Session-Id header is required"
					},
					id: null,
					jsonrpc: "2.0"
				}), { status: 400 });
				const { readable, writable } = new TransformStream();
				const writer = writable.getWriter();
				const encoder = new TextEncoder();
				const agent = await getAgentByName(namespace, `streamable-http:${sessionId}`, {
					props: ctx.props,
					jurisdiction: options.jurisdiction
				});
				if (!await agent.getInitializeRequest()) return new Response(JSON.stringify({
					jsonrpc: "2.0",
					error: {
						code: -32001,
						message: "Session not found"
					},
					id: null
				}), { status: 404 });
				const existingHeaders = {};
				request.headers.forEach((v, k) => {
					existingHeaders[k] = v;
				});
				if (ctx.props) agent.updateProps(ctx.props);
				const ws = (await agent.fetch(new Request(request.url, { headers: {
					...existingHeaders,
					[MCP_HTTP_METHOD_HEADER]: "GET",
					Upgrade: "websocket"
				} }))).webSocket;
				if (!ws) {
					await writer.close();
					return new Response("Failed to establish WS to DO", { status: 500 });
				}
				ws.accept();
				ws.addEventListener("message", (event) => {
					try {
						async function onMessage(ev) {
							const data = typeof ev.data === "string" ? ev.data : new TextDecoder().decode(ev.data);
							const message = JSON.parse(data);
							if (message.type !== MessageType.CF_MCP_AGENT_EVENT) return;
							await writer.write(encoder.encode(message.event));
						}
						onMessage(event).catch(console.error);
					} catch (e) {
						console.error("Error forwarding message to SSE:", e);
					}
				});
				ws.addEventListener("error", () => {
					writer.close().catch(() => {});
				});
				ws.addEventListener("close", () => {
					writer.close().catch(() => {});
				});
				return new Response(readable, {
					headers: {
						"Cache-Control": "no-cache",
						Connection: "keep-alive",
						"Content-Type": "text/event-stream",
						"mcp-session-id": sessionId,
						...corsHeaders(request, options.corsOptions)
					},
					status: 200
				});
			} else if (request.method === "DELETE") {
				const sessionId = request.headers.get("mcp-session-id");
				if (!sessionId) return new Response(JSON.stringify({
					jsonrpc: "2.0",
					error: {
						code: -32e3,
						message: "Bad Request: Mcp-Session-Id header is required"
					},
					id: null
				}), {
					status: 400,
					headers: corsHeaders(request, options.corsOptions)
				});
				const agent = await getAgentByName(namespace, `streamable-http:${sessionId}`, { jurisdiction: options.jurisdiction });
				if (!await agent.getInitializeRequest()) return new Response(JSON.stringify({
					jsonrpc: "2.0",
					error: {
						code: -32001,
						message: "Session not found"
					},
					id: null
				}), {
					status: 404,
					headers: corsHeaders(request, options.corsOptions)
				});
				ctx.waitUntil(agent.destroy().catch(() => {}));
				return new Response(null, {
					status: 204,
					headers: corsHeaders(request, options.corsOptions)
				});
			}
		}
		const body = JSON.stringify({
			error: {
				code: -32e3,
				message: "Not found"
			},
			id: null,
			jsonrpc: "2.0"
		});
		return new Response(body, { status: 404 });
	};
};
const createLegacySseHandler = (basePath, namespace, options = {}) => {
	let pathname = basePath;
	if (basePath === "/") pathname = "/*";
	const basePattern = new URLPattern({ pathname });
	const messagePattern = new URLPattern({ pathname: `${basePath}/message` });
	return async (request, ctx) => {
		const url = new URL(request.url);
		if (request.method === "GET" && basePattern.test(url)) {
			const sessionId = url.searchParams.get("sessionId") || namespace.newUniqueId().toString();
			const { readable, writable } = new TransformStream();
			const writer = writable.getWriter();
			const encoder = new TextEncoder();
			const endpointUrl = new URL(request.url);
			endpointUrl.pathname = encodeURI(`${basePath}/message`);
			endpointUrl.searchParams.set("sessionId", sessionId);
			const endpointMessage = `event: endpoint\ndata: ${endpointUrl.pathname + endpointUrl.search + endpointUrl.hash}\n\n`;
			writer.write(encoder.encode(endpointMessage));
			const agent = await getAgentByName(namespace, `sse:${sessionId}`, {
				props: ctx.props,
				jurisdiction: options.jurisdiction
			});
			const existingHeaders = {};
			request.headers.forEach((value, key) => {
				existingHeaders[key] = value;
			});
			if (ctx.props) agent.updateProps(ctx.props);
			const ws = (await agent.fetch(new Request(request.url, { headers: {
				...existingHeaders,
				Upgrade: "websocket"
			} }))).webSocket;
			if (!ws) {
				console.error("Failed to establish WebSocket connection");
				await writer.close();
				return new Response("Failed to establish WebSocket connection", { status: 500 });
			}
			ws.accept();
			ws.addEventListener("message", (event) => {
				async function onMessage(event) {
					try {
						const message = JSON.parse(event.data);
						const result = JSONRPCMessageSchema.safeParse(message);
						if (!result.success) return;
						const messageText = `event: message\ndata: ${JSON.stringify(result.data)}\n\n`;
						await writer.write(encoder.encode(messageText));
					} catch (error) {
						console.error("Error forwarding message to SSE:", error);
					}
				}
				onMessage(event).catch(console.error);
			});
			ws.addEventListener("error", (error) => {
				async function onError(_error) {
					try {
						await writer.close();
					} catch (_e) {}
				}
				onError(error).catch(console.error);
			});
			ws.addEventListener("close", () => {
				async function onClose() {
					try {
						await writer.close();
					} catch (error) {
						console.error("Error closing SSE connection:", error);
					}
				}
				onClose().catch(console.error);
			});
			return new Response(readable, { headers: {
				"Cache-Control": "no-cache",
				Connection: "keep-alive",
				"Content-Type": "text/event-stream",
				...corsHeaders(request, options.corsOptions)
			} });
		}
		if (request.method === "POST" && messagePattern.test(url)) {
			const sessionId = url.searchParams.get("sessionId");
			if (!sessionId) return new Response(`Missing sessionId. Expected POST to ${basePath} to initiate new one`, { status: 400 });
			const contentType = request.headers.get("content-type") || "";
			if (!contentType.includes("application/json")) return new Response(`Unsupported content-type: ${contentType}`, { status: 400 });
			const contentLength = Number.parseInt(request.headers.get("content-length") || "0", 10);
			if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) return new Response(`Request body too large: ${contentLength} bytes`, { status: 400 });
			const agent = await getAgentByName(namespace, `sse:${sessionId}`, {
				props: ctx.props,
				jurisdiction: options.jurisdiction
			});
			const messageBody = await request.json();
			const extraInfo = { requestInfo: { headers: Object.fromEntries(request.headers.entries()) } };
			const error = await agent.onSSEMcpMessage(sessionId, messageBody, extraInfo);
			if (error) return new Response(error.message, {
				headers: {
					"Cache-Control": "no-cache",
					Connection: "keep-alive",
					"Content-Type": "text/event-stream",
					...corsHeaders(request, options.corsOptions)
				},
				status: 400
			});
			return new Response("Accepted", {
				headers: {
					"Cache-Control": "no-cache",
					Connection: "keep-alive",
					"Content-Type": "text/event-stream",
					...corsHeaders(request, options.corsOptions)
				},
				status: 202
			});
		}
		return new Response("Not Found", { status: 404 });
	};
};
function corsHeaders(_request, corsOptions = {}) {
	const origin = "*";
	return {
		"Access-Control-Allow-Headers": corsOptions.headers || "Content-Type, Accept, mcp-session-id, mcp-protocol-version",
		"Access-Control-Allow-Methods": corsOptions.methods || "GET, POST, DELETE, OPTIONS",
		"Access-Control-Allow-Origin": corsOptions.origin || origin,
		"Access-Control-Expose-Headers": corsOptions.exposeHeaders || "mcp-session-id",
		"Access-Control-Max-Age": (corsOptions.maxAge || 86400).toString()
	};
}
function handleCORS(request, corsOptions) {
	if (request.method === "OPTIONS") return new Response(null, { headers: corsHeaders(request, corsOptions) });
	return null;
}
function isDurableObjectNamespace(namespace) {
	return typeof namespace === "object" && namespace !== null && "newUniqueId" in namespace && typeof namespace.newUniqueId === "function" && "idFromName" in namespace && typeof namespace.idFromName === "function";
}

//#endregion
//#region src/mcp/transport.ts
var McpSSETransport = class {
	constructor() {
		this._started = false;
		const { agent } = getCurrentAgent();
		if (!agent) throw new Error("McpAgent was not found in Transport constructor");
		this.sessionId = agent.getSessionId();
		this._getWebSocket = () => agent.getWebSocket();
	}
	async start() {
		if (this._started) throw new Error("Transport already started");
		this._started = true;
	}
	async send(message) {
		if (!this._started) throw new Error("Transport not started");
		const websocket = this._getWebSocket();
		if (!websocket) throw new Error("WebSocket not connected");
		try {
			websocket.send(JSON.stringify(message));
		} catch (error) {
			this.onerror?.(error);
		}
	}
	async close() {
		this.onclose?.();
	}
};
/**
* Adapted from: https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/client/streamableHttp.ts
* - Validation and initialization are removed as they're handled in `McpAgent.serve()` handler.
* - Replaces the Node-style `req`/`res` with Worker's `Request`.
* - Writes events as WS messages that the Worker forwards to the client as SSE events.
* - Replaces the in-memory maps that track requestID/stream by using `connection.setState()` and `agent.getConnections()`.
*
* Besides these points, the implementation is the same and should be updated to match the original as new features are added.
*/
var StreamableHTTPServerTransport = class {
	constructor(options) {
		this._started = false;
		this._requestResponseMap = /* @__PURE__ */ new Map();
		const { agent } = getCurrentAgent();
		if (!agent) throw new Error("McpAgent was not found in Transport constructor");
		this.sessionId = agent.getSessionId();
		this._eventStore = options.eventStore;
	}
	/**
	* Starts the transport. This is required by the Transport interface but is a no-op
	* for the Streamable HTTP transport as connections are managed per-request.
	*/
	async start() {
		if (this._started) throw new Error("Transport already started");
		this._started = true;
	}
	/**
	* Handles GET requests for SSE stream
	*/
	async handleGetRequest(req) {
		const { connection } = getCurrentAgent();
		if (!connection) throw new Error("Connection was not found in handleGetRequest");
		if (this._eventStore) {
			const lastEventId = req.headers.get("last-event-id");
			if (lastEventId) {
				await this.replayEvents(lastEventId);
				return;
			}
		}
		connection.setState({ _standaloneSse: true });
	}
	/**
	* Replays events that would have been sent after the specified event ID
	* Only used when resumability is enabled
	*/
	async replayEvents(lastEventId) {
		if (!this._eventStore) return;
		const { connection } = getCurrentAgent();
		if (!connection) throw new Error("Connection was not available in replayEvents");
		try {
			await this._eventStore?.replayEventsAfter(lastEventId, { send: async (eventId, message) => {
				try {
					this.writeSSEEvent(connection, message, eventId);
				} catch (error) {
					this.onerror?.(error);
				}
			} });
		} catch (error) {
			this.onerror?.(error);
		}
	}
	/**
	* Writes an event to the SSE stream with proper formatting
	*/
	writeSSEEvent(connection, message, eventId, close) {
		let eventData = "event: message\n";
		if (eventId) eventData += `id: ${eventId}\n`;
		eventData += `data: ${JSON.stringify(message)}\n\n`;
		return connection.send(JSON.stringify({
			type: MessageType.CF_MCP_AGENT_EVENT,
			event: eventData,
			close
		}));
	}
	/**
	* Handles POST requests containing JSON-RPC messages
	*/
	async handlePostRequest(req, parsedBody) {
		const authInfo = req.auth;
		const requestInfo = { headers: Object.fromEntries(req.headers.entries()) };
		delete requestInfo.headers[MCP_HTTP_METHOD_HEADER];
		delete requestInfo.headers[MCP_MESSAGE_HEADER];
		delete requestInfo.headers.upgrade;
		const rawMessage = parsedBody;
		let messages;
		if (Array.isArray(rawMessage)) messages = rawMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
		else messages = [JSONRPCMessageSchema.parse(rawMessage)];
		const hasRequests = messages.some(isJSONRPCRequest);
		if (!hasRequests) for (const message of messages) {
			if (this.messageInterceptor) {
				if (await this.messageInterceptor(message, {
					authInfo,
					requestInfo
				})) continue;
			}
			this.onmessage?.(message, {
				authInfo,
				requestInfo
			});
		}
		else if (hasRequests) {
			const { connection } = getCurrentAgent();
			if (!connection) throw new Error("Connection was not found in handlePostRequest");
			const requestIds = messages.filter(isJSONRPCRequest).map((message) => message.id);
			connection.setState({ requestIds });
			for (const message of messages) {
				if (this.messageInterceptor) {
					if (await this.messageInterceptor(message, {
						authInfo,
						requestInfo
					})) continue;
				}
				this.onmessage?.(message, {
					authInfo,
					requestInfo
				});
			}
		}
	}
	async close() {
		const { agent } = getCurrentAgent();
		if (!agent) throw new Error("Agent was not found in close");
		for (const conn of agent.getConnections()) conn.close(1e3, "Session closed");
		this.onclose?.();
	}
	async send(message, options) {
		const { agent } = getCurrentAgent();
		if (!agent) throw new Error("Agent was not found in send");
		let requestId = options?.relatedRequestId;
		if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) requestId = message.id;
		if (requestId === void 0) {
			if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) throw new Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request");
			let standaloneConnection;
			for (const conn of agent.getConnections()) if (conn.state?._standaloneSse) standaloneConnection = conn;
			if (standaloneConnection === void 0) return;
			let eventId;
			if (this._eventStore) eventId = await this._eventStore.storeEvent(standaloneConnection.id, message);
			this.writeSSEEvent(standaloneConnection, message, eventId);
			return;
		}
		const connection = Array.from(agent.getConnections()).find((conn) => conn.state?.requestIds?.includes(requestId));
		if (!connection) throw new Error(`No connection established for request ID: ${String(requestId)}`);
		let eventId;
		if (this._eventStore) eventId = await this._eventStore.storeEvent(connection.id, message);
		let shouldClose = false;
		if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
			this._requestResponseMap.set(requestId, message);
			const relatedIds = connection.state?.requestIds ?? [];
			shouldClose = relatedIds.every((id) => this._requestResponseMap.has(id));
			if (shouldClose) for (const id of relatedIds) this._requestResponseMap.delete(id);
		}
		this.writeSSEEvent(connection, message, eventId, shouldClose);
	}
};

//#endregion
//#region src/mcp/client-transports.ts
/**
* Deprecated transport wrappers
*/
let didWarnAboutSSEEdgeClientTransport = false;
/**
* @deprecated Use SSEClientTransport from @modelcontextprotocol/sdk/client/sse.js instead. This alias will be removed in the next major version.
*/
var SSEEdgeClientTransport = class extends SSEClientTransport {
	constructor(url, options) {
		super(url, options);
		if (!didWarnAboutSSEEdgeClientTransport) {
			didWarnAboutSSEEdgeClientTransport = true;
			console.warn("SSEEdgeClientTransport is deprecated. Use SSEClientTransport from @modelcontextprotocol/sdk/client/sse.js instead. SSEEdgeClientTransport will be removed in the next major version.");
		}
	}
};
let didWarnAboutStreamableHTTPEdgeClientTransport = false;
/**
* @deprecated Use StreamableHTTPClientTransport from @modelcontextprotocol/sdk/client/streamableHttp.js instead. This alias will be removed in the next major version.
*/
var StreamableHTTPEdgeClientTransport = class extends StreamableHTTPClientTransport {
	constructor(url, options) {
		super(url, options);
		if (!didWarnAboutStreamableHTTPEdgeClientTransport) {
			didWarnAboutStreamableHTTPEdgeClientTransport = true;
			console.warn("StreamableHTTPEdgeClientTransport is deprecated. Use StreamableHTTPClientTransport from @modelcontextprotocol/sdk/client/streamableHttp.js instead. StreamableHTTPEdgeClientTransport will be removed in the next major version.");
		}
	}
};

//#endregion
//#region src/mcp/worker-transport.ts
const MCP_PROTOCOL_VERSION_HEADER = "MCP-Protocol-Version";
const RESTORE_REQUEST_ID = "__restore__";
var WorkerTransport = class {
	constructor(options) {
		this.started = false;
		this.initialized = false;
		this.enableJsonResponse = false;
		this.standaloneSseStreamId = "_GET_stream";
		this.streamMapping = /* @__PURE__ */ new Map();
		this.requestToStreamMapping = /* @__PURE__ */ new Map();
		this.requestResponseMap = /* @__PURE__ */ new Map();
		this.stateRestored = false;
		this.sessionIdGenerator = options?.sessionIdGenerator;
		this.enableJsonResponse = options?.enableJsonResponse ?? false;
		this.onsessioninitialized = options?.onsessioninitialized;
		this.onsessionclosed = options?.onsessionclosed;
		this.corsOptions = options?.corsOptions;
		this.storage = options?.storage;
		this.eventStore = options?.eventStore;
		this.retryInterval = options?.retryInterval;
	}
	/**
	* Restore transport state from persistent storage.
	* This is automatically called on start.
	*/
	async restoreState() {
		if (!this.storage || this.stateRestored) return;
		const state = await Promise.resolve(this.storage.get());
		if (state) {
			this.sessionId = state.sessionId;
			this.initialized = state.initialized;
			if (state.initializeParams && this.onmessage) this.onmessage({
				jsonrpc: "2.0",
				id: RESTORE_REQUEST_ID,
				method: "initialize",
				params: state.initializeParams
			});
		}
		this.stateRestored = true;
	}
	/**
	* Persist current transport state to storage.
	*/
	async saveState() {
		if (!this.storage) return;
		const state = {
			sessionId: this.sessionId,
			initialized: this.initialized,
			initializeParams: this.initializeParams
		};
		await Promise.resolve(this.storage.set(state));
	}
	async start() {
		if (this.started) throw new Error("Transport already started");
		this.started = true;
	}
	/**
	* Validates the MCP-Protocol-Version header on incoming requests.
	*
	* This performs a simple check: if a version header is present, it must be
	* in the SUPPORTED_PROTOCOL_VERSIONS list. We do not track the negotiated
	* version or enforce version consistency across requests - the SDK handles
	* version negotiation during initialization, and we simply reject any
	* explicitly unsupported versions.
	*
	* - Header present and supported: Accept
	* - Header present and unsupported: 400 Bad Request
	* - Header missing: Accept (version validation is optional)
	*/
	validateProtocolVersion(request) {
		const protocolVersion = request.headers.get(MCP_PROTOCOL_VERSION_HEADER);
		if (protocolVersion !== null && !SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: `Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`
			},
			id: null
		}), {
			status: 400,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
	}
	getHeaders({ forPreflight } = {}) {
		const options = {
			origin: "*",
			headers: "Content-Type, Accept, Authorization, mcp-session-id, MCP-Protocol-Version",
			methods: "GET, POST, DELETE, OPTIONS",
			exposeHeaders: "mcp-session-id",
			maxAge: 86400,
			...this.corsOptions
		};
		if (forPreflight) return {
			"Access-Control-Allow-Origin": options.origin,
			"Access-Control-Allow-Headers": options.headers,
			"Access-Control-Allow-Methods": options.methods,
			"Access-Control-Max-Age": options.maxAge.toString()
		};
		return {
			"Access-Control-Allow-Origin": options.origin,
			"Access-Control-Expose-Headers": options.exposeHeaders
		};
	}
	async handleRequest(request, parsedBody) {
		await this.restoreState();
		switch (request.method) {
			case "OPTIONS": return this.handleOptionsRequest(request);
			case "GET": return this.handleGetRequest(request);
			case "POST": return this.handlePostRequest(request, parsedBody);
			case "DELETE": return this.handleDeleteRequest(request);
			default: return this.handleUnsupportedRequest();
		}
	}
	async handleGetRequest(request) {
		if (!request.headers.get("Accept")?.includes("text/event-stream")) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: "Not Acceptable: Client must accept text/event-stream"
			},
			id: null
		}), {
			status: 406,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
		const sessionError = this.validateSession(request);
		if (sessionError) return sessionError;
		const versionError = this.validateProtocolVersion(request);
		if (versionError) return versionError;
		let streamId = this.standaloneSseStreamId;
		const lastEventId = request.headers.get("Last-Event-ID");
		if (lastEventId && this.eventStore) {
			const eventStreamId = await this.eventStore.getStreamIdForEventId?.(lastEventId);
			if (eventStreamId) streamId = eventStreamId;
		}
		if (this.streamMapping.get(streamId) !== void 0) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: "Conflict: Only one SSE stream is allowed per session"
			},
			id: null
		}), {
			status: 409,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
		const { readable, writable } = new TransformStream();
		const writer = writable.getWriter();
		const encoder = new TextEncoder();
		const headers = new Headers({
			"Content-Type": "text/event-stream",
			"Cache-Control": "no-cache",
			Connection: "keep-alive",
			...this.getHeaders()
		});
		if (this.sessionId !== void 0) headers.set("mcp-session-id", this.sessionId);
		const keepAlive = setInterval(() => {
			try {
				writer.write(encoder.encode("event: ping\ndata: \n\n"));
			} catch {
				clearInterval(keepAlive);
			}
		}, 3e4);
		this.streamMapping.set(streamId, {
			writer,
			encoder,
			cleanup: () => {
				clearInterval(keepAlive);
				this.streamMapping.delete(streamId);
				writer.close().catch(() => {});
			}
		});
		if (this.retryInterval !== void 0) await writer.write(encoder.encode(`retry: ${this.retryInterval}\n\n`));
		if (lastEventId && this.eventStore) {
			const replayedStreamId = await this.eventStore.replayEventsAfter(lastEventId, { send: async (eventId, message) => {
				const data = `id: ${eventId}\nevent: message\ndata: ${JSON.stringify(message)}\n\n`;
				await writer.write(encoder.encode(data));
			} });
			if (replayedStreamId !== streamId) {
				this.streamMapping.delete(streamId);
				streamId = replayedStreamId;
				this.streamMapping.set(streamId, {
					writer,
					encoder,
					cleanup: () => {
						clearInterval(keepAlive);
						this.streamMapping.delete(streamId);
						writer.close().catch(() => {});
					}
				});
			}
		}
		return new Response(readable, { headers });
	}
	async handlePostRequest(request, parsedBody) {
		const acceptHeader = request.headers.get("Accept");
		if (!acceptHeader?.includes("application/json") || !acceptHeader?.includes("text/event-stream")) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: "Not Acceptable: Client must accept both application/json and text/event-stream"
			},
			id: null
		}), {
			status: 406,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
		if (!request.headers.get("Content-Type")?.includes("application/json")) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: "Unsupported Media Type: Content-Type must be application/json"
			},
			id: null
		}), {
			status: 415,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
		let rawMessage = parsedBody;
		if (rawMessage === void 0) try {
			rawMessage = await request.json();
		} catch {
			return new Response(JSON.stringify({
				jsonrpc: "2.0",
				error: {
					code: -32700,
					message: "Parse error: Invalid JSON"
				},
				id: null
			}), {
				status: 400,
				headers: {
					"Content-Type": "application/json",
					...this.getHeaders()
				}
			});
		}
		let messages;
		try {
			if (Array.isArray(rawMessage)) messages = rawMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
			else messages = [JSONRPCMessageSchema.parse(rawMessage)];
		} catch {
			return new Response(JSON.stringify({
				jsonrpc: "2.0",
				error: {
					code: -32700,
					message: "Parse error: Invalid JSON-RPC message"
				},
				id: null
			}), {
				status: 400,
				headers: {
					"Content-Type": "application/json",
					...this.getHeaders()
				}
			});
		}
		const requestInfo = { headers: Object.fromEntries(request.headers.entries()) };
		const isInitializationRequest = messages.some(isInitializeRequest);
		if (isInitializationRequest) {
			if (this.initialized && this.sessionId !== void 0) return new Response(JSON.stringify({
				jsonrpc: "2.0",
				error: {
					code: -32600,
					message: "Invalid Request: Server already initialized"
				},
				id: null
			}), {
				status: 400,
				headers: {
					"Content-Type": "application/json",
					...this.getHeaders()
				}
			});
			if (messages.length > 1) return new Response(JSON.stringify({
				jsonrpc: "2.0",
				error: {
					code: -32600,
					message: "Invalid Request: Only one initialization request is allowed"
				},
				id: null
			}), {
				status: 400,
				headers: {
					"Content-Type": "application/json",
					...this.getHeaders()
				}
			});
			this.sessionId = this.sessionIdGenerator?.();
			this.initialized = true;
			const initMessage = messages.find(isInitializeRequest);
			if (initMessage && isInitializeRequest(initMessage)) this.initializeParams = {
				capabilities: initMessage.params.capabilities,
				clientInfo: initMessage.params.clientInfo,
				protocolVersion: initMessage.params.protocolVersion
			};
			await this.saveState();
			if (this.sessionId && this.onsessioninitialized) this.onsessioninitialized(this.sessionId);
		}
		if (!isInitializationRequest) {
			const sessionError = this.validateSession(request);
			if (sessionError) return sessionError;
			const versionError = this.validateProtocolVersion(request);
			if (versionError) return versionError;
		}
		if (!messages.some(isJSONRPCRequest)) {
			for (const message of messages) this.onmessage?.(message, { requestInfo });
			return new Response(null, {
				status: 202,
				headers: { ...this.getHeaders() }
			});
		}
		const streamId = crypto.randomUUID();
		if (this.enableJsonResponse) return new Promise((resolve) => {
			this.streamMapping.set(streamId, {
				resolveJson: resolve,
				cleanup: () => {
					this.streamMapping.delete(streamId);
				}
			});
			for (const message of messages) if (isJSONRPCRequest(message)) this.requestToStreamMapping.set(message.id, streamId);
			for (const message of messages) this.onmessage?.(message, { requestInfo });
		});
		const { readable, writable } = new TransformStream();
		const writer = writable.getWriter();
		const encoder = new TextEncoder();
		const headers = new Headers({
			"Content-Type": "text/event-stream",
			"Cache-Control": "no-cache",
			Connection: "keep-alive",
			...this.getHeaders()
		});
		if (this.sessionId !== void 0) headers.set("mcp-session-id", this.sessionId);
		this.streamMapping.set(streamId, {
			writer,
			encoder,
			cleanup: () => {
				this.streamMapping.delete(streamId);
				writer.close().catch(() => {});
			}
		});
		for (const message of messages) if (isJSONRPCRequest(message)) this.requestToStreamMapping.set(message.id, streamId);
		for (const message of messages) this.onmessage?.(message, { requestInfo });
		return new Response(readable, { headers });
	}
	async handleDeleteRequest(request) {
		const sessionError = this.validateSession(request);
		if (sessionError) return sessionError;
		const versionError = this.validateProtocolVersion(request);
		if (versionError) return versionError;
		const closedSessionId = this.sessionId;
		await this.close();
		if (closedSessionId && this.onsessionclosed) this.onsessionclosed(closedSessionId);
		return new Response(null, {
			status: 200,
			headers: { ...this.getHeaders() }
		});
	}
	handleOptionsRequest(_request) {
		return new Response(null, {
			status: 200,
			headers: { ...this.getHeaders({ forPreflight: true }) }
		});
	}
	handleUnsupportedRequest() {
		return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: "Method not allowed."
			},
			id: null
		}), {
			status: 405,
			headers: {
				Allow: "GET, POST, DELETE, OPTIONS",
				"Content-Type": "application/json"
			}
		});
	}
	validateSession(request) {
		if (this.sessionIdGenerator === void 0) return;
		if (!this.initialized) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: "Bad Request: Server not initialized"
			},
			id: null
		}), {
			status: 400,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
		const sessionId = request.headers.get("mcp-session-id");
		if (!sessionId) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32e3,
				message: "Bad Request: Mcp-Session-Id header is required"
			},
			id: null
		}), {
			status: 400,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
		if (sessionId !== this.sessionId) return new Response(JSON.stringify({
			jsonrpc: "2.0",
			error: {
				code: -32001,
				message: "Session not found"
			},
			id: null
		}), {
			status: 404,
			headers: {
				"Content-Type": "application/json",
				...this.getHeaders()
			}
		});
	}
	async close() {
		for (const { cleanup } of this.streamMapping.values()) cleanup();
		this.streamMapping.clear();
		this.requestResponseMap.clear();
		this.onclose?.();
	}
	/**
	* Close an SSE stream for a specific request, triggering client reconnection.
	* Use this to implement polling behavior during long-running operations -
	* client will reconnect after the retry interval specified in the priming event.
	*/
	closeSSEStream(requestId) {
		const streamId = this.requestToStreamMapping.get(requestId);
		if (!streamId) return;
		const stream = this.streamMapping.get(streamId);
		if (stream) stream.cleanup();
		for (const [reqId, sid] of this.requestToStreamMapping.entries()) if (sid === streamId) {
			this.requestToStreamMapping.delete(reqId);
			this.requestResponseMap.delete(reqId);
		}
	}
	async send(message, options) {
		let requestId = options?.relatedRequestId;
		if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) requestId = message.id;
		if (requestId === RESTORE_REQUEST_ID) return;
		if (requestId === void 0) {
			if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) throw new Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request");
			const standaloneSse = this.streamMapping.get(this.standaloneSseStreamId);
			if (standaloneSse === void 0) return;
			if (standaloneSse.writer && standaloneSse.encoder) {
				let eventId;
				if (this.eventStore) eventId = await this.eventStore.storeEvent(this.standaloneSseStreamId, message);
				const data = `${eventId ? `id: ${eventId}\n` : ""}event: message\ndata: ${JSON.stringify(message)}\n\n`;
				await standaloneSse.writer.write(standaloneSse.encoder.encode(data));
			}
			return;
		}
		const streamId = this.requestToStreamMapping.get(requestId);
		if (!streamId) throw new Error(`No connection established for request ID: ${String(requestId)}`);
		const response = this.streamMapping.get(streamId);
		if (!response) throw new Error(`No connection established for request ID: ${String(requestId)}`);
		if (!this.enableJsonResponse) {
			if (response.writer && response.encoder) {
				let eventId;
				if (this.eventStore) eventId = await this.eventStore.storeEvent(streamId, message);
				const data = `${eventId ? `id: ${eventId}\n` : ""}event: message\ndata: ${JSON.stringify(message)}\n\n`;
				await response.writer.write(response.encoder.encode(data));
			}
		}
		if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
			this.requestResponseMap.set(requestId, message);
			const relatedIds = Array.from(this.requestToStreamMapping.entries()).filter(([, sid]) => sid === streamId).map(([id]) => id);
			if (relatedIds.every((id) => this.requestResponseMap.has(id))) {
				if (this.enableJsonResponse && response.resolveJson) {
					const responses = relatedIds.map((id) => this.requestResponseMap.get(id));
					const headers = new Headers({
						"Content-Type": "application/json",
						...this.getHeaders()
					});
					if (this.sessionId !== void 0) headers.set("mcp-session-id", this.sessionId);
					const body = responses.length === 1 ? responses[0] : responses;
					response.resolveJson(new Response(JSON.stringify(body), { headers }));
				} else response.cleanup();
				for (const id of relatedIds) {
					this.requestResponseMap.delete(id);
					this.requestToStreamMapping.delete(id);
				}
			}
		}
	}
};

//#endregion
//#region src/mcp/auth-context.ts
const authContextStorage = new AsyncLocalStorage();
function getMcpAuthContext() {
	return authContextStorage.getStore();
}
function runWithAuthContext(context, fn) {
	return authContextStorage.run(context, fn);
}

//#endregion
//#region src/mcp/handler.ts
function createMcpHandler(server, options = {}) {
	const route = options.route ?? "/mcp";
	return async (request, _env, ctx) => {
		const url = new URL(request.url);
		if (route && url.pathname !== route) return new Response("Not Found", { status: 404 });
		const transport = options.transport ?? new WorkerTransport({
			sessionIdGenerator: options.sessionIdGenerator,
			enableJsonResponse: options.enableJsonResponse,
			onsessioninitialized: options.onsessioninitialized,
			corsOptions: options.corsOptions,
			storage: options.storage
		});
		const buildAuthContext = () => {
			if (options.authContext) return options.authContext;
			if (ctx.props && Object.keys(ctx.props).length > 0) return { props: ctx.props };
		};
		const handleRequest = async () => {
			return await transport.handleRequest(request);
		};
		const authContext = buildAuthContext();
		if (!transport.started) await server.connect(transport);
		try {
			if (authContext) return await runWithAuthContext(authContext, handleRequest);
			else return await handleRequest();
		} catch (error) {
			console.error("MCP handler error:", error);
			return new Response(JSON.stringify({
				jsonrpc: "2.0",
				error: {
					code: -32603,
					message: error instanceof Error ? error.message : "Internal server error"
				},
				id: null
			}), {
				status: 500,
				headers: { "Content-Type": "application/json" }
			});
		}
	};
}
let didWarnAboutExperimentalCreateMcpHandler = false;
/**
* @deprecated This has been renamed to createMcpHandler, and experimental_createMcpHandler will be removed in the next major version
*/
function experimental_createMcpHandler(server, options = {}) {
	if (!didWarnAboutExperimentalCreateMcpHandler) {
		didWarnAboutExperimentalCreateMcpHandler = true;
		console.warn("experimental_createMcpHandler is deprecated, use createMcpHandler instead. experimental_createMcpHandler will be removed in the next major version.");
	}
	return createMcpHandler(server, options);
}

//#endregion
//#region src/mcp/index.ts
var McpAgent = class McpAgent extends Agent {
	async setInitializeRequest(initializeRequest) {
		await this.ctx.storage.put("initializeRequest", initializeRequest);
	}
	async getInitializeRequest() {
		return this.ctx.storage.get("initializeRequest");
	}
	/** Read the transport type for this agent.
	* This relies on the naming scheme being `sse:${sessionId}`
	* or `streamable-http:${sessionId}`.
	*/
	getTransportType() {
		const [t, ..._] = this.name.split(":");
		switch (t) {
			case "sse": return "sse";
			case "streamable-http": return "streamable-http";
			default: throw new Error("Invalid transport type. McpAgent must be addressed with a valid protocol.");
		}
	}
	/** Read the sessionId for this agent.
	* This relies on the naming scheme being `sse:${sessionId}`
	* or `streamable-http:${sessionId}`.
	*/
	getSessionId() {
		const [_, sessionId] = this.name.split(":");
		if (!sessionId) throw new Error("Invalid session id. McpAgent must be addressed with a valid session id.");
		return sessionId;
	}
	/** Get the unique WebSocket. SSE transport only. */
	getWebSocket() {
		const websockets = Array.from(this.getConnections());
		if (websockets.length === 0) return null;
		return websockets[0];
	}
	/** Returns a new transport matching the type of the Agent. */
	initTransport() {
		switch (this.getTransportType()) {
			case "sse": return new McpSSETransport();
			case "streamable-http": {
				const transport = new StreamableHTTPServerTransport({});
				transport.messageInterceptor = async (message) => {
					return this._handleElicitationResponse(message);
				};
				return transport;
			}
		}
	}
	/** Update and store the props */
	async updateProps(props) {
		await this.ctx.storage.put("props", props ?? {});
		this.props = props;
	}
	async reinitializeServer() {
		const initializeRequest = await this.getInitializeRequest();
		if (initializeRequest) this._transport?.onmessage?.(initializeRequest);
	}
	/** Sets up the MCP transport and server every time the Agent is started.*/
	async onStart(props) {
		if (props) await this.updateProps(props);
		this.props = await this.ctx.storage.get("props");
		await this.init();
		const server = await this.server;
		this._transport = this.initTransport();
		await server.connect(this._transport);
		await this.reinitializeServer();
	}
	/** Validates new WebSocket connections. */
	async onConnect(conn, { request: req }) {
		switch (this.getTransportType()) {
			case "sse":
				if (Array.from(this.getConnections()).length > 1) {
					conn.close(1008, "Websocket already connected");
					return;
				}
				break;
			case "streamable-http": if (this._transport instanceof StreamableHTTPServerTransport) switch (req.headers.get(MCP_HTTP_METHOD_HEADER)) {
				case "POST": {
					const payloadHeader = req.headers.get(MCP_MESSAGE_HEADER);
					let rawPayload;
					if (!payloadHeader) rawPayload = "{}";
					else try {
						rawPayload = Buffer.from(payloadHeader, "base64").toString("utf-8");
					} catch (_error) {
						throw new Error("Internal Server Error: Failed to decode MCP message header");
					}
					const parsedBody = JSON.parse(rawPayload);
					this._transport?.handlePostRequest(req, parsedBody);
					break;
				}
				case "GET":
					this._transport?.handleGetRequest(req);
					break;
			}
		}
	}
	/** Handles MCP Messages for the legacy SSE transport. */
	async onSSEMcpMessage(_sessionId, messageBody, extraInfo) {
		if (this.getTransportType() !== "sse") return /* @__PURE__ */ new Error("Internal Server Error: Expected SSE transport");
		try {
			let parsedMessage;
			try {
				parsedMessage = JSONRPCMessageSchema.parse(messageBody);
			} catch (error) {
				this._transport?.onerror?.(error);
				throw error;
			}
			if (await this._handleElicitationResponse(parsedMessage)) return null;
			this._transport?.onmessage?.(parsedMessage, extraInfo);
			return null;
		} catch (error) {
			console.error("Error forwarding message to SSE:", error);
			this._transport?.onerror?.(error);
			return error;
		}
	}
	/** Elicit user input with a message and schema */
	async elicitInput(params) {
		const requestId = `elicit_${Math.random().toString(36).substring(2, 11)}`;
		await this.ctx.storage.put(`elicitation:${requestId}`, {
			message: params.message,
			requestedSchema: params.requestedSchema,
			timestamp: Date.now()
		});
		const elicitRequest = {
			jsonrpc: "2.0",
			id: requestId,
			method: "elicitation/create",
			params: {
				message: params.message,
				requestedSchema: params.requestedSchema
			}
		};
		if (this._transport) await this._transport.send(elicitRequest);
		else {
			const connections = this.getConnections();
			if (!connections || Array.from(connections).length === 0) {
				await this.ctx.storage.delete(`elicitation:${requestId}`);
				throw new Error("No active connections available for elicitation");
			}
			const connectionList = Array.from(connections);
			for (const connection of connectionList) try {
				connection.send(JSON.stringify(elicitRequest));
			} catch (error) {
				console.error("Failed to send elicitation request:", error);
			}
		}
		return this._waitForElicitationResponse(requestId);
	}
	/** Wait for elicitation response through storage polling */
	async _waitForElicitationResponse(requestId) {
		const startTime = Date.now();
		const timeout = 6e4;
		try {
			while (Date.now() - startTime < timeout) {
				const response = await this.ctx.storage.get(`elicitation:response:${requestId}`);
				if (response) {
					await this.ctx.storage.delete(`elicitation:${requestId}`);
					await this.ctx.storage.delete(`elicitation:response:${requestId}`);
					return response;
				}
				await new Promise((resolve) => setTimeout(resolve, 100));
			}
			throw new Error("Elicitation request timed out");
		} finally {
			await this.ctx.storage.delete(`elicitation:${requestId}`);
			await this.ctx.storage.delete(`elicitation:response:${requestId}`);
		}
	}
	/** Handle elicitation responses */
	async _handleElicitationResponse(message) {
		if (isJSONRPCResultResponse(message) && message.result) {
			const requestId = message.id?.toString();
			if (!requestId || !requestId.startsWith("elicit_")) return false;
			if (!await this.ctx.storage.get(`elicitation:${requestId}`)) return false;
			await this.ctx.storage.put(`elicitation:response:${requestId}`, message.result);
			return true;
		}
		if (isJSONRPCErrorResponse(message)) {
			const requestId = message.id?.toString();
			if (!requestId || !requestId.startsWith("elicit_")) return false;
			if (!await this.ctx.storage.get(`elicitation:${requestId}`)) return false;
			const errorResult = {
				action: "cancel",
				content: { error: message.error.message || "Elicitation request failed" }
			};
			await this.ctx.storage.put(`elicitation:response:${requestId}`, errorResult);
			return true;
		}
		return false;
	}
	/** Return a handler for the given path for this MCP.
	* Defaults to Streamable HTTP transport.
	*/
	static serve(path, { binding = "MCP_OBJECT", corsOptions, transport = "streamable-http", jurisdiction } = {}) {
		return { async fetch(request, env, ctx) {
			const corsResponse = handleCORS(request, corsOptions);
			if (corsResponse) return corsResponse;
			const bindingValue = env[binding];
			if (bindingValue == null || typeof bindingValue !== "object") throw new Error(`Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`);
			if (!isDurableObjectNamespace(bindingValue)) throw new Error(`Invalid McpAgent binding for ${binding}. Make sure it's a Durable Object binding.`);
			const namespace = bindingValue;
			switch (transport) {
				case "streamable-http": return createStreamingHttpHandler(path, namespace, {
					corsOptions,
					jurisdiction
				})(request, ctx);
				case "sse": return createLegacySseHandler(path, namespace, {
					corsOptions,
					jurisdiction
				})(request, ctx);
				default: return new Response("Invalid MCP transport mode. Only `streamable-http` or `sse` are allowed.", { status: 500 });
			}
		} };
	}
	/**
	* Legacy api
	**/
	static mount(path, opts = {}) {
		return McpAgent.serveSSE(path, opts);
	}
	static serveSSE(path, opts = {}) {
		return McpAgent.serve(path, {
			...opts,
			transport: "sse"
		});
	}
};

//#endregion
export { ElicitRequestSchema, McpAgent, SSEEdgeClientTransport, StreamableHTTPEdgeClientTransport, WorkerTransport, createMcpHandler, experimental_createMcpHandler, getMcpAuthContext };
//# sourceMappingURL=index.js.map