BrandGhost
Testing and Debugging Your C# MCP Server with MCP Inspector

Testing and Debugging Your C# MCP Server with MCP Inspector

If you've already built a server and now need to prove that it actually behaves like an MCP server, MCP Inspector should be one of your first stops. It gives C# and .NET developers a focused way to connect to an MCP server, list capabilities, invoke tools, read resources, try prompts, and inspect the JSON-RPC traffic without guessing what your eventual host is doing behind the scenes.

This is a MOFU debugging guide, so the focus is practical evaluation. I am not going to rebuild the server from scratch or dive deeply into in-server logging implementation. Instead, we'll use MCP Inspector to test an already-built C# MCP server over stdio or Streamable HTTP, understand the failure signals, and decide when a complementary C# harness or xUnit integration test makes sense.

At review time in July 2026, NuGet lists ModelContextProtocol, ModelContextProtocol.Core, and ModelContextProtocol.AspNetCore stable packages at 1.4.0, with preview packages also possible in the feed. Check NuGet before pinning versions. The Inspector details in this article were verified against the live MCP Inspector repository and the official MCP Inspector documentation.

What MCP Inspector Is and Why It Belongs in Your Debug Loop

MCP Inspector is the official interactive developer tool for testing and debugging MCP servers. The live repository describes it as two cooperating pieces: a React-based web UI called the MCP Inspector Client and a Node.js proxy server that acts as an MCP client to your server. That proxy can connect through stdio, SSE, or Streamable HTTP, while the browser UI gives you tabs for tools, resources, prompts, logs, notifications, and request history.

That architecture matters for a C# MCP server because stdio is not browser-friendly. Your browser cannot directly spawn dotnet run and speak JSON-RPC over stdin and stdout. The Node proxy does that work, then exposes the interaction to the React UI. For Streamable HTTP servers, the proxy still gives you a consistent Inspector experience and helps you keep protocol testing separate from your target MCP host.

The biggest benefit is isolation. If MCP Inspector cannot connect to your server or list its tools, you can investigate your server launch, transport selection, endpoint URL, schema, or protocol output before blaming your editor, agent framework, or desktop client. If MCP Inspector works but another host fails, the problem is more likely in that host's configuration.

For a broader agent context, this fits naturally beside MCP tool integration in Microsoft Agent Framework in C#. Inspector helps validate the server contract before you plug the contract into a larger agent workflow.

Starting MCP Inspector for a C# Stdio Server

The repository quick start is simple: run npx @modelcontextprotocol/inspector. The live MCP Inspector repository states that Node.js ^22.7.5 is required, the client UI defaults to http://localhost:6274, and the proxy defaults to port 6277. The proxy also requires authentication by default and prints a session token plus a pre-filled URL when it starts.

For a C# stdio server, you can launch Inspector and point it at dotnet run:

npx @modelcontextprotocol/inspector -- dotnet run --project C:devMyMcpServerMyMcpServer.csproj

If your server needs arguments, pass them after the command. If your server needs environment variables, use the Inspector -e flag before the separator. The repository docs also recommend -- when you need to separate Inspector flags from server arguments.

npx @modelcontextprotocol/inspector `
  -e ASPNETCORE_ENVIRONMENT=Development `
  -e MY_SERVER_SETTING=local `
  -- dotnet run --project C:devMyMcpServerMyMcpServer.csproj -- --profile debug

That separator pattern is easy to miss. The separator before dotnet belongs to Inspector. The later -- before --profile belongs to dotnet run, so --profile debug reaches the server process rather than being interpreted as an Inspector option.

For faster iteration, you can also point MCP Inspector at a built executable instead of dotnet run. That removes build time from each connection attempt and gets closer to how many stdio MCP hosts will launch your server.

npx @modelcontextprotocol/inspector `
  -- C:devMyMcpServerinDebug
et10.0MyMcpServer.exe `
  --workspace C:devsample-workspace

Use the built executable when you are debugging process launch behavior. Use dotnet run --project when you are iterating quickly and want build-and-run convenience. The tradeoff is speed versus convenience.

Connect MCP Inspector to a C# Streamable HTTP Server

For a C# Streamable HTTP server, start your ASP.NET Core MCP server separately, then connect MCP Inspector to the endpoint URL. The C# SDK docs show ModelContextProtocol.AspNetCore, WithHttpTransport(...), and app.MapMcp() for HTTP servers, with Streamable HTTP as the recommended HTTP transport for remote servers. If your server maps MCP at /mcp, the Inspector URL value should point directly at that route.

Write-Host 'Starting the already-built ASP.NET Core MCP server'
$env:ASPNETCORE_URLS = 'http://localhost:3001'
dotnet run --project C:devMyHttpMcpServerMyHttpMcpServer.csproj

Write-Host 'Opening Inspector UI'
npx @modelcontextprotocol/inspector

In the Inspector UI, choose the Streamable HTTP transport and enter:

http://localhost:3001/mcp

This is a common place to make an endpoint mistake. app.MapMcp() maps the default route unless your application specifies a route like app.MapMcp("/mcp"). If your server maps /mcp, connect to /mcp. If it maps root, connect to the root. If you accidentally enter the app's home page, a Swagger endpoint, or an old SSE URL, Inspector will fail before it can meaningfully test your tools.

If your server calls downstream HTTP services, the patterns from HttpClient in C#: The Complete Guide for .NET Developers and IHttpClientFactory in .NET still matter. MCP Inspector proves the MCP contract. It does not magically make downstream dependencies reliable.

Use the MCP Inspector UI to Test Tools, Resources, and Prompts

Once connected, start with the capability list. MCP Inspector's Tools tab lists available tools, descriptions, schemas, and execution results. For a C# server using attribute discovery, this is where you verify that [McpServerToolType], [McpServerTool], and [Description] metadata produced the contract you intended.

A practical workflow is straightforward. List tools. Pick a read-only or low-risk tool. Fill in the generated form fields. Invoke it. Then inspect both the displayed result and the raw request/response log. If the tool does not appear, the issue is usually registration or discovery. If it appears with the wrong inputs, the issue is usually the C# method signature, descriptions, or schema generation. If it appears and fails during invocation, the issue is likely runtime behavior inside the tool or its dependencies.

Here is a tiny C# client-style shape that mirrors what Inspector is doing conceptually. You would not use this instead of Inspector for visual debugging, but it helps explain the interaction model:

using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;

var transport = new StdioClientTransport(new StdioClientTransportOptions
{
    Name = "Local C# MCP Server",
    Command = "dotnet",
    Arguments = ["run", "--project", @"C:devMyMcpServerMyMcpServer.csproj"],
});

await using var client = await McpClient.CreateAsync(transport);

foreach (var tool in await client.ListToolsAsync())
{
    Console.WriteLine($"{tool.Name}: {tool.Description}");
}

var result = await client.CallToolAsync(
    "echo",
    new Dictionary<string, object?> { ["message"] = "hello from a harness" },
    cancellationToken: CancellationToken.None);

Console.WriteLine(result.Content.OfType<TextContentBlock>().First().Text);

MCP Inspector gives you the same basic loop with less harness code and more visibility. That makes it especially useful when you are exploring a server contract, finding schema surprises, or trying several inputs manually.

Resources and prompts deserve the same treatment. In the Resources tab, list available resources and inspect returned content, MIME types, and metadata. In the Prompts tab, provide prompt arguments and preview generated messages. This catches a different class of bug than tool invocation. A tool can work while a resource URI template is awkward, or a prompt can generate the wrong message shape even when the server initializes correctly.

Read the Raw JSON-RPC Log in MCP Inspector

The raw JSON-RPC request/response log is where MCP Inspector becomes more than a form UI. It lets you inspect the initialization exchange, method names, parameters, responses, and errors. When something fails, do not stop at the red error banner. Read the actual JSON-RPC payload.

Look first at initialization. The client and server negotiate protocol version and capabilities. If initialization fails, later tool calls are irrelevant. The MCP debugging guide calls out capability negotiation as a common issue, including -32602, the standard JSON-RPC invalid params code, in many contexts. If you see that around initialization, compare what the client declared with what your server expects.

Next, inspect tools/list, resources/list, and prompts/list. The list response tells you what your C# server actually exposed. This is better evidence than what you thought you registered. For C# attribute-based servers, the log can reveal missing descriptions, unexpected parameter names, unexpected required fields, or no tools at all.

Finally, inspect tools/call. If the request body contains a parameter type your C# method cannot bind, that is different from your tool throwing after successful binding. The Inspector log helps separate schema mismatch, validation failure, transport failure, and application failure.

If you are also collecting server-side logs, connect the two views by time and tool name. Keep the implementation detail light inside the article's scope, but in practice the connection between Inspector JSON-RPC and server logs shortens the debugging loop. For .NET logging fundamentals, Logging in .NET: The Complete Developer's Guide is the better deep dive.

Debug MCP Server .NET Failure Patterns with MCP Inspector

The most painful failures usually fit a few patterns. MCP Inspector helps because each pattern leaves a different trace.

The first .NET-specific pattern is stdout contamination in stdio mode. Stdio MCP uses stdout for JSON-RPC protocol messages. If your C# server writes normal logs, banners, Console.WriteLine output, or diagnostic text to stdout, the client reads non-protocol text where JSON-RPC should be. Inspector may fail to initialize, disconnect, or show malformed responses. The C# SDK getting-started docs configure console logging to standard error for stdio servers, and the MCP debugging guide warns that local MCP servers should not log to stdout.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

var builder = Host.CreateApplicationBuilder(args);

builder.Logging.AddConsole(options =>
{
    // For stdio MCP, stdout is protocol traffic. Send logs to stderr.
    options.LogToStandardErrorThreshold = LogLevel.Trace;
});

builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();

await builder.Build().RunAsync();

The second pattern is the wrong transport or endpoint. A stdio server needs a command. A Streamable HTTP server needs a URL. A legacy SSE URL is not the same as a Streamable HTTP endpoint. In the C# SDK transport docs, Streamable HTTP is the recommended transport for remote servers, while SSE is legacy and disabled by default unless explicitly enabled. If Inspector cannot connect over HTTP, verify the route, scheme, port, and transport selection before changing server code.

The third pattern is schema mismatch. C# makes it easy to express optional parameters, enums, nullable values, complex objects, and service parameters. Inspector shows what reached the MCP contract. If a parameter you expected is missing, required when it should be optional, or shaped differently than expected, test the smallest input that should pass. Then compare the schema and the raw tools/call payload.

The fourth pattern is environment drift. Stdio clients may launch your process with a different working directory or a different environment than your shell. Inspector lets you pass environment variables explicitly with -e, and the UI supports customizing command-line arguments and environment for local servers. If a tool works in your terminal but not in Inspector, check the command, working directory assumptions, required files, and environment variables before assuming MCP is broken.

The fifth pattern is dependency behavior. Your tool might call a database, HTTP API, filesystem, or containerized dependency. Inspector can prove that MCP routing and JSON-RPC are working, but it cannot replace integration tests for those dependencies. If you need to isolate downstream HTTP behavior, the ideas in Mock HttpClient C#: DelegatingHandler, Mock Handlers, and Integration Testing are a better fit. If the server depends on real infrastructure during local verification, C# Testcontainers for MongoDB shows the style of repeatable dependency setup I prefer.

Export or Generate an mcp.json Configuration from Inspector

After you have a working connection, MCP Inspector can help you capture that configuration. The MCP Inspector repository docs describe Server Entry and Servers File export buttons. Server Entry copies one server configuration that you can paste under mcpServers in an existing file. Servers File copies a complete mcp.json-style payload using default-server.

For a stdio C# server, the exported shape is conceptually like this:

{
  "mcpServers": {
    "default-server": {
      "command": "dotnet",
      "args": [
        "run",
        "--project",
        "C:\dev\MyMcpServer\MyMcpServer.csproj"
      ],
      "env": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

For a Streamable HTTP C# server, the shape is more like this:

{
  "mcpServers": {
    "default-server": {
      "type": "streamable-http",
      "url": "http://localhost:3001/mcp",
      "note": "For Streamable HTTP connections, add this URL directly in your MCP Client"
    }
  }
}

Treat export as a way to reduce transcription mistakes, not as a replacement for review. Remove secrets before committing anything. Prefer absolute paths when the target client may launch from an unpredictable working directory. Rename default-server to something meaningful before using the file in a real workspace.

Complementary Testing Beyond MCP Inspector

MCP Inspector is the focus because it is interactive, visual, and protocol-aware. But it should not be the only verification path once a server becomes important. I like using Inspector for exploratory debugging and then capturing important behaviors in automated tests.

A tiny C# harness is useful when you want repeatable command-line checks without a browser. It can list tools, call a known tool, and assert on the result shape. This is especially useful for local stdio servers because it exercises process launch behavior.

using ModelContextProtocol.Client;

public static async Task<int> Main()
{
    var transport = new StdioClientTransport(new StdioClientTransportOptions
    {
        Command = @"C:devMyMcpServerinDebug
et10.0MyMcpServer.exe",
        Arguments = [],
        WorkingDirectory = @"C:devMyMcpServer"
    });

    await using var client = await McpClient.CreateAsync(transport);
    var tools = await client.ListToolsAsync();

    return tools.Any(tool => tool.Name == "echo") ? 0 : 1;
}

An xUnit integration test is better when you want the behavior to live with the codebase and run in CI. For HTTP servers, this might be an ASP.NET Core integration test that hosts the app and calls the MCP endpoint through the SDK client. For stdio servers, it might launch the built executable and assert that key tools list and return expected responses.

The tradeoff is simple. MCP Inspector is faster for diagnosis and discovery. Automated tests are better for regression protection. Use Inspector to understand the bug, then promote the important lesson into a test if the behavior matters long term.

MCP Inspector Security Notes for Local Debugging

Because MCP Inspector's proxy can spawn local processes and connect to specified MCP servers, treat it like a local developer tool with real privileges. The live MCP Inspector repository warns that the proxy should not be exposed to untrusted networks. By default, the client and proxy bind to localhost, and proxy authentication is enabled with a generated session token. Keep those defaults unless you have a specific, trusted development reason to change them.

Do not disable authentication casually. The repository documents DANGEROUSLY_OMIT_AUTH=true and explicitly labels it dangerous. For normal C# MCP server debugging, you do not need that setting. If you run Inspector in Docker, bind ports to 127.0.0.1 unless you intentionally need broader access.

Also remember that MCP Inspector may pass environment variables to a child process. Avoid pasting production secrets into a local debugging session. Use dedicated local credentials, scoped test tokens, or mock dependencies where practical.

Final Takeaway: Use MCP Inspector Before You Blame the Host

When you need to debug MCP server .NET behavior, MCP Inspector gives you a fast way to separate server contract problems from host integration problems. Start with connection. Verify capability negotiation. List tools, resources, and prompts. Invoke one simple tool. Read the JSON-RPC log. Then move outward to environment variables, endpoint routing, downstream dependencies, and the target client.

That order keeps the debugging loop grounded in evidence. MCP Inspector does not replace good .NET tests, good logs, or careful server design. But for testing and debugging an already-built C# MCP server, it gives you the protocol-level visibility you need before speculation takes over.

FAQ

What is MCP Inspector used for?

MCP Inspector is used for testing and debugging MCP servers through an interactive UI and proxy. For C# developers, it helps verify stdio and Streamable HTTP connections, list server capabilities, invoke tools, read resources, try prompts, and inspect the raw JSON-RPC exchange.

How do I use MCP Inspector with a C# stdio server?

Run npx @modelcontextprotocol/inspector followed by -- and the command that launches your server when the server command has flags. For example, use npx @modelcontextprotocol/inspector -- dotnet run --project C:devMyMcpServerMyMcpServer.csproj. If your server needs environment variables, pass them with Inspector's -e flag before the separator.

How do I use MCP Inspector with a C# Streamable HTTP server?

Start the ASP.NET Core MCP server first, then open MCP Inspector and select Streamable HTTP. Enter the exact endpoint URL, such as http://localhost:3001/mcp when your server uses app.MapMcp("/mcp"). Wrong routes and wrong transports are common causes of connection failures.

Why does my MCP server fail in stdio mode but run from the terminal?

One common reason is stdout contamination. In stdio mode, stdout is reserved for JSON-RPC messages. If your C# server writes logs or Console.WriteLine text to stdout, MCP Inspector may see malformed protocol traffic. Send logs to stderr instead.

Can MCP Inspector replace xUnit integration tests?

No. MCP Inspector is excellent for interactive testing and diagnosis, but xUnit tests are better for repeatable regression coverage. Use MCP Inspector to discover what is happening, then add tests for the behavior that must stay fixed.

Does MCP Inspector generate mcp.json files?

Yes. The Inspector UI provides Server Entry and Servers File export buttons after you configure a server. These can produce stdio or Streamable HTTP configuration payloads that you can adapt for clients that use mcp.json-style configuration.

Is MCP Inspector safe to expose on my network?

Generally, no. The proxy can spawn local processes and connect to configured MCP servers, so keep it bound to localhost for normal development. Inspector uses proxy authentication by default, and you should avoid disabling it.

Building MCP Servers and Clients in C#: The Complete Guide

Learn how to build an MCP server C# developers can trust, from stdio and HTTP transports to tools, clients, security, Azure hosting, and debugging tips.

Build Your First MCP Server in C#: A Step-by-Step Quickstart

Build an MCP server in C# with a local stdio quickstart covering packages, Host setup, tool attributes, VS Code wiring, stderr logs, and common fixes.

MCP Tool Integration in Microsoft Agent Framework in C#

MCP tool integration in Microsoft Agent Framework in C# using AIFunctionFactory and ChatClientAgent -- real working code with filesystem tools.

An error has occurred. This application may no longer respond until reloaded. Reload