Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tricky-weeks-reply.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"agents": patch
---

Fix/mcp agent error handling
28 changes: 28 additions & 0 deletions examples/mcp/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ export class MyMCP extends McpAgent<Env, State, {}> {
onStateUpdate(state: State) {
console.log({ stateUpdate: state });
}

onError(error: Error): { status: number; message: string } {
console.error("MyMCP initialization error:", error);

// Provide more specific error messages based on error type
if (error.message.includes("counter")) {
return {
status: 500,
message:
"Failed to initialize counter resource. Please check the counter configuration."
};
}

if (error.message.includes("tool")) {
return {
status: 500,
message:
"Failed to register MCP tools. Please verify tool configurations."
};
}

// Fall back to default error handling
return {
status: 500,
message:
error.message || "An unexpected error occurred during initialization"
};
}
}

export default MyMCP.serve("/mcp", {
Expand Down
53 changes: 49 additions & 4 deletions packages/agents/src/mcp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,21 @@ export abstract class McpAgent<

abstract init(): Promise<void>;

/**
* Handle errors that occur during initialization or operation.
* Override this method to provide custom error handling.
* @param error - The error that occurred
* @returns An error response object with status code and message
*/
onError(error: Error): { status: number; message: string } {
console.error("McpAgent error:", error);
return {
status: 500,
message:
error.message || "An unexpected error occurred during initialization"
};
}

async _init(props: Props) {
await this.ctx.storage.put("props", props ?? {});
if (!this.ctx.storage.get("transportType")) {
Expand All @@ -309,7 +324,12 @@ export abstract class McpAgent<
this.props = props;
if (!this.initRun) {
this.initRun = true;
await this.init();
try {
await this.init();
} catch (error) {
const errorResponse = this.onError(error as Error);
throw new Error(`Initialization failed: ${errorResponse.message}`);
}
}
}

Expand Down Expand Up @@ -607,7 +627,17 @@ export abstract class McpAgent<
const doStub = namespace.get(id);

// Initialize the object
await doStub._init(ctx.props);
try {
await doStub._init(ctx.props);
} catch (error) {
console.error("Failed to initialize McpAgent:", error);
await writer.close();
const errorMessage =
error instanceof Error ? error.message : String(error);
return new Response(`Initialization failed: ${errorMessage}`, {
status: 500
});
}

// Connect to the Durable Object via WebSocket
const upgradeUrl = new URL(request.url);
Expand Down Expand Up @@ -968,8 +998,23 @@ export abstract class McpAgent<
const isInitialized = await doStub.isInitialized();

if (isInitializationRequest) {
await doStub._init(ctx.props);
await doStub.setInitialized();
try {
await doStub._init(ctx.props);
await doStub.setInitialized();
} catch (error) {
console.error("Failed to initialize McpAgent:", error);
const errorMessage =
error instanceof Error ? error.message : String(error);
const body = JSON.stringify({
error: {
code: -32001,
message: `Initialization failed: ${errorMessage}`
},
id: null,
jsonrpc: "2.0"
});
return new Response(body, { status: 500 });
}
} else if (!isInitialized) {
// if we have gotten here, then a session id that was never initialized
// was provided
Expand Down