Skip to main content
RapidDev - Software Development Agency
mcp-tutorial

How to fix MCP server timeout errors

MCP server timeout errors occur when a tool call takes longer than the default 60-second limit. You will see 'Request timeout (-32001)' in the logs. Fix this by increasing the timeout via the MCP_SERVER_REQUEST_TIMEOUT environment variable, sending progress notifications for long-running operations, implementing pagination for large data returns, and optimizing slow API calls within your tools.

What you'll learn

  • What causes MCP timeout errors and the default timeout values
  • How to increase the timeout via environment variables
  • How to send progress notifications for long-running tools
  • How to implement pagination to avoid timeout on large results
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate8 min read15-20 minMCP SDK 1.0+, all MCP hostsMarch 2026RapidDev Engineering Team
TL;DR

MCP server timeout errors occur when a tool call takes longer than the default 60-second limit. You will see 'Request timeout (-32001)' in the logs. Fix this by increasing the timeout via the MCP_SERVER_REQUEST_TIMEOUT environment variable, sending progress notifications for long-running operations, implementing pagination for large data returns, and optimizing slow API calls within your tools.

Fixing MCP Server Timeout Errors

When an MCP tool call takes too long, the host cancels the request and reports a timeout error. The default timeout is typically 60 seconds, which is sufficient for most operations but too short for tools that call slow external APIs, process large files, or perform complex computations. This tutorial covers multiple strategies for handling long-running operations without hitting timeout limits.

Prerequisites

  • An MCP server with tools that are timing out
  • Understanding of which tool calls are slow
  • Access to your MCP host configuration

Step-by-step guide

1

Identify the timeout error in your logs

The timeout error appears as a JSON-RPC error with code -32001 and a message like 'Request timeout'. Check your MCP host logs and server stderr output for this error. In Claude Desktop, check ~/Library/Logs/Claude/mcp*.log. In Cursor, check the Output panel under MCP. The error typically includes the tool name and the timeout duration, helping you identify which specific tool is too slow.

typescript
1# Error messages you might see:
2
3# In MCP host logs:
4# "Request timeout (-32001)"
5# "Tool execution timed out after 60000ms"
6# "MCP server request timed out"
7
8# In JSON-RPC format:
9# {
10# "jsonrpc": "2.0",
11# "error": {
12# "code": -32001,
13# "message": "Request timed out"
14# },
15# "id": 1
16# }
17
18# Check logs:
19tail -n 50 ~/Library/Logs/Claude/mcp*.log | grep -i timeout

Expected result: You have identified the timeout error and know which tool call is triggering it.

2

Increase the timeout via environment variable

The quickest fix is to increase the timeout duration. Set the MCP_SERVER_REQUEST_TIMEOUT environment variable in your host configuration's env block. The value is in milliseconds. Setting it to 120000 gives tools two minutes, and 300000 gives five minutes. This is a valid approach for tools that are inherently slow (like web scraping or complex API calls) and cannot be optimized further.

typescript
1// claude_desktop_config.json — increase timeout to 2 minutes
2{
3 "mcpServers": {
4 "slow-api-server": {
5 "command": "node",
6 "args": ["./dist/index.js"],
7 "env": {
8 "MCP_SERVER_REQUEST_TIMEOUT": "120000",
9 "API_KEY": "your-key"
10 }
11 }
12 }
13}

Expected result: Tool calls have more time to complete before the host triggers a timeout.

3

Send progress notifications for long-running tools

The MCP protocol supports progress notifications that keep the host informed during long operations. By sending periodic progress updates, you signal that the tool is still working and prevent some hosts from timing out. This also provides a better user experience, showing the user what the tool is doing. Send progress notifications from within your tool handler using the server's notification mechanism.

