Skip to content

About

A dotnet new template for a Model Context Protocol server using the MCP C# SDK, built with a streamlined Clean Architecture on .NET 10.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Clean Model Context Protocol

Build Pipeline NuGet NuGet Downloads License

A dotnet new template for a Model Context Protocol server using the MCP C# SDK in .NET 10, built with a streamlined Clean Architecture. All the layers you need, none of the ceremony you don't.

It's one of five Lean Mean Clean Apps templates. They share the same Application and Infrastructure layers and differ only in how they face the world. Same genes, different haircuts.

The guides, the reference and the reasoning behind every opinion live at leanmeancleanapps.github.io/mcp. This is the version for people who skim. We see you.

Get started

You need the .NET 10 SDK. Docker is optional, but it's the quickest way to see it running.

# Install the template
dotnet new install CleanModelContextProtocol.Template

# Create a solution
dotnet new cleanmodelcontextprotocol --name WorksOnMyMachine.Movies --authorName "Your Name"
cd WorksOnMyMachine.Movies

cleanmcp works too, for anyone who'd rather not type cleanmodelcontextprotocol every time, and so do lmca-mcp and leanmeancleanapps-mcp. dotnet new search leanmeanclean lists the whole family.

Option Default What it does
--name, -n The folder's name Names the solution and its root namespace
--authorName, -an Stephen Walsh Puts your name on the assembly instead of ours
--include-auth Off Adds OAuth for MCP clients. Leave it out and the server has no auth code at all
--authority, -iss Empty Your OAuth authorization server. Required with --include-auth
--audience, -aud Empty The audience tokens must be issued for, usually the server's own URL. Only used with --include-auth
--no-restore Off Skips the package restore that normally runs once the solution is created

Rather click than type? Visual Studio and Rider show the same options in their new project dialogs. They always show the authority and audience fields, but only use them when Include authentication is ticked. In the terminal, dotnet new cleanmodelcontextprotocol --help lists them all.

That's three layers, four test projects, a Dockerfile and a CI pipeline. Go and tell your team you've been working on it all week.

Run it

# Build the image and start it with sample data, plus the MCP Inspector, a collector and the Aspire dashboard
docker compose up -d --build

# Ask the movies_search tool for a page of movies
curl http://localhost:8080/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "movies_search",
      "arguments": { "query": "space", "limit": 2 }
    }
  }'

The answer comes back as an event stream, and its result carries the movies as structured content:

{
  "items": [
    {
      "id": "cb188ef6-14e7-f85f-2f78-924c2ab26b28",
      "title": "Deep Space Gardeners",
      "reviewCount": 5,
      "averageStars": 3.4
    },
    {
      "id": "dfefa450-5454-6a4d-a4aa-95a9b047c17b",
      "title": "Postcards from Outer Space",
      "reviewCount": 1,
      "averageStars": 3
    }
  ],
  "totalCount": 4,
  "nextOffset": 2
}

The sample movies are all made up, and the critics are harsh.

Curl is a fine way to prove it works and a terrible way to spend an afternoon. Open the MCP Inspector at http://localhost:6274 instead. It's already pointed at the server, so flip the switch to connect and open Tools.

For a chat over the same tools, docker compose --profile demo up -d --build adds Open WebUI at http://localhost:3000. It's optional and online only, and your prompts go to Kilo's free gateway, a third party. Run it has the details.

There are six tools shaped around jobs rather than tables: movies_search, movies_get, authors_search, reviews_list, reviews_write and reviews_delete. Each has a description written for agents and hints that say what's read-only and what's destructive. Lists come back ten at a time, with a totalCount and a nextOffset when there's more to come, so an agent doesn't drown in its own context window. There are resources for every movie, author and review, and prompts for jobs like comparing two movies. Its logs, traces and metrics land in the Aspire dashboard at http://localhost:18888.

No Docker? dotnet run --project src/Presentation works too. Every other way to run it, from plain docker run to stamping a version into the image, is in docs/RUN.md.

