Samples MCP Hosts - Garume/Manifold GitHub Wiki
This page provides a detailed walkthrough of the two MCP (Model Context Protocol) host sample applications included in the Manifold repository: McpStdioHost and McpHttpHost. These samples demonstrate how to host Manifold operations as MCP tools using two different transport mechanisms — stdio for local process communication and HTTP/Streamable HTTP for network-accessible endpoints. Both samples rely on source-generated registration code produced by the Manifold.Generators package, and share the same sample operations library. For an understanding of the underlying MCP runtime, see MCP Runtime — Manifold.Mcp.
Both MCP host samples follow the same high-level pattern: register the source-generated MCP server into the dependency injection container, select a transport, build the host, and run it. The difference lies in the hosting model and transport configuration.
flowchart TD
subgraph SharedLib["Manifold.Samples.Operations"]
SO["SampleOperations"]
WP["WeatherPreviewOperation"]
end
subgraph Generator["Source Generator"]
GEN["Manifold.Generators"]
end
SharedLib --> GEN
GEN --> GMT["GeneratedMcpTools"]
GEN --> GME["AddGeneratedMcpServer()"]
subgraph StdioHost["McpStdioHost"]
SH_B["HostApplicationBuilder"]
SH_T["WithStdioServerTransport()"]
SH_R["host.RunAsync()"]
end
subgraph HttpHost["McpHttpHost"]
HH_B["WebApplicationBuilder"]
HH_T["WithHttpTransport()"]
HH_M["app.MapMcp('/mcp')"]
HH_R["app.RunAsync()"]
end
GMT --> StdioHost
GME --> StdioHost
GMT --> HttpHost
GME --> HttpHost
Both host samples reference the Manifold.Samples.Operations project, which defines the operations exposed as MCP tools. This project references all four Manifold packages — including the source generator as an analyzer — so that the generated registration code is produced at compile time.
Sources: samples/Manifold.Samples.Operations/Manifold.Samples.Operations.csproj:1-14
The operations library contains two operations: a static-method style math.add operation and a class-based weather.preview operation:
[Operation("math.add", Description = "Add two integers.", Summary = "Returns the sum of x and y.")]
[CliCommand("math", "add")]
[McpTool("math_add")]
public static int Add(
[Argument(0, Name = "x", Description = "Left operand")] int x,
[Argument(1, Name = "y", Description = "Right operand")] int y)
{
return x + y;
}[Operation("weather.preview", Description = "Return a pretend weather summary.")]
[CliCommand("weather", "preview")]
[McpTool("weather_preview")]
public sealed class WeatherPreviewOperation : IOperation<WeatherPreviewOperation.Request, string>
{
public ValueTask<string> ExecuteAsync(Request request, OperationContext context) { /* ... */ }
}Sources: samples/Manifold.Samples.Operations/SampleOperations.cs:1-40
The source generator processes the [Operation] and [McpTool] attributes and emits several key artifacts. The most important for MCP hosting is the AddGeneratedMcpServer() extension method on IServiceCollection.
The generated GeneratedMcpServiceCollectionExtensions class provides a single extension method that registers the MCP server and the generated tool type:
public static IMcpServerBuilder AddGeneratedMcpServer(
this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);
IMcpServerBuilder builder =
McpServerServiceCollectionExtensions.AddMcpServer(services, static _ => { });
return McpServerBuilderExtensions.WithTools<GeneratedMcpTools>(builder);
}This method:
- Calls
AddMcpServer()from the ModelContextProtocol SDK to register the core MCP server services - Calls
WithTools<GeneratedMcpTools>()to register the generated tool class containing all MCP-visible operations
Sources: src/Manifold.Generators/OperationDescriptorGenerator.cs:1029-1040
The GeneratedMcpTools class is decorated with [McpServerToolType] and contains one method per MCP-visible operation, each annotated with [McpServerTool]:
[McpServerToolType]
public sealed class GeneratedMcpTools
{
private readonly IServiceProvider? services;
public GeneratedMcpTools(IServiceProvider? services = null)
{
this.services = services;
}
[McpServerTool(Name = "math_add")]
[Description("Add two integers.")]
public Task<int> MathAddAsync(/* parameters */) { /* ... */ }
[McpServerTool(Name = "weather_preview")]
[Description("Return a pretend weather summary.")]
public Task<string> WeatherPreviewAsync(/* parameters */) { /* ... */ }
}For class-based operations (like WeatherPreviewOperation), the generated method resolves the operation instance from the service provider and constructs an OperationContext for MCP invocation.
Sources: src/Manifold.Generators/OperationDescriptorGenerator.cs:1003-1027, src/Manifold.Generators/OperationDescriptorGenerator.cs:1837-1916
The stdio-based host is a console application that communicates with MCP clients through standard input and output streams. This transport is suitable for local tool invocation, such as when an AI assistant spawns the host as a subprocess.
The project uses the standard Microsoft.NET.Sdk and depends on Microsoft.Extensions.Hosting for the generic host infrastructure:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Manifold.Samples.McpStdioHost</AssemblyName>
<RootNamespace>Manifold.Samples.McpStdioHost</RootNamespace>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Manifold.Samples.Operations\Manifold.Samples.Operations.csproj" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
</ItemGroup>
</Project>Sources: samples/Manifold.Samples.McpStdioHost/Manifold.Samples.McpStdioHost.csproj:1-11
The entire host is configured in 6 lines of code:
using Manifold.Generated;
using Manifold.Samples.Operations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddTransient<WeatherPreviewOperation>();
builder.Services.AddGeneratedMcpServer()
.WithStdioServerTransport();
IHost host = builder.Build();
await host.RunAsync();Sources: samples/Manifold.Samples.McpStdioHost/Program.cs:1-12
sequenceDiagram
participant Client as MCP Client
participant Host as McpStdioHost
participant DI as ServiceProvider
participant Tools as GeneratedMcpTools
Host->>DI: CreateApplicationBuilder(args)
Host->>DI: AddTransient<WeatherPreviewOperation>()
Host->>DI: AddGeneratedMcpServer()
Note over DI: Registers MCP server<br/>and GeneratedMcpTools
Host->>DI: WithStdioServerTransport()
Note over DI: Configures stdin/stdout<br/>transport
Host->>Host: Build() and RunAsync()
Client->>Host: JSON-RPC via stdin
Host->>Tools: Dispatch to tool method
Tools->>DI: Resolve services
Tools-->>Host: Return result
Host-->>Client: JSON-RPC via stdout
| Step | Code | Purpose |
|---|---|---|
| 1. Create builder | Host.CreateApplicationBuilder(args) |
Initializes the generic host with default configuration, logging, and DI |
| 2. Register operation | AddTransient<WeatherPreviewOperation>() |
Registers the class-based operation so it can be resolved by the generated tool class |
| 3. Register MCP server | AddGeneratedMcpServer() |
Calls the source-generated extension to register the MCP server and all tool definitions |
| 4. Select transport | .WithStdioServerTransport() |
Configures the MCP server to communicate via stdin/stdout using JSON-RPC |
| 5. Build and run |
builder.Build() / host.RunAsync()
|
Constructs the DI container and starts listening for MCP requests |
The HTTP-based host is an ASP.NET Core web application that exposes MCP tools over HTTP and Streamable HTTP. This transport allows remote MCP clients to connect over the network.
The project uses Microsoft.NET.Sdk.Web and depends on ModelContextProtocol.AspNetCore for HTTP transport support:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<AssemblyName>Manifold.Samples.McpHttpHost</AssemblyName>
<RootNamespace>Manifold.Samples.McpHttpHost</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Manifold.Samples.Operations\Manifold.Samples.Operations.csproj" />
<PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.4.1-preview.1" />
</ItemGroup>
</Project>Note that the HTTP host does not explicitly reference Microsoft.Extensions.Hosting because the ASP.NET Core Web SDK includes it transitively.
Sources: samples/Manifold.Samples.McpHttpHost/Manifold.Samples.McpHttpHost.csproj:1-10
using Manifold.Generated;
using Manifold.Samples.Operations;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://127.0.0.1:38474");
builder.Services.AddTransient<WeatherPreviewOperation>();
builder.Services.AddGeneratedMcpServer()
.WithHttpTransport();
WebApplication app = builder.Build();
app.MapGet("/", () => Results.Text(
"Manifold MCP sample host is running.\nPOST MCP requests to /mcp or connect with a Streamable HTTP MCP client.",
"text/plain"));
app.MapMcp("/mcp");
await app.RunAsync();Sources: samples/Manifold.Samples.McpHttpHost/Program.cs:1-19
sequenceDiagram
participant Client as MCP Client
participant Kestrel as ASP.NET Core
participant MCP as MCP Middleware
participant Tools as GeneratedMcpTools
participant DI as ServiceProvider
Note over Kestrel: Listening on<br/>127.0.0.1:38474
Client->>Kestrel: GET /
Kestrel-->>Client: "MCP sample host is running"
Client->>Kestrel: POST /mcp (JSON-RPC)
Kestrel->>MCP: MapMcp routing
MCP->>Tools: Dispatch to tool method
Tools->>DI: Resolve services
DI-->>Tools: WeatherPreviewOperation
Tools-->>MCP: Tool result
MCP-->>Kestrel: JSON-RPC response
Kestrel-->>Client: HTTP response
| Step | Code | Purpose |
|---|---|---|
| 1. Create builder | WebApplication.CreateBuilder(args) |
Initializes ASP.NET Core with Kestrel, configuration, and DI |
| 2. Bind URL | builder.WebHost.UseUrls("http://127.0.0.1:38474") |
Sets the listen address to localhost on port 38474 |
| 3. Register operation | AddTransient<WeatherPreviewOperation>() |
Registers the class-based operation for DI resolution |
| 4. Register MCP server | AddGeneratedMcpServer() |
Source-generated extension to register MCP server and tools |
| 5. Select transport | .WithHttpTransport() |
Configures HTTP/Streamable HTTP transport via ModelContextProtocol.AspNetCore |
| 6. Map health endpoint | app.MapGet("/", ...) |
Provides a simple health-check response at the root URL |
| 7. Map MCP endpoint | app.MapMcp("/mcp") |
Routes MCP JSON-RPC requests to the /mcp path |
| 8. Run | await app.RunAsync() |
Starts the Kestrel server and begins accepting connections |
| Method | Path | Purpose |
|---|---|---|
| GET | / |
Health-check endpoint returning plain text status |
| POST | /mcp |
MCP JSON-RPC endpoint for tool invocation and discovery |
flowchart TD
subgraph Common["Shared Setup"]
REG["AddTransient<WeatherPreviewOperation>()"]
MCP["AddGeneratedMcpServer()"]
end
REG --> MCP
MCP --> STDIO["WithStdioServerTransport()"]
MCP --> HTTP["WithHttpTransport()"]
STDIO --> SB["host.RunAsync()"]
HTTP --> HB["app.MapMcp('/mcp')"]
HB --> HR["app.RunAsync()"]
style STDIO fill:#e1f0da
style HTTP fill:#dae1f0
| Aspect | McpStdioHost | McpHttpHost |
|---|---|---|
| SDK | Microsoft.NET.Sdk |
Microsoft.NET.Sdk.Web |
| Host type | HostApplicationBuilder |
WebApplicationBuilder |
| Transport | WithStdioServerTransport() |
WithHttpTransport() |
| Communication | stdin/stdout (JSON-RPC) | HTTP POST (JSON-RPC) |
| Endpoint mapping | Not required | app.MapMcp("/mcp") |
| Use case | Local subprocess tool hosting | Network-accessible MCP server |
| Key dependency |
Microsoft.Extensions.Hosting 10.0.0 |
ModelContextProtocol.AspNetCore 0.4.1-preview.1 |
| Lines of code | 12 | 19 |
Both samples depend on the shared operations library, which in turn references all Manifold packages:
flowchart TD
STDIO["McpStdioHost"]
HTTP["McpHttpHost"]
OPS["Samples.Operations"]
MFLD["Manifold"]
CLI["Manifold.Cli"]
MCPLIB["Manifold.Mcp"]
GEN["Manifold.Generators<br/>(Analyzer)"]
HOST["Microsoft.Extensions.Hosting"]
ASPNET["ModelContextProtocol.AspNetCore"]
MCPSDK["ModelContextProtocol"]
STDIO --> OPS
STDIO --> HOST
HTTP --> OPS
HTTP --> ASPNET
OPS --> MFLD
OPS --> CLI
OPS --> MCPLIB
OPS --> GEN
MCPLIB --> MCPSDK
MCPLIB --> MFLD
ASPNET --> MCPSDK
Sources: samples/Manifold.Samples.Operations/Manifold.Samples.Operations.csproj:6-13, src/Manifold.Mcp/Manifold.Mcp.csproj:19-24
Both hosts must register class-based operations (such as WeatherPreviewOperation) in the DI container before the generated MCP tools class can resolve them. The generated tool method for weather_preview calls McpBinding.GetRequiredServiceOrThrow<WeatherPreviewOperation>(services), which throws a descriptive error if the operation type is not registered.
Static-method operations (such as SampleOperations.Add) do not require DI registration, as the generated tool method invokes them directly.
flowchart TD
REG["services.AddTransient<WeatherPreviewOperation>()"]
ADD["services.AddGeneratedMcpServer()"]
TOOLS["GeneratedMcpTools registered"]
MCPSVR["MCP Server registered"]
REG --> ADD
ADD --> MCPSVR
ADD --> TOOLS
TOOLS --> INV["Tool invocation resolves<br/>WeatherPreviewOperation from DI"]
Sources: src/Manifold.Generators/OperationDescriptorGenerator.cs:1872-1876
The stdio host is typically launched by an MCP client as a subprocess. To run it manually:
dotnet run --project samples/Manifold.Samples.McpStdioHostThe process then waits for JSON-RPC messages on stdin and writes responses to stdout.
dotnet run --project samples/Manifold.Samples.McpHttpHostThe server starts listening on http://127.0.0.1:38474. Navigate to the root URL to verify the server is running, then send MCP requests to /mcp.
- Home — Project overview and quick-start guide
- Architecture Overview — High-level system architecture and package relationships
- MCP Runtime — Manifold.Mcp — Documentation of the MCP runtime package
- Source Generator — Manifold.Generators — Details on the code generation pipeline
- Sample — CLI Host — The companion CLI host sample
- Sample Operations Reference — Documentation of the shared sample operations
-
Attributes and Operation Definition — Reference for
[Operation],[McpTool], and other attributes -
Dependency Injection and Service Resolution — DI patterns and
[FromServices]usage - Performance and Benchmarks — Fast-path invocation design used by the MCP runtime