mcp‑error‑formatter is a lightweight npm package designed to standardize error formatting for Model Context Protocol (MCP) tool calls, inspired by Cursor's clean and LLM‑friendly approach. If you've built MCP servers for LLM integrations and struggled with cryptic error messages that confuse models or hinder debugging, this utility simplifies the process by transforming JavaScript Errors into structured CallToolResult objects. It auto‑detects error types (timeouts, user aborts, network faults), tags each error with a request‑ID for easy tracing, and sets flags such as isRetryable so LLMs (and agents) can behave intelligently—reducing vague "something went wrong" outputs and speeding up development. With zero runtime dependencies beyond uuid and seamless compatibility with the official MCP SDK, FastMCP, or bare JSON‑RPC servers, it's a drop‑in upgrade that makes your MCP tools more robust and user‑friendly.
Installation
npm install @bjoaquinc/mcp-error-formatter
Usage
Basic Usage
import { formatMCPError } from "@bjoaquinc/mcp-error-formatter"; export async function myTool(_args) { try { const result = await someOperation(); return { content: [{ type: "text", text: result }] }; } catch (err) { // Minimum call – auto‑detects type, adds requestId, structuredContent return formatMCPError(err, { title: "Operation failed" }); } }
Advanced Usage (structuredContent override)
import { formatMCPError, ErrorType } from "@bjoaquinc/mcp-error-formatter"; export async function githubTool(args) { try { const res = await github.api.repos.get(args.repo); return { content: [{ type: "text", text: JSON.stringify(res) }] }; } catch (err) { return formatMCPError(err, { title: "GitHub API request failed", detail: `Failed to fetch repository: ${args.repo}`, errorType: ErrorType.NETWORK_ERROR, isRetryable: true, additionalInfo: { repo: args.repo, statusCode: err.status, rateLimitRemaining: err.headers?.["x-ratelimit-remaining"] }, // NEW — full structured payload override (optional) structured: { service: "github", repo: args.repo, statusCode: err.status, retryable: true } }); } }
Response / Return Values
formatMCPError() always returns a valid MCP CallToolResult with the following structure:
structuredContent– machine‑readable JSON for modern clients.content– single text item duplicating the JSON plus full stack trace for Cursor & other UIs.
API Overview
| Function | Description |
|---|---|
formatMCPError(error, options?) |
Convert any Error into a structured CallToolResult. |
createUserAbortedError(requestId?) |
Convenience: pre‑built user‑cancelled error. |
createTimeoutError(timeoutMs, requestId?) |
Convenience: pre‑built timeout error. |
createNetworkError(error, requestId?) |
Convenience: wraps fetch/axios errors. |
FormatOptions
interface FormatOptions { title?: string; detail?: string; requestId?: string; // Defaults to uuid.v4() errorType?: ErrorType; // Auto‑detected if omitted isRetryable?: boolean; isExpected?: boolean; additionalInfo?: Record<string, any>; structured?: Record<string, unknown>; // NEW: full override of structuredContent }
ErrorType
enum ErrorType { USER_ABORTED = "ERROR_USER_ABORTED_REQUEST", TIMEOUT = "ERROR_TIMEOUT", NETWORK_ERROR = "ERROR_NETWORK_ERROR", INTERNAL_ERROR = "ERROR_INTERNAL_ERROR", INVALID_INPUT = "ERROR_INVALID_INPUT" }
Output Examples
Default (auto‑generated structuredContent)
Request ID: 4de16c8d‑...‑6a9c
{"errorType":"ERROR_NETWORK_ERROR","title":"GitHub API request failed","detail":"Failed to fetch repository","retryable":true,"expected":false,"info":{"statusCode":503}}
Error: Request failed with status code 503
at githubTool (/path/to/file.js:12:18)
...
Custom structuredContent override
Request ID: 2f3a08e1‑...‑d212
{"service":"github","repo":"octocat/Hello-World","statusCode":503,"retryable":true}
Error: Request failed with status code 503
at githubTool (/path/to/file.js:12:18)
...
That's it! Drop formatMCPError into any MCP tool, get rich JSON for agents and readable stacks for humans—no extra setup required.