tasks

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package tasks implements the official MCP tasks extension io.modelcontextprotocol/tasks (draft): task-augmented tool execution with polling, input_required rendezvous and status notifications.

Server side: Install the extension, then register long-running tools with AddTool. Client side: declare the capability via client Options.Extensions, detect task creation with AsTask, and follow the task with Await.

Index

Constants

View Source
const (
	MethodGet    = "tasks/get"
	MethodUpdate = "tasks/update"
	MethodCancel = "tasks/cancel"

	// NotificationTasks is the subscriptions/listen notification method; its
	// params are a full DetailedTask.
	NotificationTasks = "notifications/tasks"

	// FilterTaskIDs is the subscriptions/listen filter field selecting task
	// status notifications.
	FilterTaskIDs = "taskIds"

	// ResultTypeTask marks a tools/call result that created a task.
	ResultTypeTask = "task"
)
View Source
const ID = "io.modelcontextprotocol/tasks"

ID is the extension identifier, declared in capabilities.extensions on both sides.

Variables

View Source
var ErrNotFound = errors.New("tasks: task not found")

ErrNotFound is returned by Store.Get for unknown (or expired) task IDs.

View Source
var RouteNames = map[string]string{
	MethodGet:    "taskId",
	MethodUpdate: "taskId",
	MethodCancel: "taskId",
}

RouteNames maps the extension's methods to the params key sent as the Mcp-Name routing header, as the draft requires over Streamable HTTP.

Functions

func AddTool

func AddTool[In any](t *Tasks, tool *protocol.Tool, handler HandlerFor[In])

AddTool registers a task-capable tool. Clients that declare the tasks capability on the request receive a CreateTaskResult immediately and follow the task via tasks/get; clients without it get the tool executed synchronously (or rejected, per Options.Reject).

func Cancel

func Cancel(ctx context.Context, c Caller, taskID string) error

Cancel requests cooperative cancellation.

func EnableClient

func EnableClient(opts *client.Options)

EnableClient configures opts to declare the tasks capability and emit the extension's routing headers. Call it before client.New:

opts := &client.Options{...}
tasks.EnableClient(opts)
c := client.New(transport, opts)

func Update

func Update(ctx context.Context, c Caller, taskID string, responses protocol.InputResponses) error

Update answers an input_required task.

Types

type Caller

type Caller interface {
	Call(ctx context.Context, method string, params, result any) error
}

Caller is the slice of *client.Client the task helpers need.

type CancelParams

type CancelParams struct {
	TaskID string `json:"taskId"`
}

type Capability

type Capability struct{}

Capability is the value to declare under client Options.Extensions[ID].

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context provides task facilities to a running handler.

func (*Context) Interactive

func (c *Context) Interactive() bool

Interactive reports whether the handler runs as a task and can use RequireInput.

func (*Context) RequireInput

func (c *Context) RequireInput(ctx context.Context, requests protocol.InputRequests) (protocol.InputResponses, error)

RequireInput parks the task in input_required and blocks until the client has answered every request via tasks/update (partial submissions merge; the task stays input_required with the remaining subset outstanding) or ctx ends. In synchronous fallback mode it fails immediately; tools that cannot proceed without input should be installed with Options.Reject.

func (*Context) TaskID

func (c *Context) TaskID() string

TaskID is empty in synchronous fallback mode.

type DetailedTask

type DetailedTask struct {
	Task
	// InputRequests is set while Status is input_required.
	InputRequests protocol.InputRequests `json:"inputRequests,omitempty"`
	// Result is the stored tool result (including resultType) once completed.
	Result json.RawMessage `json:"result,omitempty"`
	// Error is set once failed.
	Error *protocol.Error `json:"error,omitempty"`
}

DetailedTask adds the status-dependent fields. It is the tasks/get result (a plain complete result) and the notifications/tasks payload.

func Await

func Await(ctx context.Context, c Caller, task *Task, onInput OnInputFunc) (*DetailedTask, error)

Await polls the task until it reaches a terminal status, honoring the server's pollIntervalMs. When the task requires input and onInput is non-nil, Await answers via tasks/update and keeps waiting; with a nil onInput an input_required task is returned as-is.

func Get

func Get(ctx context.Context, c Caller, taskID string) (*DetailedTask, error)

Get fetches the current task snapshot.

func TaskEvent

