Skip to content

Commit da4ba02

Browse files
committed
Fix: Ensure McpError is returned to client in all failure scenarios
1 parent 72dfb3b commit da4ba02

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

src/mcp-proxy.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
ListResourceTemplatesResultSchema,
1717
ResourceTemplate,
1818
CompatibilityCallToolResultSchema,
19-
GetPromptResultSchema
19+
GetPromptResultSchema,
20+
McpError
2021
} from "@modelcontextprotocol/sdk/types.js";
2122
import { createClients, ConnectedClient, reconnectSingleClient } from './client.js';
2223
import { logger } from './logger.js';
@@ -439,8 +440,9 @@ export const createServer = async () => {
439440

440441
// If no entry was found after checking all enabled tools and their potential overrides
441442
if (!mapEntry || !originalQualifiedName) {
442-
logger.error(`Attempted to call tool with exposed name "${requestedExposedName}", but no corresponding enabled tool or override configuration found.`);
443-
throw new Error(`Unknown or disabled tool: ${requestedExposedName}`);
443+
const errorMessage = `Attempted to call tool with exposed name "${requestedExposedName}", but no corresponding enabled tool or override configuration found.`;
444+
logger.error(errorMessage);
445+
throw new McpError(-32601, errorMessage); // Method not found error code
444446
}
445447

446448
// Now we have the correct mapEntry and the originalQualifiedName
@@ -488,11 +490,11 @@ export const createServer = async () => {
488490
toolInfo = newMapEntry.toolInfo;
489491
} else {
490492
logger.error(`SSE Reconnection to server '${clientForTool.name}' failed.`);
491-
// If reconnect fails, break retry loop
492-
break;
493+
// If reconnect fails, throw an error to exit the retry loop and propagate
494+
throw new McpError(-32000, `SSE Reconnection to server '${clientForTool.name}' failed for tool '${requestedExposedName}'.`);
493495
}
494-
}
495-
}
496+
}
497+
}
496498

497499
try {
498500
logger.log(`Forwarding tool call for exposed name '${requestedExposedName}' (original qualified name: '${originalQualifiedName}'). Forwarding to server '${clientForTool.name}' as tool '${originalToolNameForBackend}' (Attempt ${attempt + 1})`);
@@ -521,13 +523,23 @@ export const createServer = async () => {
521523
if (!shouldRetry && attempt === 0) {
522524
// If it's the first attempt and not a retryable error type, re-throw immediately
523525
logger.error(`Tool call for '${requestedExposedName}' failed with non-retryable error on first attempt: ${error.message}`, error);
524-
throw error;
526+
// If the error is already an McpError, re-throw it directly. Otherwise, wrap it.
527+
if (error instanceof McpError) {
528+
throw error;
529+
} else {
530+
throw new McpError(error?.code || -32000, error.message || 'An unknown error occurred', error?.data);
531+
}
525532
}
526533

527534
if (!shouldRetry && attempt > 0) {
528535
// If it's a subsequent attempt and the error is no longer retryable (e.g., backend returned a specific error after reconnect)
529536
logger.error(`Tool call for '${requestedExposedName}' failed with non-retryable error after retries: ${error.message}`, error);
530-
throw error;
537+
// If the error is already an McpError, re-throw it directly. Otherwise, wrap it.
538+
if (error instanceof McpError) {
539+
throw error;
540+
} else {
541+
throw new McpError(error?.code || -32000, error.message || 'An unknown error occurred', error?.data);
542+
}
531543
}
532544

533545
// If it's a retryable error and we are within maxRetries, the loop continues.
@@ -538,7 +550,8 @@ export const createServer = async () => {
538550
// If the loop finishes without returning, it means all retries failed.
539551
const errorMessage = `Error calling tool '${requestedExposedName}' after ${maxRetries} retries (on backend server '${clientForTool.name}', original tool name '${originalToolNameForBackend}'): ${lastError?.message || 'An unknown error occurred'}`;
540552
logger.error(errorMessage, lastError);
541-
throw new Error(errorMessage);
553+
// Ensure a structured McpError is returned to the client
554+
throw new McpError(lastError?.code || -32000, errorMessage, lastError?.data);
542555
});
543556

544557
// ... rest of the file ...

0 commit comments

Comments
 (0)