typescript
1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2import { z } from "zod";
3
4const server = new McpServer({
5 name: "progress-demo",
6 version: "1.0.0",
7});
8
9server.tool(
10 "process-large-dataset",
11 "Process a large dataset with progress updates",
12 { datasetId: z.string() },
13 async ({ datasetId }, { sendNotification }) => {
14 const totalItems = 1000;
15
16 for (let i = 0; i < totalItems; i += 100) {
17 // Process batch...
18 await processBatch(datasetId, i, i + 100);
19
20 // Send progress notification
21 await sendNotification({
22 method: "notifications/progress",
23 params: {
24 progressToken: datasetId,
25 progress: i + 100,
26 total: totalItems,
27 },
28 });
29 }
30
31 return {
32 content: [{ type: "text", text: `Processed ${totalItems} items` }],
33 };
34 }
35);

Expected result: The host receives progress updates and shows them to the user while the tool continues processing.

4

Implement pagination for large results

If your tool returns large amounts of data, it may timeout during response serialization rather than during processing. Break large results into pages using a cursor parameter. The first call returns the first page plus a cursor for the next page. Subsequent calls use the cursor to fetch more data. This keeps individual tool calls fast while still allowing access to all the data.

typescript
1server.tool(
2 "search-records",
3 "Search records with pagination",
4 {
5 query: z.string(),
6 cursor: z.string().optional(),
7 pageSize: z.number().optional().default(50),
8 },
9 async ({ query, cursor, pageSize }) => {
10 const offset = cursor ? parseInt(cursor, 10) : 0;
11 const results = await searchDatabase(query, offset, pageSize);
12 const hasMore = results.length === pageSize;
13 const nextCursor = hasMore ? String(offset + pageSize) : null;
14
15 return {
16 content: [
17 {
18 type: "text",
19 text: JSON.stringify({
20 results,
21 nextCursor,
22 hasMore,
23 }, null, 2),
24 },
25 ],
26 };
27 }
28);

Expected result: Each tool call returns a manageable page of results within the timeout window.

5

Optimize slow external API calls

Often the timeout is caused by a slow third-party API call within your tool. Add request timeouts with AbortController, implement caching for repeated queries, and consider parallelizing independent API calls. For tools that must call multiple APIs, set individual timeouts shorter than the MCP timeout to leave room for response serialization. If your MCP tools interact with complex API architectures and you need help optimizing performance, the RapidDev engineering team can assist with architecture design.

typescript
1// Add timeout to fetch calls within tools
2async function fetchWithTimeout(
3 url: string,
4 timeoutMs: number = 30000
5): Promise<Response> {
6 const controller = new AbortController();
7 const timeout = setTimeout(() => controller.abort(), timeoutMs);
8
9 try {
10 const response = await fetch(url, { signal: controller.signal });
11 return response;
12 } finally {
13 clearTimeout(timeout);
14 }
15}
16
17// Use in your tool handler
18server.tool("api-call", "Call external API", { id: z.string() },
19 async ({ id }) => {
20 try {
21 const response = await fetchWithTimeout(
22 `https://api.example.com/items/${id}`,
23 30000 // 30 second timeout for API call
24 );
25 const data = await response.json();
26 return { content: [{ type: "text", text: JSON.stringify(data) }] };
27 } catch (error) {
28 if (error.name === "AbortError") {
29 return {
30 content: [{ type: "text", text: "API call timed out after 30s" }],
31 isError: true,
32 };
33 }
34 throw error;
35 }
36 }
37);

Expected result: External API calls fail gracefully within the timeout rather than causing the entire MCP request to timeout.

Complete working example

