Samples MCP Hosts - Garume/Manifold GitHub Wiki

Samples — MCP Hosts (Stdio and HTTP)

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.

Architecture Overview

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
Loading

Shared Operations Library

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

Source-Generated Registration

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.

Generated Extension Method

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:

  1. Calls AddMcpServer() from the ModelContextProtocol SDK to register the core MCP server services
  2. Calls WithTools<GeneratedMcpTools>() to register the generated tool class containing all MCP-visible operations

Sources: src/Manifold.Generators/OperationDescriptorGenerator.cs:1029-1040

Generated Tool Class

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

McpStdioHost — Stdio Transport

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.

Project Configuration

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

Program Entry Point

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

Startup Sequence

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
Loading

Key Steps Explained

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

McpHttpHost — HTTP Transport

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.

Project Configuration

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

Program Entry Point

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

Startup and Request Flow

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
Loading

Key Steps Explained

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

Endpoint Summary

Method Path Purpose
GET / Health-check endpoint returning plain text status
POST /mcp MCP JSON-RPC endpoint for tool invocation and discovery

Comparing the Two Hosts

flowchart TD
    subgraph Common["Shared Setup"]
        REG["AddTransient&lt;WeatherPreviewOperation&gt;()"]
        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
Loading
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

Dependency Graph

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
Loading

Sources: samples/Manifold.Samples.Operations/Manifold.Samples.Operations.csproj:6-13, src/Manifold.Mcp/Manifold.Mcp.csproj:19-24

Service Registration Pattern

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&lt;WeatherPreviewOperation&gt;()"]
    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"]
Loading

Sources: src/Manifold.Generators/OperationDescriptorGenerator.cs:1872-1876

Running the Samples

McpStdioHost

The stdio host is typically launched by an MCP client as a subprocess. To run it manually:

dotnet run --project samples/Manifold.Samples.McpStdioHost

The process then waits for JSON-RPC messages on stdin and writes responses to stdout.

McpHttpHost

dotnet run --project samples/Manifold.Samples.McpHttpHost

The 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.

Related Pages

⚠️ **GitHub.com Fallback** ⚠️