MCP Server | Tasks

The tasks extension (io.modelcontextprotocol/tasks) of the MCP protocol version 2026-07-28 lets a server run a long tools/call in the background. Instead of waiting for the result, the server answers immediately with a task handle (resultType task) and the client polls it with tasks/get, sends requested input with tasks/update or cancels it with tasks/cancel. The server handles the three tasks/* methods automatically.

 

Configuration

 

A task is only created when the client declared the tasks extension in the _meta of that request. Use the TaskSupport property of the tool to control it: aimcptsForbidden never creates a task, aimcptsOptional creates it when the client supports it, and aimcptsRequired rejects clients without the extension with error -32021.

 

Creating a task

Inside OnMCPRequestTool, call CreateTask(aSession, aResponse). If it returns a task object, the response is converted into a task handle: start the work in a background thread and exit the handler. If it returns nil (tasks disabled, legacy client, extension not declared, tool forbids tasks or MaxTasks reached), run the tool synchronously as usual.


procedure TMainForm.MCPServerMCPRequestTool(Sender: TObject;
  const aSession: TsgcAI_MCP_Session; const aRequest: TsgcAI_MCP_Request_ToolsCall;
  const aResponse: TsgcAI_MCP_Response_ToolsCall);
var
  oTask: TsgcAI_MCP_Task;
begin
  oTask := MCPServer.CreateTask(aSession, aResponse);
  if Assigned(oTask) then
  begin
    TThread.CreateAnonymousThread(
      procedure
      var
        i: Integer;
      begin
        for i := 1 to 10 do
        begin
          if oTask.IsCancelled then
            exit;
          oTask.SetStatusMessage(Format('Processing %d of 10', [i]));
          Sleep(1000);
        end;
        oTask.Complete('{"content":[{"type":"text","text":"Report ready"}]}');
      end).Start;
  end
  else
    aResponse.Result.Content.AddText('Report ready');
end;

 

TsgcAI_MCP_Task

The task object is owned by the server and is thread safe, do not free it. Its methods return False when the task is already in a terminal state (completed, failed or cancelled) or has expired.

 

Task events

 

Both events are published, assign them in the Object Inspector or in code.


procedure TMainForm.FormCreate(Sender: TObject);
begin
  MCPServer.MCPOptions.Tasks.Enabled := True;
  MCPServer.OnMCPTaskCancel := OnMCPTaskCancelEvent;
  MCPServer.OnMCPTaskUpdate := OnMCPTaskUpdateEvent;
end;

procedure TMainForm.OnMCPTaskCancelEvent(Sender: TObject; const aTask: TsgcAI_MCP_Task);
begin
  Log('task cancelled: ' + aTask.TaskId);
end;

procedure TMainForm.OnMCPTaskUpdateEvent(Sender: TObject; const aTask: TsgcAI_MCP_Task;
  const aInputResponses: string);
begin
  Log('task ' + aTask.TaskId + ' input: ' + aInputResponses);
end;

 

The read only property TasksCount returns the number of tasks stored by the server, working or finished; expired tasks are purged before counting.

MemoLog.Lines.Add('stored tasks: ' + IntToStr(MCPServer.TasksCount));

 

Tasks are bound to the principal returned by DoGetRequestPrincipal, so a client can only read, update or cancel its own tasks. An unknown task returns error -32602 "Task not found" and an expired one "Failed to retrieve task: Task has expired".