src/timeout-resilient-server.ts
1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3import { z } from "zod";
4
5const server = new McpServer({
6 name: "timeout-resilient-server",
7 version: "1.0.0",
8});
9
10// Helper: fetch with timeout
11async function fetchWithTimeout(
12 url: string,
13 timeoutMs: number = 30000
14): Promise<Response> {
15 const controller = new AbortController();
16 const timeout = setTimeout(() => controller.abort(), timeoutMs);
17 try {
18 return await fetch(url, { signal: controller.signal });
19 } finally {
20 clearTimeout(timeout);
21 }
22}
23
24// Tool with pagination
25server.tool(
26 "search",
27 "Search with pagination",
28 {
29 query: z.string(),
30 cursor: z.string().optional(),
31 limit: z.number().optional().default(25),
32 },
33 async ({ query, cursor, limit }) => {
34 const offset = cursor ? parseInt(cursor, 10) : 0;
35 const url = `https://api.example.com/search?q=${query}&offset=${offset}&limit=${limit}`;
36 const response = await fetchWithTimeout(url, 30000);
37 const data = await response.json();
38
39 return {
40 content: [
41 {
42 type: "text",
43 text: JSON.stringify({
44 results: data.items,
45 nextCursor: data.hasMore ? String(offset + limit) : null,
46 }, null, 2),
47 },
48 ],
49 };
50 }
51);
52
53const transport = new StdioServerTransport();
54await server.connect(transport);

Common mistakes when fixing MCP server timeout errors

Why it's a problem: Setting the MCP timeout higher than the host's maximum allowed timeout

How to avoid: Check your host's documentation for maximum timeout values. Some hosts cap the timeout regardless of environment variable settings.

Why it's a problem: Not adding timeouts to fetch calls inside tool handlers

How to avoid: Always add a timeout to external HTTP requests using AbortController. A hanging fetch call will consume the entire MCP timeout.

Why it's a problem: Returning extremely large JSON responses that take time to serialize

How to avoid: Implement pagination to return smaller chunks. A 10MB JSON response may timeout during serialization even if the data is ready.

Why it's a problem: Running synchronous CPU-heavy operations that block the event loop

How to avoid: Use worker threads for CPU-intensive tasks or break them into async chunks with periodic await to keep the event loop responsive.

Best practices

  • Set explicit timeouts on all external API calls shorter than the MCP timeout
  • Implement pagination for tools that return more than 50 results
  • Send progress notifications for operations expected to take more than 10 seconds
  • Use the MCP_SERVER_REQUEST_TIMEOUT env var as a safety net, not the primary solution
  • Cache repeated API responses to speed up subsequent calls
  • Log timing information for tool calls to identify which tools need optimization
  • Return partial results with a continuation cursor rather than failing on timeout

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

My MCP tool is timing out with 'Request timeout (-32001)'. The tool calls [describe API/operation] which takes about [X] seconds. Help me: 1) increase the timeout, 2) add progress notifications, and 3) implement pagination. Show me the TypeScript code.

MCP Prompt

My MCP server tool times out when processing large datasets. Add pagination support with a cursor parameter and progress notifications. The tool currently fetches all results in one call — refactor it to return pages of 50 items with a nextCursor field.

Frequently asked questions

What is the default MCP timeout?

Most MCP hosts default to 60 seconds (60000ms) per tool call. This can vary by host — Claude Desktop and Cursor use approximately 60 seconds. Check your host's documentation for the exact default.

Can I set different timeouts for different tools?

Not directly through the MCP protocol. The timeout is set per server, not per tool. If you have one slow tool and several fast ones, consider moving the slow tool to its own server with a higher timeout.

Do progress notifications actually prevent timeout?

This depends on the host implementation. Some hosts reset their timeout counter when they receive a progress notification. Others use a fixed timeout regardless. Progress notifications always improve user experience even if they do not affect the timeout.

What happens to in-progress work when a timeout occurs?

The host cancels the request, but the server may continue processing. There is no guaranteed cancellation mechanism in MCP. Design your tools to handle this gracefully — avoid leaving resources in a partially modified state.

Is there a maximum timeout I can set?

The MCP protocol does not define a maximum, but hosts may enforce their own limits. Setting a timeout over 5 minutes is generally not recommended as it creates a poor user experience.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.