What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use the official Model Context Protocol (MCP) C# SDK v2.0, register typed methods as tools, and choose the transport that matches how your host connects. For a local process launched by an MCP host, create a console app with the ModelContextProtocol package and stdio transport. For a network-accessible service, use an ASP.NET Core app with ModelContextProtocol.AspNetCore and map an HTTP endpoint. The SDK v2.0 implements the MCP specification revision dated July 28, 2026, so older preview tutorials may show obsolete HTTP APIs.

What you are building

MCP uses a host/client/server architecture. An AI host such as an editor starts or connects to your server; the server advertises tools, resources, or prompts; the host decides when to call them. Your .NET code remains the authority for validation, permissions, and side effects.

This guide creates a small echo tool first, then shows the HTTP shape, transport decisions, security settings, publishing route, and operational troubleshooting. The current SDK supports net8.0, net9.0, net10.0, and netstandard2.0. Pin package versions in a real project and check the SDK documentation whenever you upgrade because MCP protocol and package APIs change quickly.

Choose stdio or HTTP before writing code

Question Use local stdio Use ASP.NET Core HTTP
Who starts the server? The MCP host launches your executable as a child process. A web host, container, service manager, or platform runs the app.
Where is it reachable? Only through the launching host’s process pipes. Over a URL reachable by an MCP client, subject to network controls.
Best first project Console application with ModelContextProtocol. Web application with ModelContextProtocol.AspNetCore.
State model in SDK v2 Process lifetime naturally scopes state. HTTP is stateless by default; opt into sessions only when your feature requires them.
Typical reason to choose it Desktop assistants, IDE integrations, and private local automation. Shared services, remote clients, container deployment, or standard web infrastructure.

Stateless HTTP is recommended for servers that do not need server-to-client requests such as sampling or elicitation. If you do need those interactions or session state, follow the version-matched transport and session guidance rather than copying a v1 or preview sample.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prerequisites and project creation

  • Install a supported .NET SDK (the .NET 8, 9, or 10 SDK is a practical choice).
  • Use a terminal with access to NuGet.
  • For HTTP, understand ASP.NET Core hosting and configure a reverse proxy or container only after the local endpoint works.

The minimal local project uses the current package name without the old universal --prerelease instruction:

dotnet new console -n MyMcpServer
cd MyMcpServer
dotnet add package ModelContextProtocol
dotnet add package Microsoft.Extensions.Hosting

For an HTTP server:

dotnet new web -n MyMcpHttpServer
cd MyMcpHttpServer
dotnet add package ModelContextProtocol.AspNetCore

Build a local stdio server

1. Configure the host and tool discovery

Replace the generated Program.cs with this documented SDK pattern:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;

var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(options =>
{
    // Keep protocol stdout clean when using stdio transport.
    options.LogToStandardErrorThreshold = LogLevel.Trace;
});
builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();

await builder.Build().RunAsync();

[McpServerToolType]
public static class EchoTool
{
    [McpServerTool, Description("Echoes the message back to the client.")]
    public static string Echo(string message) => $"hello {message}";
}

WithToolsFromAssembly() scans the assembly for classes marked [McpServerToolType] and methods marked [McpServerTool]. The Description text is part of the tool contract an AI host sees, so describe inputs, outputs, side effects, and limits precisely. Keep the tool narrow: a method that performs one validated domain action is safer than a generic “run arbitrary code” tool.

2. Build and run

dotnet build
dotnet run

A stdio server normally waits for protocol messages, so a terminal may appear idle. Do not write banners, diagnostics, or JSON to standard output. Send ordinary logs to standard error, as the example does; otherwise you can corrupt the protocol stream.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Connect it from an MCP host

Configure the host’s MCP settings with the command it should launch. A typical configuration uses dotnet run --project /absolute/path/MyMcpServer during development. Use an absolute path, the correct working directory, and environment variables for secrets. For production-like local use, publish the executable and point the host at the published command instead of invoking a build on every launch.

Expose real tools safely

Typed arguments and validation

Use ordinary C# types for arguments and return values. Validate lengths, allowed identifiers, file paths, and network destinations inside the tool, not only in the prompt. Return a useful, bounded result rather than dumping an entire database or filesystem.

Dependency injection

Register services on builder.Services and inject them into tool classes when your chosen SDK pattern supports instance tools. Keep credentials in environment variables or a secret store. Never place API keys in tool descriptions or source control.

Prompts and resources

The SDK also provides analogous attributes for prompts and resources. Add them only when the client needs reusable prompt templates or read-only contextual data; a tool is the right abstraction for an explicit operation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build an ASP.NET Core HTTP server

1. Configure the endpoint

In the web project, use the HTTP transport, discover tools, map MCP, and run:

using ModelContextProtocol.Server;

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddMcpServer()
    .WithHttpTransport(options =>
    {
        // Stateless is appropriate when the server does not need
        // server-to-client requests such as sampling or elicitation.
        options.Stateless = true;
    })
    .WithToolsFromAssembly();

var app = builder.Build();
app.MapMcp();
app.Run();

[McpServerToolType]
public static class EchoTool
{
    [McpServerTool, System.ComponentModel.Description("Echoes the message back to the client.")]
    public static string Echo(string message) => $"hello {message}";
}

Confirm the exact option names against the SDK version in your project. The v2 HTTP design is self-contained and stateless by default, unlike many older samples that assume a persistent session.

