Extract Tasks into ModelContextProtocol.Extensions.Tasks (raw seams)#27
Open
jeffhandley wants to merge 3 commits into
Open
Extract Tasks into ModelContextProtocol.Extensions.Tasks (raw seams)#27jeffhandley wants to merge 3 commits into
jeffhandley wants to merge 3 commits into
Conversation
- Add IMcpServerRawHandlerRegistry seam (McpRawRequestHandler delegate, registry over request handlers, IsDraftProtocolRequest) and McpServerOptions.RawRequestHandlerConfigurators - Add McpServer.CurrentOutgoingRequestInterceptor AsyncLocal seam and McpOutgoingRequestInterceptor delegate; route SampleAsync/ElicitAsync/RequestRootsAsync through it - Make McpSession.IsDraftProtocol public and McpClient.ResolveInputRequestsAsync public abstract (MCPEXP002) - Remove Tasks coupling from Core: ConfigureTasks, task-store tools/call wrapper, SetTaskAugmented, CallToolWithTaskHandler/Filters, task lifecycle handlers, MaxConsecutiveStuckPolls, task method/notification/meta consts, task JsonSerializable entries - Rewrite client CallToolAsync to a plain tools/call returning CallToolResult - Relocate Tasks DTOs and store types into ModelContextProtocol.Extensions.Tasks; drop McpTaskExecutionContext - Add ModelContextProtocol.Extensions.Tasks project and TasksJsonContext Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add TaskMethods/TaskMetaKeys consts (tasks/get|update|cancel, notification, related-task) - Add McpServerTasksExtensions: WithTasks(McpServerOptions/IMcpServerBuilder), SendTaskStatusNotificationAsync, store-backed tasks/* raw handlers gated to draft, and a tools/call wrapper that runs tasks in the background via the outgoing-request interceptor seam - Add McpClientTasksExtensions: CallToolAsTaskAsync, CallToolRawAsync, GetTaskAsync/UpdateTaskAsync/CancelTaskAsync, PollTaskToCompletionAsync - Add JsonNode to TasksJsonContext; replace internal Throw with inline null checks in ResultOrCreatedTask - Include only the attribute polyfills the Tasks DTOs need (required/init) on netstandard2.0 - Relax Result/RequestParams/NotificationParams base ctors to protected so the moved DTOs can derive across the assembly boundary - Register the new project in ModelContextProtocol.slnx Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add ProjectReference from tests and sample to ModelContextProtocol.Extensions.Tasks - Migrate task tests to public extension API (WithTasks, CallToolAsTaskAsync, GetTaskAsync, UpdateTaskAsync, CancelTaskAsync, CallToolRawAsync) - Rename const references to TaskMethods.Get/Update/Cancel/StatusNotification - Rewrite McpServerTaskTests and TaskPollStuckDetectorTests to use the store-based public API with custom IMcpTaskStore doubles - Drop manual CallToolWithTaskHandler tests (TaskStoreOrphanedTaskTests, TaskHandlerConfigurationValidationTests) that exercised configuration paths removed from Core - Add public McpTasksJsonUtilities.DefaultOptions so the public task DTOs can be serialized under source generation when reflection is disabled - Point task DTO serialization in tests at McpTasksJsonUtilities.DefaultOptions instead of the Core McpJsonUtilities.DefaultOptions - Send and read tasks/update inputResponses explicitly in the extension because RequestParams serializes them through an internal backing property the extension context cannot access - Update samples/TasksExtension to the WithTasks plus CallToolAsTaskAsync API Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extracts the SEP-2663 Tasks feature out of
ModelContextProtocol.Coreinto a newbolt-on package,
ModelContextProtocol.Extensions.Tasks, mirroring the existingModelContextProtocol.Extensions.Apps. After this change Core has no compile-timeknowledge of Tasks; the extension references the main package and adds Tasks behavior
entirely from the side.
Unlike Apps -- which was pure additive metadata over existing public APIs -- Tasks was
woven into Core's request-dispatch pipeline (task-augmented
tools/call, AsyncLocalredirection of
sampling/elicitation/roots, and transparent client polling). To makea clean side bolt-on possible, Core gains a small set of minimal "raw" extensibility
hooks (delegate/registry seams, no Tasks-specific surface, no
InternalsVisibleTo).New public Core API surface (the seams)
What moves to the extension
All Tasks-specific types and machinery move to
ModelContextProtocol.Extensions.Tasks:CreateTaskResult,GetTaskRequestParams/Result,UpdateTaskRequestParams/Result,CancelTaskRequestParams/Result,TaskStatusNotificationParams,McpTaskStatus,ResultOrCreatedTask.IMcpTaskStore,InMemoryMcpTaskStore,McpTaskExecutionContext,McpTaskInfo,InputResponseReceivedEventArgs.tools/callwrapper, thesampling/elicitation/rootsredirection, and the client transparent-polling loop -- re-expressed on top of the
raw Core seams above.
tasks/*request methods,notifications/tasks/status, thetaskresultdiscriminator, the
RelatedTaskmeta key, and thetasksextension capabilitystring -- all owned by the extension.
[JsonSerializable]registrations move to the extension's JSON context.Public entry points become extension methods, mirroring Apps:
builder.WithTasks(...)for servers andclient.GetTaskAsync(...)/CancelTaskAsync/UpdateTaskAsyncfor clients.Design rationale (raw seams)
lets the extension own all typing and shape, so Core carries the least Tasks-shaped
baggage.
TryWrapHandlerlets the extension layer taskaugmentation over Core's existing
tools/callhandler without Core knowing why.InternalsVisibleTo. The extension depends only on public Core API, like Apps.Trade-offs vs the typed-seams alternative
AsyncLocal(
McpServer.CurrentOutgoingRequestInterceptor) for redirection rather than a scopedIDisposable; simpler wiring but ambient lifetime.JsonRpcRequest/JsonRpcResponse) rather than generic typedprimitives, so less reusable outside Tasks and less AOT-shaped.
(
TaskStoreOrphanedTaskTests,TaskHandlerConfigurationValidationTests) whosescenarios no longer map onto the raw-seam wiring.
Breaking changes
This is a preview SDK and the change is intentionally breaking:
ModelContextProtocol(.Core)into the newModelContextProtocol.Extensions.Taskspackage; consumers add a package referenceand a
using.TaskStorewiring and client task operations are now extension methods.ExperimentalAttributefrom official Extensions/Tasks/MRTR APIs and alignMCPEXP001usage modelcontextprotocol/csharp-sdk#1642, the moved Tasks APIs are non-experimental (no[Experimental]).Validation
dotnet buildclean (0/0) across net10.0/net9.0/net8.0/netstandard2.0 withTreatWarningsAsErrors=true.