GitShow/modelcontextprotocol/csharp-sdk
modelcontextprotocol

csharp-sdk

The official C# SDK for Model Context Protocol servers and clients. Maintained in collaboration with Microsoft.

by modelcontextprotocol
csharpdotnetmcpmcp-clientmcp-servermodelcontextprotocol
Star on GitHubForkWebsite

C#

4.4k stars733 forks77 contributorsActive · 5h agoSince 2025v1.4.0

Meet the team

See all 77 on GitHub →
CopilotBot
Copilot150 contributions
stephentoub
stephentoub121 contributions
dependabot[bot]Bot
dependabot[bot]84 contributions
halter73
halter7383 contributions
jeffhandley
jeffhandley54 contributions
eiriktsarpalis
eiriktsarpalis50 contributions
PederHP
PederHP40 contributions
mikekistler
mikekistler19 contributions

Languages

View on GitHub →
C#100%
Makefile0%

Commit activity

Last 12 weeks · 64 commits

Full graph →

Community health

5 of 6 standards met

Community profile →
87
✓README✓License✓Contributing✓Code of Conduct○Issue Template✓PR Template

Recent PRs & issues

Active · Last activity 5h ago
See all on GitHub →
Copilot
Add DeferChanges() to McpServerPrimitiveCollection for batched change notificationsOpenPR

Fixes #1688 Registering a batch of N tools/prompts/resources emits N wire notifications -- one per -- instead of one. This can trip clients that debounce or rate-limit notifications, and is wasteful for progressive-disclosure patterns. Changes on -- returns an scope that suppresses events. A single notification fires when the outermost scope disposes, only if at least one mutation occurred. Nesting is supported via a depth counter. Thread-safe implementation -- and are coordinated with /; defers when depth > 0, and the dispose is idempotent via . Unit tests** covering: no-mutation scope, single/multiple mutations, mixed add+remove, , nested scopes, idempotent dispose, no-handler, and baseline non-deferred behavior. Usage Purely additive -- no behavior change for callers that never call . Applies uniformly to tool, prompt, and resource collections.

Copilot · 4h ago
tarekgh
Echo request id in post-parse Streamable HTTP error responsesOpenPR

Summary On the Streamable HTTP transport, several JSON-RPC error responses were emitted with even after the request body had been successfully parsed and its id was readable. This violates the base protocol responses rule (error responses MUST include the same id as the request they correspond to, except when the id could not be read due to a malformed request) and SEP-2243's error response format for header validation failures, which echoes the request id. Fix Thread the parsed request id through every post-parse error site on the POST path in : Header validation failure ( HeaderMismatch) - the reported case 2026-07-28 rejection (SEP-2567) Unsupported protocol version fallback (SEP-2575) New-session-only-via-initialize rejection Stateless-mode session-id rejection Session not found () and forbidden cases Pre-parse failures (protocol version and accept header checks) and malformed requests (invalid JSON, explicit ) still return , which is correct per the base protocol. Tests Strengthened the header/body mismatch conformance test and added a missing test to assert the echoed id. Strengthened the session-not-found and new-session-required tests, and added a stateless session-id test, to assert the echoed id. Kept the existing null-id guards for malformed and explicit-null-id requests. All pass on net8.0, net9.0, and net10.0. Fixes #1677

tarekgh · 5h ago
jeffhandley
Add batched change notifications to McpServerPrimitiveCollection<T>OpenIssue

