It's included as internal on netstandard/net472, and the C# compiler may bake a reference to that into a consumer. If that consumer is then used with a net8.0+ build, the IsExternalInit needs to be there and forwarded to the real one.
This switches our polyfill files to always be included but the actual contents ifdef'd out on TFMs that already have the contents. That then makes it easier to do specialized ifdef'ing in the future, as this does for IsExternalInit.
* Update content according to latest spec
* Add Title to a bunch of types
* Add _meta to lots of types
* Address feedback, more cleanup, fix NAOT test failure
* Improve exception diagnostics for stdio client
Track the last several lines of stderr and include those in an exception created as part of CleanupAsync if the server process has already exited. This is based on an assumption that the server should never exit prior to CleanupAsync being called.
* Address feedback and fix test failure
* Add McpServer/ClientResource{Template} and friends
This PR copies the same design used by tools and prompts to add McpServerResource, McpServerResourceAttribute, McpServerResourceTypeAttribute, McpClientResource, and then all of those for ResourceTemplate as well.
Unlike the others, [McpServerResource] is permitted not only on methods but also on properties. This convenience is afforded because such resources aren't parameterized, and thus can be easily modeled as properties, likely auto-props, e.g.
```C#
[McpServerResource]
public static BlobResourceContents MyAmazingData { get; } = Create();
```
Details about resources can be encoded into the attributes or provided via McpServerResource{Template}.Create methods. If not URI is explicitly defined, one is derived from the member name and arguments. For templates, this means manufacturing a URI template that includes variables for all non-DI parameters.
This also fixes a few issues discovered along the way:
- McpClientExtensions are updated to use `ValueTask<T>` instead of `Task<T>` where relevant.
- McpServerPrompt was missing handling for progress notifications; that's been rectified. It was also missing configuring the description on the ProtocolPrompt.
- Renamed IMcpServerPrimitive.Name to Id. For resources, names aren't unique.
- After going back and forth, updated McpServer to not fail for missing handlers and to instead register default handlers. It simplifies the implementation and makes it more consistent.
- Added a bunch of primitive types into the McpJsonUtilities JSON source generator context so that such primitives are usable with tools/prompts/resources without folks being required to add them into their own context for Native AOT. I think we should consider pushing this down to AIJsonUtilities, instead, and that will then flow up to McpJsonUtilities automatically.
* Address feedback
* AI generated `///` comment updates
* Fix compilation issues
* Fix incorrect XML comment structure
* Update all Client comments
* Update all Configuration comments
* Update all Messages comments
* Update all Transport comments
* Update all Types comments
* Update all Server comments
* Undo some commenting
---------
Co-authored-by: Stephen Toub <stoub@microsoft.com>
* Separate ASP.NET Core tests into a distinct project and make the main test project netfx compatible.
* Fix merge conflicts.
* Update tests/ModelContextProtocol.Tests/ModelContextProtocol.Tests.csproj
Co-authored-by: Stephen Halter <halter73@gmail.com>
* Revert "Fix merge conflicts."
This reverts commit 852169b96786bad2144795540fa164e20b4b197e.
* Fix merge conflicts
---------
Co-authored-by: Stephen Halter <halter73@gmail.com>
* Remove McpServerConfig and have McpClientFactory accept IClientTransport instances directly.
* Address feedback and use lists when representing stdio arguments.
* Use "Name" for transport descriptors and "EndpointName" for MCP clients and servers.
* Update code samples.
* Fix source file naming
* Reduce dependencies to 8.x versions of packages
When building for netstandard2.0 or net8.0, the ModelContextProtocol library now only depends on 8.x versions of nuget packages, rather than using the newer 9.x versions. The exception to this are packages that don't have 8.x versions.
This also introduces a net9.0 tfm. When building for net9.0, it'll use 9.x versions of packages.
The PR temporarily removes the Microsoft.Extensions.AI.nupkg reference (the Microsoft.Extensions.AI.Abstractions reference is still very much there). The latest Microsoft.Extensions.AI package on nuget has a System.Text.Json 9.x reference, but the next build to be published drops that down to 8.x as well. Once that build is published, the dependency will be added back, and temporary polyfills (in particular TemporaryAIFunctionFactory) will be deleted.
* Fix StdioClientSessionTransport shutdown
StreamClientSessionTransport's ReadMessageAsync method does await CleanupAsync in its finally. CleanupAsync awaits _readTask. _readTask _is_ ReadMessageAsync. So it's waiting for itself to complete, which will then always timeout. We may want to refactor how this works more in the future, but for now, make sure it doesn't wait for itself.
* Fix dangling requests when server unexpectedly shuts down
If the client makes a request to the server and while waiting for the response the server shuts down, the client hangs. Make sure that when the client's message loops ends due to the server's output it's reading from ends, any pending requests are notified.
* Add net9.0 testing
* Avoid docker port conflicts from test suites running concurrently
* Overhaul tool handling
- Renames [McpTool{Type}] to [McpServerTool{Type}], in order to distinguish representations of tools on the server from tools on the client.
- Enables [McpServerTool] methods to have arguments injected from DI, as well as a specific set of types from the implementation directly, like IMcpServer.
- Renames WithTools to WithToolsFromAssembly.
- All of the WithToolsXx methods now publish each individual McpServerTool into DI; other code can do so as well. The options setup code gathers all of the tools from DI and combines them into a collection which is then stored in McpServerOptions and used to construct the server.
- The server tools specified via DI as well as manually-provided handlers, using CallToolHandler as a fallback in case the requested tool doesn't exist in the tools collection, and ListToolsHandler augments the information for whatever tools exist.
- The tools are stored in McpServerOptions in a new McpServerToolCollection type, which is a thread-safe container that exposes add/removal notification. Adding/removing tools triggers a change notification that in turn sends a notification to the client about a tools update.
- The ServerOptions are exposed from the server instance.
- Removed cursor-based APIs from McpClientExtensions.
- Changed McpClientExtensions APIs to return `Task<IList<...>` rather than `IAsyncEnumerable<...>`.
I'm sure this will need to evolve further before we're "done", but it's a significant improvement from where we are now. One area I'm not super happy with is the notifying collection; that might work ok for a stdio server, where you can grab the created collection from the server's options and mutate it, but I don't know how well that's going to work for sse servers.
* Make McpServerTool{Collection} extensible
* Fix README.md example
* Add notifications test
* Address feedback
Handlers are now specified before connecting the client/server. Otherwise, race conditions exist. Handlers move into being a part of the McpClientOptions/McpServerOptions, so that they're provided to the factories. Where relevant, the handlers are specified as part of the capability descriptors, so that they go hand in hand.
The factories are no longer stateful. Instead of allocating a factory and then calling a create method on it, you just call a static factory method.