CC-301j · Module 2

Error Handling in MCP Tools

3 min read

When an MCP tool fails, Claude needs to understand why. A tool that throws an unhandled exception returns a generic error message that Claude cannot act on. A tool that catches the error and returns a structured error message gives Claude the context to recover — retry with different parameters, try an alternative approach, or explain the failure to the user.

The error handling pattern: wrap your handler in a try-catch. In the catch block, classify the error (authentication failure, invalid input, resource not found, rate limit, server error) and return a structured message. "Authentication failed — the API token may have expired. Ask the user to re-authenticate." gives Claude a recovery action. "Error: 500 Internal Server Error" gives Claude nothing to work with.

server.tool('query_db', 'Query the database', schema, async (params) => {
  try {
    const result = await db.query(params.sql);
    return { content: [{ type: 'text', text: JSON.stringify(result) }] };
  } catch (error) {
    // Classify and return actionable error
    if (error.code === 'ECONNREFUSED') {
      return {
        content: [{ type: 'text',
          text: 'Database connection refused. The database server may be down. ' +
                'Ask the user to verify the database is running.' }],
        isError: true,
      };
    }
    return {
      content: [{ type: 'text', text: `Query failed: ${error.message}` }],
      isError: true,
    };
  }
});