> ## Documentation Index
> Fetch the complete documentation index at: https://learn.orbexa.io/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server testing and debugging techniques

> Complete MCP Server testing guide — MCP Inspector, unit tests, integration tests, protocol compliance verification, and common debugging techniques

# Testing and Debugging

## 8.1 MCP Inspector

The official interactive debugging tool that lets you test every capability of your Server in a browser.

```bash theme={null}
npx @modelcontextprotocol/inspector node dist/index.js
```

The Inspector opens a web interface where you can:

* View all tools, resources, and prompts exposed by the Server
* Manually enter parameters and execute tools
* Inspect the raw JSON-RPC requests and responses
* Validate inputSchema and outputSchema
* Test resource reading and subscriptions
* Test prompt retrieval (with argument filling)
* View the Server's declared capabilities

### Testing Remote Servers with Inspector

The Inspector also supports testing Streamable HTTP Servers:

```bash theme={null}
npx @modelcontextprotocol/inspector --url https://my-server.example.com/mcp
```

You can attach authentication headers:

```bash theme={null}
npx @modelcontextprotocol/inspector --url https://my-server.example.com/mcp --header "Authorization: Bearer YOUR_TOKEN"
```

## 8.2 Unit Testing

Test each tool's execution logic (without involving the MCP protocol layer):

```typescript theme={null}
import { describe, it, expect } from "vitest";

describe("search_products tool", () => {
  it("returns matching products", async () => {
    const result = await searchProducts("running shoes", { limit: 5 });
    expect(result.results).toHaveLength(5);
    expect(result.results[0]).toHaveProperty("name");
    expect(result.results[0]).toHaveProperty("price");
  });

  it("returns empty array for no matches", async () => {
    const result = await searchProducts("nonexistent_product_xyz", { limit: 5 });
    expect(result.results).toHaveLength(0);
  });

  it("price range filtering works", async () => {
    const result = await searchProducts("shoes", {
      minPrice: 50,
      maxPrice: 100,
      limit: 10
    });
    result.results.forEach(p => {
      expect(p.price).toBeGreaterThanOrEqual(50);
      expect(p.price).toBeLessThanOrEqual(100);
    });
  });
});
```

### Testing Tool Error Handling

```typescript theme={null}
describe("get_order tool", () => {
  it("returns isError when order does not exist", async () => {
    const result = await getOrderTool({ orderId: "INVALID-001" });
    expect(result.isError).toBe(true);
    expect(result.content[0].text).toContain("not found");
  });
});
```

## 8.3 Integration Testing

Test the complete MCP protocol interaction, including initialization, capability negotiation, and tool calls:

```typescript theme={null}
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

describe("MCP Server Integration Tests", () => {
  let client: Client;

  beforeAll(async () => {
    const transport = new StdioClientTransport({
      command: "node",
      args: ["dist/index.js"]
    });
    client = new Client({
      name: "test-client",
      version: "1.0.0"
    });
    await client.connect(transport);
  });

  afterAll(async () => {
    await client.close();
  });

  it("initializes successfully and returns Server info", () => {
    const info = client.getServerInfo();
    expect(info.name).toBe("my-commerce-server");
  });

  it("tool list is not empty", async () => {
    const tools = await client.listTools();
    expect(tools.tools.length).toBeGreaterThan(0);
  });

  it("tool execution returns correct format", async () => {
    const result = await client.callTool("search_products", {
      query: "shoes"
    });
    expect(result.content[0].type).toBe("text");
    const data = JSON.parse(result.content[0].text);
    expect(data).toHaveProperty("results");
  });

  it("resource list is accessible", async () => {
    const resources = await client.listResources();
    expect(resources.resources.length).toBeGreaterThan(0);
  });

  it("resources are readable", async () => {
    const result = await client.readResource(
      "commerce://catalog/categories"
    );
    expect(result.contents[0].mimeType).toBe("application/json");
  });

  it("prompts are accessible", async () => {
    const prompts = await client.listPrompts();
    expect(prompts.prompts.length).toBeGreaterThan(0);
  });
});
```

## 8.4 Protocol Compliance Verification

Key checkpoints to ensure your Server conforms to the MCP specification:

| Checkpoint                             | Verification Method                                     |
| -------------------------------------- | ------------------------------------------------------- |
| `initialize` responds correctly        | Inspect initialization handshake in Inspector           |
| Capability declarations are complete   | Check that capabilities declare all provided primitives |
| `tools/list` pagination is correct     | Test cursor pagination with large tool sets             |
| `isError` is used correctly            | Business errors use isError, not JSON-RPC error         |
| Notification format is correct         | Notification messages have no id field                  |
| Content types are correct              | text/image/audio type fields are complete               |
| structuredContent matches outputSchema | When outputSchema exists, return structuredContent      |

## 8.5 Common Debugging Techniques

| Problem                      | Diagnosis                          | Solution                                   |
| ---------------------------- | ---------------------------------- | ------------------------------------------ |
| Server not responding        | Check stderr output                | Confirm the process started successfully   |
| Tools missing from list      | Check tools/list in Inspector      | Review tool registration code              |
| Parameter type errors        | Check inputSchema in Inspector     | Correct the JSON Schema                    |
| Incorrect return data format | Check raw response in Inspector    | Ensure content array format is correct     |
| Claude cannot see the Server | Check `claude_desktop_config.json` | Confirm the path and command are correct   |
| Initialization timeout       | Check Server startup time          | Reduce blocking operations during startup  |
| Streamable HTTP 401          | Check OAuth configuration          | Confirm the token is valid and not expired |
| Session lost                 | Check `Mcp-Session-Id` header      | Ensure Client includes it in every request |

### stderr Logging

Logs from a stdio Server must be output to stderr:

```typescript theme={null}
// Correct -- output to stderr
console.error("[INFO] Server started");
console.error(`[DEBUG] Processing request: ${method}`);

// Wrong -- will break protocol communication
console.log("Server started");  // stdout is the protocol channel
```

### Log Levels

The MCP specification defines standard log levels. Servers can send log messages to the Client via `notifications/message`:

```typescript theme={null}
// Server -> Client sends log notification
server.sendLoggingMessage({
  level: "warning",
  logger: "inventory",
  data: "SKU SHOE-001 inventory below safety threshold"
});
```

The Client can set the minimum log level it wants to receive via `logging/setLevel`.

### Debugging Streamable HTTP

For remote Servers, you can use `curl` to manually send JSON-RPC requests:

```bash theme={null}
curl -X POST https://my-server.example.com/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

***

**Next Chapter**: [Deployment Guide](/en/book-5/ch9-deployment) — Local deployment vs remote deployment
