All skills
github avatar

/dotnet-mcp-builder

@aa01464 official
by githubgithub/awesome-copilot40k stars
5,040

Build Model Context Protocol (MCP) servers in C#/.NET against the current ModelContextProtocol 2.x NuGet packages. Helps with cases the model gets wrong without guidance — stale versions (0.x preview or 1.x-era defaults), the v2 stateless-by-default HTTP flip, the 2026-07-28 spec deprecations (roots/sampling/logging), MCP Apps and Tasks extension packages, elicitation URL mode, per-session HTTP wiring, OAuth and reverse-proxy deploy specifics, and debugging MapMcp / STDIO / Streamable-HTTP errors. Also covers STDIO and Streamable HTTP transports (SSE is deprecated), tools, prompts, resources, completions, and a basic .NET MCP client. Trigger when the user says or implies any .NET MCP server work: ModelContextProtocol, McpServerTool, MapMcp, WithStdioServerTransport, "MCP server in C#", "MCP tool in dotnet", "expose this as MCP", or names a primitive (prompt/resource/elicitation/MCP App) in a .NET context. Skip for MCP work in other languages.

Use this Skill: https://skilld.dev/gh/github/awesome-copilot/dotnet-mcp-builder

This session only. Nothing lands on disk.

referencesprompt-primitive.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Prompts

Prompts are reusable, parameterised message templates that the user (not the LLM) typically picks from a list — think "slash commands" in a chat client. The server defines them; the host renders them as menus.

Anatomy of a prompt

using System.ComponentModel;
using Microsoft.Extensions.AI;
using ModelContextProtocol.Server;

[McpServerPromptType]
public class CodePrompts
{
    [McpServerPrompt, Description("Generates a code review prompt.")]
    public static IEnumerable<ChatMessage> CodeReview(
        [Description("The programming language")] string language,
        [Description("The code to review")] string code) =>
        [
            new(ChatRole.User,
                $"Please review the following {language} code:\n\n```{language}\n{code}\n```"),
            new(ChatRole.Assistant,
                "I'll review the code for correctness, style, and potential improvements.")
        ];
}

Register it:

.WithPrompts<CodePrompts>()
// or
.WithPromptsFromAssembly()

Return types

Return type Result
ChatMessage Single message.
IEnumerable<ChatMessage> Conversation seed.
PromptMessage / IEnumerable<PromptMessage> Lower-level — use when you need full control over content blocks (embedded resources, multiple typed blocks per message).
GetPromptResult Full control — set Messages and Description.

ChatMessage/ChatRole come from Microsoft.Extensions.AI. They're the high-level shape and what you should use 90% of the time. Drop down to PromptMessage/ContentBlock only when you need embedded resources or fine-grained content typing.

Arguments

Every parameter (after the special ones the SDK strips out — IMcpServer, CancellationToken, etc.) becomes a prompt argument visible to the user when they pick the prompt. Use [Description] on each to explain what the user should supply.

To mark an argument optional, give it a default value:

[McpServerPrompt, Description("…")]
public static ChatMessage Greeting(
    [Description("Their preferred greeting style")] string style = "casual")
    => new(ChatRole.User, $"Greet me in a {style} style.");

Image and file content

For prompts that include images:

[McpServerPrompt, Description("Asks the model to analyze an image.")]
public static IEnumerable<ChatMessage> AnalyzeImage(
    [Description("Instructions for the analysis")] string instructions)
{
    byte[] imageBytes = LoadSampleImage();
    return new[]
    {
        new ChatMessage(ChatRole.User, new AIContent[]
        {
            new TextContent($"Please analyze this image: {instructions}"),
            new DataContent(imageBytes, "image/png")
        })
    };
}

For embedded text resources (e.g. seeding the conversation with a document the user picked):