The server is open unless you ask for authentication. Create the solution with --include-auth --authority https://login.example.com --audience https://mcp.example.com and /mcp asks for a bearer token, and the server publishes protected resource metadata so MCP clients can find your authorization server and sign in by themselves. Leave --include-auth out and there's no authentication code in the solution at all, so there's nothing to leave switched off by accident. Securing the server has the details, including how to add it later.

What's inside

Three layers, loosely based on Clean Architecture. Fewer layers than an onion, more than a sandwich.

  • Presentation is the MCP server, stateless Streamable HTTP at /mcp. Its tools, resources and prompts send each request through Mediator, and Application errors become tool errors that tell the agent how to recover.
  • Application owns the rules. Commands and queries are validated by FluentValidation and mapped by Mapperly.
  • Infrastructure owns the data, with Entity Framework Core on SQLite. Everything in it is internal, so Presentation can wire it up but can't move in.

There's a little CQRS in how commands and queries are shaped, but reads and writes share one database underneath. CQRS-curious, not CQRS-committed.

And around the edges:

  • Tests use xUnit, Shouldly and NSubstitute, with coverage from Coverlet. Each test gets its own throwaway in-memory database, so no test can spoil another one's data.
  • Sample data comes from Bogus, and only when Database:SeedSampleData is on. A real deployment never starts with fake reviews.
  • Telemetry is OpenTelemetry all the way: a span for every request, tool call and use case, metrics from ASP.NET Core, the MCP SDK, EF Core and the .NET runtime, and Serilog logs that know which trace they belong to. It all leaves over OTLP when OTEL_EXPORTER_OTLP_ENDPOINT is set, so point it at whatever backend you like. Docker Compose runs an OpenTelemetry Collector that forwards it to the Aspire dashboard, the same shape you'd run in production. Health checks answer at /health/live and /health/ready.
  • Build rules live in Directory.Build.props. Code style and the recommended analyzers run on every build, warnings fail it, and package versions sit in one place with Central Package Management.
  • The container runs as a non-root user and has its own health check.
  • The pipeline builds, checks formatting, tests with a 95% coverage bar, makes sure the packed template still works, runs CodeQL, reviews new dependencies and their licences, starts the image to check it actually answers, and scans the container and Dockerfile with Trivy. Then it sums the lot up in one comment on your pull request, so you know exactly who to blame. Your copy, or a solution from dotnet new, gets the format check, build and tests with no accounts, tokens or secrets, so it goes green the moment you push it. The scans stay switched off outside our organisation until you want them, and Jacques can switch them on with you. Trust is earned.
  • Dependabot bundles the month's dependency updates into one pull request on the 15th.

The architecture page has the long version, with full credit to Jason Taylor's template and Uncle Bob for the ideas.

Releases

A new version lands on the 1st of each month, as long as something changed, with notes for every pull request in the GitHub release. No changes, no release. We're not here to pad the download stats. Each release also carries an SPDX bill of materials listing every package the server ships with, for anyone whose security team asks nicely (or not so nicely).

dotnet new update

The family

Template Presentation
Clean Minimal API ASP.NET Core Minimal APIs
Clean Model Context Protocol Model Context Protocol server, you are here
Clean GraphQL API GraphQL with Hot Chocolate
Clean Web API ASP.NET Core controllers
Clean Lambda Function AWS Lambda

Contributing

Bug reports, ideas and pull requests are all welcome, and typo fixes doubly so. Start with the contributing guide and the code of conduct. Security problems go through the security policy, not an issue.

Who built this

Built by Stephen Walsh in spare time, with strong coffee and a healthy disregard for pomp and ceremony. Say hello on GitHub, LinkedIn, Medium or at stphnwlsh.github.io.

If this template saves you some time, sponsoring the work keeps all five templates current and the coffee flowing, which is the real dependency here.

License

MIT. Take it, change it, ship it. Just don't blame us for what your agent does with it.

About

A dotnet new template for a Model Context Protocol server using the MCP C# SDK, built with a streamlined Clean Architecture on .NET 10.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages