|
| 1 | +# README Code Sample Validation |
| 2 | + |
| 3 | +This reference describes how to validate that C# code samples in README files compile against the current SDK. |
| 4 | + |
| 5 | +## Which READMEs to Validate |
| 6 | + |
| 7 | +Validate code samples from the **package README** files — these are shipped with NuGet packages and are the primary documentation users see: |
| 8 | + |
| 9 | +| README | Package | |
| 10 | +|--------|---------| |
| 11 | +| `README.md` (root) | ModelContextProtocol | |
| 12 | +| `src/ModelContextProtocol.Core/README.md` | ModelContextProtocol.Core | |
| 13 | +| `src/ModelContextProtocol.AspNetCore/README.md` | ModelContextProtocol.AspNetCore | |
| 14 | + |
| 15 | +Sample README files (`samples/*/README.md`) are excluded — the samples themselves are buildable projects and are validated by CI. |
| 16 | + |
| 17 | +## What to Extract |
| 18 | + |
| 19 | +Extract only fenced code blocks tagged as `csharp` (` ```csharp `). Skip blocks tagged as plain ` ``` ` (shell commands, install instructions) or any other language. |
| 20 | + |
| 21 | +### Handling Incomplete Snippets |
| 22 | + |
| 23 | +README samples are often **incomplete** — they use `...` for placeholder values, omit `using` directives, or show only a method body. The validation wrapper must account for this: |
| 24 | + |
| 25 | +- **Placeholder expressions** like `IChatClient chatClient = ...;` — replace `...` on the right-hand side of assignments with `null!` |
| 26 | +- **Missing usings** — the wrapper file supplies all common namespaces (see template below) |
| 27 | +- **Top-level statements** — wrap in an `async Task` method so `await` works |
| 28 | +- **Suppressed warnings** — disable CS1998 (async without await), CS8321 (unused local function), and similar non-substantive warnings |
| 29 | + |
| 30 | +### Snippets That Cannot Be Validated |
| 31 | + |
| 32 | +Some code blocks are illustrative fragments that cannot compile even with wrappers (e.g., partial class definitions shown in isolation, pseudo-code). If a snippet fails to compile after applying the standard fixups, examine the error: |
| 33 | + |
| 34 | +- **API mismatch** (missing member, wrong type, wrong signature) → this is a **real bug** in the README that must be reported and fixed |
| 35 | +- **Structural issue** (missing context, incomplete fragment) → exclude this specific snippet from validation with a comment explaining why |
| 36 | + |
| 37 | +## Test Project Approach |
| 38 | + |
| 39 | +Create a **temporary** test project that references the SDK projects, wraps each README's code samples in compilable methods, and builds. |
| 40 | + |
| 41 | +### Project File Template |
| 42 | + |
| 43 | +```xml |
| 44 | +<Project Sdk="Microsoft.NET.Sdk"> |
| 45 | + <PropertyGroup> |
| 46 | + <TargetFramework>net10.0</TargetFramework> |
| 47 | + <OutputType>Library</OutputType> |
| 48 | + <Nullable>enable</Nullable> |
| 49 | + <ImplicitUsings>enable</ImplicitUsings> |
| 50 | + <LangVersion>preview</LangVersion> |
| 51 | + <NoWarn>CS1998;CS8321;CS0168;CS0219;CS1591;CS8602</NoWarn> |
| 52 | + </PropertyGroup> |
| 53 | + <ItemGroup> |
| 54 | + <ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" /> |
| 55 | + <ProjectReference Include="..\..\src\ModelContextProtocol.AspNetCore\ModelContextProtocol.AspNetCore.csproj" /> |
| 56 | + </ItemGroup> |
| 57 | +</Project> |
| 58 | +``` |
| 59 | + |
| 60 | +Place the project at `tests/ReadmeSnippetValidation/ReadmeSnippetValidation.csproj`. |
| 61 | + |
| 62 | +### Source File Template |
| 63 | + |
| 64 | +Create one `.cs` file per README. Each file wraps the README's code blocks in static methods inside a class. Use this pattern: |
| 65 | + |
| 66 | +```csharp |
| 67 | +#pragma warning disable CS1998 |
| 68 | +#pragma warning disable CS8321 |
| 69 | + |
| 70 | +using Microsoft.AspNetCore.Builder; |
| 71 | +using Microsoft.Extensions.AI; |
| 72 | +using Microsoft.Extensions.DependencyInjection; |
| 73 | +using Microsoft.Extensions.Hosting; |
| 74 | +using Microsoft.Extensions.Logging; |
| 75 | +using ModelContextProtocol; |
| 76 | +using ModelContextProtocol.Client; |
| 77 | +using ModelContextProtocol.Protocol; |
| 78 | +using ModelContextProtocol.Server; |
| 79 | +using System.ComponentModel; |
| 80 | +using System.Text.Json; |
| 81 | + |
| 82 | +namespace ReadmeSnippetValidation; |
| 83 | + |
| 84 | +public static class RootReadmeSamples |
| 85 | +{ |
| 86 | + // Snippet 1: Client example |
| 87 | + public static async Task ClientExample() |
| 88 | + { |
| 89 | + // ... pasted snippet code ... |
| 90 | + } |
| 91 | + |
| 92 | + // Snippet 2: Server example |
| 93 | + public static async Task ServerExample() |
| 94 | + { |
| 95 | + // ... pasted snippet code ... |
| 96 | + } |
| 97 | + |
| 98 | + // Snippet with attributed types (tools, prompts) go as nested or sibling types |
| 99 | + [McpServerToolType] |
| 100 | + public static class EchoTool |
| 101 | + { |
| 102 | + [McpServerTool, Description("Echoes the message back to the client.")] |
| 103 | + public static string Echo(string message) => $"hello {message}"; |
| 104 | + } |
| 105 | +} |
| 106 | +``` |
| 107 | + |
| 108 | +### Build Commands |
| 109 | + |
| 110 | +```sh |
| 111 | +# Restore and build the validation project |
| 112 | +dotnet restore tests/ReadmeSnippetValidation/ReadmeSnippetValidation.csproj |
| 113 | +dotnet build tests/ReadmeSnippetValidation/ReadmeSnippetValidation.csproj |
| 114 | + |
| 115 | +### Cleanup |
| 116 | + |
| 117 | +After validation, **always delete** the `tests/ReadmeSnippetValidation/` directory. It must not be committed. |
| 118 | + |
| 119 | +## Reporting Results |
| 120 | + |
| 121 | +### All Snippets Compile |
| 122 | + |
| 123 | +Report success and move to the next step: |
| 124 | +> ✅ All README code samples compile successfully against the current SDK. |
| 125 | + |
| 126 | +### Compilation Failures |
| 127 | + |
| 128 | +For each failure: |
| 129 | +1. Identify the README file and which code block failed |
| 130 | +2. Show the compiler error |
| 131 | +3. Classify the error: |
| 132 | + - **API mismatch**: The README uses an API that doesn't exist or has a different signature. This indicates the README is outdated and needs updating. |
| 133 | + - **Structural**: The snippet is a fragment that can't be wrapped. Note it for exclusion. |
| 134 | +4. For API mismatches, investigate the correct current API and propose a fix |
| 135 | +5. Present all findings to the user for confirmation before making any README edits |
| 136 | + |
| 137 | +### Fixing Issues |
| 138 | + |
| 139 | +If the user approves fixes: |
| 140 | +1. Edit the README files directly with minimal, surgical changes |
| 141 | +2. Re-run the validation build to confirm fixes compile |
| 142 | +3. Ensure the overall solution still builds: `dotnet build` |
| 143 | +4. Include the README fixes in the same release or as a prerequisite PR — the user decides |
0 commit comments