2. Test locally

  1. Run dotnet run and note the HTTPS or HTTP address printed by ASP.NET Core.
  2. Point an MCP client at the mapped endpoint, including the path expected by your SDK version.
  3. Call the echo tool and inspect the structured result.

3. Decide whether state is required

Stay stateless when each request can carry everything needed and your server does not initiate sampling or elicitation. Choose stateful behavior only for a documented feature requirement, then design session expiration, concurrency, and recovery before deploying multiple instances.

HTTP security and deployment

Validate host names

Kestrel does not validate the HTTP Host header by default. For a local service, limit accepted names to loopback values. In production, configure the exact public host names and validate forwarded host headers at the reverse proxy or load balancer. This reduces DNS-rebinding exposure.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use CORS only for intentional browser access

Enable CORS only when a browser client genuinely needs cross-origin requests, and list specific allowed origins. CORS controls browser policy; it does not replace host-name validation, authentication, authorization, rate limiting, or input validation.

Deployment choices

  • Single machine: run the published app behind a process manager and bind only the required interface.
  • Container: expose the MCP port through your platform and keep secrets outside the image.
  • Reverse proxy: terminate TLS, validate forwarded headers, restrict inbound hosts, and pass only the MCP route.
  • Multiple instances: prefer stateless operation; if sessions are required, provide a shared session strategy and test reconnect behavior.

Preview project template and publishing route

Microsoft Learn also documents a .NET 10 quickstart using Microsoft.McpServer.ProjectTemplates. That template is explicitly preview, so check its prerequisites and generated code before adopting it. The walkthrough covers dotnet build, a sample random-number tool, GitHub Copilot configuration, a stdio .mcp.json entry using dotnet run --project ..., an HTTP URL configuration, and packing and publishing to NuGet.

The template route can be convenient when you want scaffolding and the documented Copilot workflow. It is not required for a hand-built SDK server. Its authoring and publishing prerequisites include the .NET 10 SDK, Visual Studio 2022 or VS Code options, GitHub Copilot for the integration steps, and a NuGet.org account for publishing.

Or skip the browser setup

If your MCP tool’s job is to capture a webpage, you can call ScreenshotNeo instead of maintaining browser automation. It is a website screenshot API and MCP server: consent banners are accepted and 60+ known consent platforms, newsletter popups, and chat widgets are removed before capture; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—work with Claude, Cursor, and other MCP clients.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

One GET request returns PNG, JPEG, WebP, or PDF. The API supports full-page and element captures, dark mode, device presets or custom viewports, retina scale, PDF paper and page settings, custom CSS and JavaScript, clicks, selector waits, delays, network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo documentation for options and response handling. Its free tier includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Complete client examples for ScreenshotNeo

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting checklist

Tool is not discovered

Check that the class has [McpServerToolType], the method has [McpServerTool], the tool assembly is loaded, and WithToolsFromAssembly() is present. Rebuild after changing attributes.

Client reports a protocol or handshake error

Match the client and server SDK/protocol expectations. Remove preview-era HTTP code, verify the endpoint path, and ensure only protocol data is sent on stdout for stdio.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

HTTP requests fail behind a proxy

Verify TLS termination, forwarded-host validation, route mapping, and that the proxy forwards the MCP method and body unchanged. Test the app directly on localhost before adding the proxy.

Requests hang

For stdio, confirm the host launched the correct executable and that the process is not waiting for interactive console input. For HTTP, inspect timeouts, reverse-proxy buffering, and whether a stateful configuration is expecting a session.

CORS or host errors

Add the exact browser origin only when required, and separately configure allowed host names. Do not solve a host-header problem by broadly enabling CORS.

Unexpected tool side effects

Reduce permissions, validate every argument, make destructive operations explicit, and return an operation identifier or bounded result that the host can display.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Performance, reliability, and cost decisions

  • Keep tools focused so model calls transfer small, predictable payloads.
  • Use cancellation-aware I/O and bounded timeouts for external services.
  • Prefer stateless HTTP for horizontal scaling and simpler recovery.
  • Log correlation IDs and failures to stderr or your web logger, never into stdio protocol output.
  • For local hosts, publish a self-contained or framework-dependent build according to the target machine and document the required runtime.
  • For remote hosts, protect the endpoint with your normal authentication and authorization layers; the SDK sample alone is not a complete production security boundary.

FAQ

Which NuGet package should a new server use?

Use ModelContextProtocol for a stdio server, ModelContextProtocol.AspNetCore for ASP.NET Core HTTP, and ModelContextProtocol.Core when you need the smaller low-level or client-oriented building block.

Does an MCP server have to run on Azure?

No. An ASP.NET Core MCP server can run on a developer workstation, a virtual machine, a container, or another web-hosting environment. The transport choice determines reachability, not a specific cloud provider.

Can I keep using an old preview tutorial?

Only after checking every package and transport call against SDK v2.0 documentation. The July 28, 2026 protocol revision changed HTTP behavior materially, including stateless-by-default operation and multi-round-trip requests.

The Bottom Line

Start with a small, attribute-based stdio server when a host launches your process. Move to ModelContextProtocol.AspNetCore and HTTP when clients need a reachable service, and treat host validation, CORS, logging, and state management as deployment concerns rather than optional polish.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.