func TaskEvent(ev client.Event) (*DetailedTask, bool)

TaskEvent decodes a notifications/tasks subscription event.

func (*DetailedTask) ResultType

func (*DetailedTask) ResultType() string

func (*DetailedTask) ToolResult

func (d *DetailedTask) ToolResult() (*protocol.CallToolResult, error)

ToolResult decodes a completed task's stored tools/call result.

type GetParams

type GetParams struct {
	TaskID string `json:"taskId"`
}

type HandlerFor

type HandlerFor[In any] func(ctx context.Context, tc *Context, in In) (*protocol.CallToolResult, error)

HandlerFor is a task-capable tool handler. ctx is the task's own lifetime (cancelled by tasks/cancel), not the creating request's. In synchronous fallback mode ctx is the original request context and tc is non-interactive.

type MemStore

type MemStore struct {
	// contains filtered or unexported fields
}

MemStore is the in-process Store. Tasks expire TTLMs after their last update; expired entries are evicted lazily.

func NewMemStore

func NewMemStore() *MemStore

func (*MemStore) Delete

func (s *MemStore) Delete(ctx context.Context, taskID string) error

func (*MemStore) Get

func (s *MemStore) Get(ctx context.Context, taskID string) (*DetailedTask, error)

func (*MemStore) Put

func (s *MemStore) Put(ctx context.Context, t *DetailedTask) error

type OnInputFunc

type OnInputFunc func(ctx context.Context, requests protocol.InputRequests) (protocol.InputResponses, error)

OnInputFunc answers a task's outstanding input requests during Await.

type Options

type Options struct {
	// PollIntervalMs is advertised on every task (default 500).
	PollIntervalMs int64
	// TTL is how long finished tasks stay retrievable (default 5 minutes).
	TTL time.Duration
	// Reject makes task tools fail with -32021 for clients that did not
	// declare the tasks capability on the request, instead of falling back to
	// synchronous execution.
	Reject bool
}

type Status

type Status string
const (
	StatusWorking       Status = "working"
	StatusInputRequired Status = "input_required"
	StatusCompleted     Status = "completed"
	StatusFailed        Status = "failed"
	StatusCancelled     Status = "cancelled"
)

func (Status) Terminal

func (s Status) Terminal() bool

Terminal reports whether the status is final; a terminal task never changes again.

type Store

type Store interface {
	// Put creates or replaces a task snapshot.
	Put(ctx context.Context, t *DetailedTask) error
	// Get returns a copy of the task, or ErrNotFound.
	Get(ctx context.Context, taskID string) (*DetailedTask, error)
	// Delete removes a task; deleting an unknown task is not an error.
	Delete(ctx context.Context, taskID string) error
}

Store persists task snapshots. Implementations must be safe for concurrent use. An external store makes task state visible across server instances; note that the input_required rendezvous (tasks/update waking a blocked handler) is in-memory, so multi-instance deployments need sticky routing for interactive tasks.

type Task

type Task struct {
	protocol.WithMeta
	TaskID        string `json:"taskId"`
	Status        Status `json:"status"`
	StatusMessage string `json:"statusMessage,omitempty"`
	CreatedAt     string `json:"createdAt"`
	LastUpdatedAt string `json:"lastUpdatedAt"`
	// TTLMs is how long the server retains the task; null means indefinitely.
	// The field is required on the wire.
	TTLMs          *int64 `json:"ttlMs"`
	PollIntervalMs int64  `json:"pollIntervalMs,omitempty"`
}

Task is the base task object. Returned from tools/call it is the CreateTaskResult (resultType "task").

func AsTask

func AsTask(err error) (*Task, bool)

AsTask inspects a CallTool error: when the server turned the call into a task (resultType "task"), it returns the CreateTaskResult.

func (*Task) ResultType

func (*Task) ResultType() string

type Tasks

type Tasks struct {
	// contains filtered or unexported fields
}

Tasks is the installed extension; AddTool registers task-capable tools against it.

func Install

func Install(s *server.Server, store Store, opts *Options) *Tasks

Install registers the tasks extension methods, capability and subscription filter on s. The server itself stays unaware of tasks; everything flows through the generic extension seam.

type UpdateParams

type UpdateParams struct {
	TaskID         string                  `json:"taskId"`
	InputResponses protocol.InputResponses `json:"inputResponses"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL