modelcontextprotocol / modelcontextprotocol/csharp-sdk

Add a stable server-side MCP Task execution extension point

Open
#1,820 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement P2 ready for work
Dominant language
C#
Stars
4.5k
Forks
814
Avg merge
9d 19h
Merged PRs (30d)
4

Description

Is your feature request related to a problem? Please describe.

WithTasks creates a durable task record through IMcpTaskStore, but executes the tool in a process-local Task.Run.

This prevents servers from delegating task execution to durable systems such as Temporal, Orleans, Hangfire, or an external queue. A durable IMcpTaskStore preserves task state, but it cannot control how execution is started.

Replacing the call-tool handler is not a suitable alternative because it relies on experimental alternate-result APIs and replaces parts of the standard MCP tool pipeline.

Describe the solution you'd like

Add a stable extension point that allows WithTasks to delegate execution after the task record has been created.

The extension point should provide:

  • The created task information, including task ID.
  • The matched tool request and request context.
  • Access to the normal tool invocation pipeline when local execution is desired.
  • Clear ownership of request-scoped services and disposal.
  • Defined ordering for authorization and request filters.
  • Cancellation information.

The existing process-local behavior should remain the default.

A custom executor should be able to submit the task to an external durable runtime without invoking the tool body in the MCP server process. Existing tasks/get, tasks/update, and tasks/cancel handling should continue to use IMcpTaskStore.

The exact interface is open for discussion. Conceptually:

public interface IMcpTaskExecutor
{
    ValueTask StartAsync(
        McpTaskExecutionContext context,
        CancellationToken cancellationToken);
}

Describe alternatives you've considered

  • Custom IMcpTaskStore: persists state but cannot replace the process-local execution mechanism.
  • Custom CallToolWithAlternateHandler: uses experimental APIs and replaces the normal tool pipeline.
  • Forking or reimplementing WithTasks: duplicates task negotiation, filtering, DI-scope, cancellation, and result-handling behavior.
  • Keeping execution process-local: unsuitable for tasks that must survive server process replacement.

Additional context

The extension point should preserve existing behavior for applications that do not configure a custom executor.

A useful acceptance scenario would be:

  1. An MCP task is created.
  2. A custom executor submits it to an external durable runtime.
  3. The original MCP server process exits.
  4. Another server instance continues serving tasks/get, tasks/update, and tasks/cancel.
  5. The task reaches a terminal state without depending on the original process.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing WithTasks, IMcpTaskStore, and the existing tasks/get, tasks/update, and tasks/cancel handlers to understand task creation and local execution. Define the executor context and lifecycle around the stated requirements, including authorization, filters, request-scoped disposal, cancellation, and access to normal tool invocation. Done means the default remains process-local and a custom executor can hand work to a durable runtime that survives the original server process.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.