--- title: Getting Started author: stephentoub description: Install the MCP C# SDK and build your first MCP client and server. uid: getting-started --- ## Getting started This guide walks you through installing the MCP C# SDK and building a minimal MCP client and server. ### Choosing a package The SDK ships as three NuGet packages. Pick the one that matches your scenario: | Package | Use when... | |---------|-------------| | **[ModelContextProtocol.Core](https://www.nuget.org/packages/ModelContextProtocol.Core/absoluteLatest)** | You only need the client or low-level server APIs and want the **minimum set of dependencies**. | | **[ModelContextProtocol](https://www.nuget.org/packages/ModelContextProtocol/absoluteLatest)** | You're building a client or a **stdio-based** server and want hosting, dependency injection, and attribute-based tool/prompt/resource discovery. References `ModelContextProtocol.Core`. **This is the right starting point for most projects.** | | **[ModelContextProtocol.AspNetCore](https://www.nuget.org/packages/ModelContextProtocol.AspNetCore/absoluteLatest)** | You're building an **HTTP-based** MCP server hosted in ASP.NET Core. References `ModelContextProtocol`, so you get everything above plus the HTTP transport. | > [!TIP] > If you're unsure, start with the **ModelContextProtocol** package. You can always add **ModelContextProtocol.AspNetCore** later if you need HTTP transport support. ### Building an MCP server > [!TIP] > You can also use the [MCP Server project template](https://learn.microsoft.com/dotnet/ai/quickstarts/build-mcp-server) to quickly scaffold a new MCP server project. Create a new console app and add the required packages: ``` dotnet new console dotnet add package ModelContextProtocol dotnet add package Microsoft.Extensions.Hosting ``` Replace `Program.cs` with the following code to get a working MCP server that exposes a single tool over stdio: ```csharp 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(consoleLogOptions => { // Configure all logs to go to stderr consoleLogOptions.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}"; } ``` The call to `WithToolsFromAssembly` discovers every class marked with `[McpServerToolType]` in the assembly and registers every `[McpServerTool]` method as a tool. Prompts and resources work the same way with `[McpServerPromptType]` / `[McpServerPrompt]` and `[McpServerResourceType]` / `[McpServerResource]`. For HTTP-based servers using ASP.NET Core, add the following packages: ``` dotnet new web dotnet add package ModelContextProtocol.AspNetCore ``` And add the following code: ```csharp using ModelContextProtocol.Server; using System.ComponentModel; var builder = WebApplication.CreateBuilder(args); builder.Services.AddMcpServer() .WithHttpTransport(options => { // Stateless mode is recommended for servers that don't need // server-to-client requests like sampling or elicitation. // See the Sessions documentation for details. options.Stateless = true; }) .WithToolsFromAssembly(); var app = builder.Build(); app.MapMcp(); app.Run("http://localhost:3001"); [McpServerToolType] public static class EchoTool { [McpServerTool, Description("Echoes the message back to the client.")] public static string Echo(string message) => $"hello {message}"; } ``` #### Host name validation For local HTTP servers, keep the set of accepted host names limited to loopback values. This helps protect against DNS rebinding, where a browser reaches a local server through an attacker-controlled DNS name while sending that DNS name in the HTTP `Host` header. ASP.NET Core's Kestrel server doesn't validate `Host` headers by default, so configure `AllowedHosts` with known host names rather than `"*"`. For production servers, configure the exact public host names for the deployment, and validate the host name at the proxy or load balancer when one is responsible for forwarding client requests. This also avoids reflecting untrusted host names through ASP.NET Core features such as absolute URL generation. See [Host filtering with ASP.NET Core Kestrel web server | Microsoft Learn](https://learn.microsoft.com/aspnet/core/fundamentals/servers/kestrel/host-filtering) and [URL generation concepts | Microsoft Learn](https://learn.microsoft.com/aspnet/core/fundamentals/routing#url-generation-concepts). #### Browser cross-origin access **Only** enable cross-origin requests (CORS) if you intentionally want browser-based cross-origin access to this server. CORS is not a substitute for host name validation. When browser-based cross-origin access is required, limit which browser origins can call the MCP endpoint by using the most restrictive ASP.NET Core CORS policy possible. See [Enable Cross-Origin Requests (CORS) in ASP.NET Core | Microsoft Learn](https://learn.microsoft.com/aspnet/core/security/cors). For the full HTTP security examples, including `AllowedHosts` and restrictive CORS on `MapMcp`, see [Streamable HTTP transport](transports/transports.md#browser-cross-origin-access). ### Building an MCP client Create a new console app and add the following packages: ``` dotnet new console dotnet add package ModelContextProtocol ``` Replace `Program.cs` with the following code. This client connects to the MCP "everything" reference server, lists its tools, and calls one: ```csharp using ModelContextProtocol.Client; using ModelContextProtocol.Protocol; var clientTransport = new StdioClientTransport(new StdioClientTransportOptions { Name = "Everything", Command = "npx", Arguments = ["-y", "@modelcontextprotocol/server-everything"], }); var client = await McpClient.CreateAsync(clientTransport); // Print the list of tools available from the server. foreach (var tool in await client.ListToolsAsync()) { Console.WriteLine($"{tool.Name} ({tool.Description})"); } // Execute a tool (this would normally be driven by LLM tool invocations). var result = await client.CallToolAsync( "echo", new Dictionary() { ["message"] = "Hello MCP!" }, cancellationToken: CancellationToken.None); // echo always returns one and only one text content object Console.WriteLine(result.Content.OfType().First().Text); ``` Clients can connect to any MCP server, not just ones created with this library. The protocol is server-agnostic. #### Using tools with an LLM `McpClientTool` inherits from [`AIFunction`](https://learn.microsoft.com/dotnet/api/microsoft.extensions.ai.aifunction), so the tools returned by `ListToolsAsync` can be given directly to any `IChatClient`: ```csharp // Get available tools. IList tools = await client.ListToolsAsync(); // Call the chat client using the tools. IChatClient chatClient = ...; var response = await chatClient.GetResponseAsync( "your prompt here", new() { Tools = [.. tools] }); ``` ### Next steps Explore the rest of the conceptual documentation to learn about [tools](tools/tools.md), [prompts](prompts/prompts.md), [resources](resources/resources.md), [transports](transports/transports.md), and [Docker deployment](deployment/docker.md) for HTTP-based servers. You can also browse the [samples](https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples) directory for complete end-to-end examples.