[McpServerPrompt, Description("Reviews a referenced document.")]
public static IEnumerable<PromptMessage> ReviewDocument(
    [Description("The document ID to review")] string documentId)
{
    string content = LoadDocument(documentId);
    return new[]
    {
        new PromptMessage
        {
            Role = Role.User,
            Content = new TextContentBlock { Text = "Please review the following document:" }
        },
        new PromptMessage
        {
            Role = Role.User,
            Content = new EmbeddedResourceBlock
            {
                Resource = new TextResourceContents
                {
                    Uri = $"docs://documents/{documentId}",
                    MimeType = "text/plain",
                    Text = content
                }
            }
        }
    };
}

Async prompts

Prompts can be async — useful when you need to look up data to build the messages:

[McpServerPrompt, Description("Drafts a release-notes prompt.")]
public static async Task<IEnumerable<ChatMessage>> ReleaseNotes(
    string repo,
    string fromTag,
    string toTag,
    IGitHubClient github,
    CancellationToken ct)
{
    var commits = await github.GetCommitsBetweenAsync(repo, fromTag, toTag, ct);
    var summary = string.Join("\n", commits.Select(c => $"- {c.Message}"));
    return new[]
    {
        new ChatMessage(ChatRole.User,
            $"Draft release notes for {repo} {fromTag}→{toTag} from these commits:\n{summary}")
    };
}

Notifying clients of prompt changes

await server.SendNotificationAsync(
    NotificationMethods.PromptListChangedNotification,
    new PromptListChangedNotificationParams(),
    cancellationToken);

When to use prompts vs. tools

  • Prompt: the user triggers it from a menu, supplying any required arguments. The output is messages, not data. Good for "/summarize", "/code-review", "/draft-email".
  • Tool: the LLM triggers it (often without explicit user action) to fetch or change data. Good for "get_weather", "create_issue".

If both apply (the user wants a slash command that triggers the same logic the LLM could call), expose both — the same DTO/service can back both.

Source: SKILL.md on GitHub

No alerts15d3 checks · Risk SAFE
  • Gen Agent Trust Hub15d

    The skill provides technical guidance and code references for building Model Context Protocol (MCP) servers and clients using the official C#/.NET SDK. It includes security best practices for resource access and follows standard development patterns.

  • Socket15d

    No alerts

  • Snyk15d

    Risk: LOW · No issues

Signed by skilld at aa01464. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 20 hours ago.

Activeupdated 2 months ago
  • MCP
  • dotnet
  • csharp
  • model-context-protocol
  • stdio
  • http
  • tools
  • prompts
  • resources
  • streaming

README badge

README badge for github/awesome-copilot/dotnet-mcp-builder

Builds Model Context Protocol servers in C# / .NET against the stable 1.x SDK, covering STDIO and HTTP transports, tools, prompts, resources, sampling, elicitation, MCP Apps, and debugging. Targets the specific pitfalls that cause breakage: stale preview package versions, stdout pollution in STDIO mode, stateless HTTP misconfiguration, and missing primitive registration in DI.

Generated from the current SKILL.md.

Does this skill work with preview versions of the ModelContextProtocol NuGet packages?
No. The skill targets stable 1.x packages only. Preview versions (0.3, 0.4) have breaking differences and won't compile against current samples. Always pin the latest 1.x release.
Can I use stateless HTTP transport with sampling, elicitation, or server-initiated notifications?
No. Stateless HTTP breaks those features at runtime because it cannot maintain bidirectional communication. Use stateful HTTP or STDIO if you need server-to-client capabilities.
What should I do if my STDIO server isn't working?
First check that nothing is writing to stdout — configure `LogToStandardErrorThreshold = LogLevel.Trace` and remove any `Console.WriteLine` calls, since stdout is the JSON-RPC channel. Also verify tools and prompts are registered with `.WithToolsFromAssembly()` or equivalent.
Does this skill cover building MCP servers in other languages like Python or TypeScript?
No. This skill is C#/.NET only. It skips MCP work in other languages.
Can I write a .NET program that consumes an MCP server instead of building one?
Yes. Load `references/client.md` for guidance on writing a basic .NET MCP client that calls an existing server.

Generated from the current SKILL.md. These answers refresh after source changes.