Background — the scenario that motivated this While building nesm, a WebAssembly runtime that exposes itself as an MCP server, the server adopted progressive disclosure: it starts with ~12 entry tools and dynamically registers additional tool groups (Core, Memory, Component, Dwarf, Debug, …) as the client loads modules or opens debug sessions. Registering a group means adding a batch of ~2-16 tools to in a single logical operation. We hit a rough edge in the SDK: raises its event — and therefore the SDK emits one wire message — after every individual /. A single "load module" operation that registers 16 tools produces 16 notifications instead of one. This is wasteful (16× the notification traffic per operation), and it is a plausible way to trip MCP clients that debounce or rate-limit — the client may coalesce the burst and drop all but the first, or throttle and miss the settled state. We debugged a client-side "additions not surfaced" symptom and, while the root cause turned out to be client-side, the notification storm was a real contributing hazard we wanted to eliminate on the server side. The workaround, and why the SDK should own this We fixed it in nesm (Blazor-Playground/nesm#61) with a that exposes returning an ; mutations inside the scope defer the event and fire exactly one on dispose. Making that subclass correct was harder than it should be, because the collection is only partially overridable: , , , , , , , , are virtual. , , and the indexer are non-virtual and read the base type's private field. is , but there is no supported way to suspend it around a batch. Because we can't intercept the non-virtual members, our subclass has to bring its own backing store and override every virtual member so the base's private store is never consulted — yet a caller holding a base-typed reference still sees / empty indexer. That's a latent correctness trap for a workaround whose only goal is "send one notification instead of N." This is a common pattern (progressive disclosure / bulk registration), and every server that does it will need the same workaround. It belongs in the SDK. Proposed API Add a first-class batching primitive to that coalesces mutations into a single : (Alternate names for API review: , . deliberately echoes WPF's , see Prior art.) Semantics: Reentrant / nestable via a suppression depth; the coalesced fires only when the outermost scope disposes, and only if ≥1 mutation actually occurred. No change fires if the scope is empty or no mutation occurred. Thread-safe suspend/resume. Example (what the nesm registrar would become): Alternatives considered / bulk-mutation methods.* We considered range APIs that fire one per call. Rejected: a range method only coalesces a single kind of mutation. Progressive disclosure frequently does adds and removes in one logical operation (e.g. swapping a module's feature set), and a range method leaves that gap — you'd be back to ≥2 notifications, or forced into a . A deferral scope coalesces any mix of // into one notification. This mirrors why deliberately has no — can't express arbitrary batched mutations and consumers fall back to (see dotnet/runtime#585). A suspend flag (à la ). Rejected: no auto-restore (leaks the suspended state if an exception skips the reset), not nestable, and forces a manual "fire the coalesced event" call afterward. An scope is exception-safe and composes. Prior art in .NET The exact shape we want — an scope that suspends change notifications and fires one on dispose — is already proven in the framework by WPF's , which returns an that holds off /refresh until the block exits. That's the clean, ergonomic model this proposal follows (and the reason is the suggested name). Within the two halves of that idea are well-established, just never combined into one primitive: scope with a nesting counter — (), depth-counted via . (Used there for reentrancy guarding rather than batching, but it's the same scope mechanism.) Suspend-notifications-during-bulk-mutation — + (); (), which suspends notifications during bulk load; and the standardized () deferral pattern. Notably, where a framework shipped only a toggle, consumers repeatedly reinvent the disposable wrapper: EF Core exposes just , and the community routinely hand-rolls an around it. Shipping the scope in the SDK avoids that recurring boilerplate — which is exactly the situation above. Secondary ask (optional) If lands, servers no longer need to subclass just to batch. But to make subclassing safe in general*, consider either making // virtual, or documenting that a subclass overriding the storage members must also shadow these three. The batching API is the priority; this is a note for API review. Compatibility Purely additive; no behavior change for existing callers who never call . Applies uniformly to tools, prompts, and resources since they share . References nesm workaround: and PR Blazor-Playground/nesm#61 Prior art: WPF ; , , , (all ); range-notification rejection dotnet/runtime#585. Observed against 1.4.0. CC @lewing

jeffhandley · 6h ago

Recent fixes

View closed PRs →
eiriktsarpalis
Fully stabilize now-stable protocol propertiesMergedPR

#1301 hid experimental JSON properties from consumer source generators using an internal twin pattern (public + internal ). #1642 later removed from , , , and but left that plumbing in place — so consumer-defined s still silently dropped these now-stable properties. This removes the twins and converts the four properties to plain public auto-properties. Wire format is unchanged; consumer source-gen contexts now round-trip them correctly. is deleted because it asserted the #1301 drop-by-consumer-context behavior, which no longer applies.

eiriktsarpalis · 13h ago
Structured data for AI agents

Repository: modelcontextprotocol/csharp-sdk. Description: The official C# SDK for Model Context Protocol servers and clients. Maintained in collaboration with Microsoft. Stars: 4369, Forks: 733. Primary language: C#. Languages: C# (100%), Makefile (0%). Homepage: https://csharp.sdk.modelcontextprotocol.io/ Topics: csharp, dotnet, mcp, mcp-client, mcp-server, modelcontextprotocol. Latest release: v1.4.0 (3w ago). Open PRs: 48, open issues: 137. Last activity: 5h ago. Community health: 87%. Top contributors: Copilot, stephentoub, dependabot[bot], halter73, jeffhandley, eiriktsarpalis, PederHP, mikekistler, MackinnonBuck, aaronpowell and others.

·@ofershap

Replace github.com with gitshow.dev