mcptask

package
v1.148.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package mcptask is the platform's implementation of the MCP Tasks extension (io.modelcontextprotocol/tasks, protocol revision 2026-07-28; #2009).

A client that declares the extension on a tools/call may be answered with a task handle (resultType "task") instead of the tool's result, and follows the work with tasks/get and tasks/cancel. The SDK the platform is built on does not implement the extension, so this package carries it at the protocol level: the handle and the tasks/* answers are its own result types, the tasks/* methods are custom methods on the server, and the tool calls that become tasks are chosen by a receiving middleware.

A task is held by a Source, one per kind of work, addressed by the prefix of its id: a managed-script run is a task whose id is the run id, and a tool call executed apart from its request (an export) is a task kept in its own table. Nothing here stores a task; it routes each tasks/* request to the Source that owns the id and renders what the Source reports.

The extension's spec: https://github.com/modelcontextprotocol/ext-tasks/blob/main/specification/2026-07-28/tasks.md

Index

Constants

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

The extension's methods.

View Source
const (
	StatusWorking   = "working"
	StatusCompleted = "completed"
	StatusFailed    = "failed"
	StatusCancelled = "cancelled" //nolint:misspell // the extension's wire value
)

Task statuses.

View Source
const CodeMissingCapability = -32021

CodeMissingCapability is the JSON-RPC error a request that needs the extension is refused with when the client did not declare it.

View Source
const ExtensionID = "io.modelcontextprotocol/tasks"

ExtensionID is the extension's identifier, the key a client and the server declare it under.

Variables

View Source
var ErrNotDetached = errors.New("call not detached")

ErrNotDetached is what a Detacher answers for a call it declines to take on, one that is answered directly instead.

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

ErrNotFound is what a Source answers for an id it does not hold, and for an id the caller may not read: the two are one answer, so a task's existence is never revealed to anybody but whoever may follow it.

Functions

func Complete

func Complete(ctx context.Context, res mcp.Result, err error)

Complete hands the outcome of a task's work to the receiver installed on ctx, if any.

func Declared

func Declared(req mcp.Request) bool

Declared reports whether the request itself declares the extension in its per-request client capabilities. Only the request counts: the spec forbids answering with a task a request that did not declare it, whatever the session declared before.

func EncodeResult

func EncodeResult(res *mcp.CallToolResult) (json.RawMessage, error)

EncodeResult renders a tool result in the wire form a client reads, the form tasks/get inlines. Structured content still held as a Go value is encoded by the platform's response encoder first, as the result-type layer does for a result answered directly (#1832), so an empty list reads [] here too.

func IsTask

func IsTask(res mcp.Result) bool

IsTask reports whether a tools/call answer is a task handle rather than the tool's result.

func Middleware

func Middleware(cfg Config) mcp.Middleware

Middleware answers a tools/call that declares the extension with a task, for the tools Config names, and identifies the caller of every tasks/* request. A call that does not declare the extension, and every other tool, passes through untouched: such a client sees exactly what it saw before.

It sits inside authorization, the gates and the consent prompts, so a call that is refused, or that needs the person's answer first, is answered directly before any task exists, as the extension requires.

func Register

func Register(server *mcp.Server, sources *Sources) error

Register adds the extension's methods to server, answered from sources.

func WithCompletion

func WithCompletion(ctx context.Context, fn CompletionFunc) context.Context

WithCompletion installs fn as the receiver of the outcome of a call that is answered with a task. The audit layer installs one: a task's answer is a handle, and the row it writes is for what the call did, which for a call executed apart from its request is known only when that work ends.

Types

type AckResult

type AckResult struct {
	mcp.ResultBase
	ResultType string `json:"resultType"`
}

AckResult is the empty acknowledgement tasks/update and tasks/cancel answer with.

type Claim

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

Claim is how a tool that keeps its own durable record (run_script) turns a call into a task: it finds a Claim on its context when the client declared the extension, starts its work without waiting for it, and accepts the claim with the id of the record it created. A call whose tool never accepts, a refusal for instance, is answered with the tool's own result.

func Requested

func Requested(ctx context.Context) *Claim

Requested returns the Claim a call to become a task carries, or nil when the call is to be answered with its result.

func (*Claim) Accept

func (c *Claim) Accept(id string)

Accept names the task the call became. The id must already resolve through its Source: the extension forbids handing out a task a tasks/get cannot find.

type CompletionFunc

type CompletionFunc func(ctx context.Context, res mcp.Result, err error)

CompletionFunc receives the outcome of a tools/call that was answered with a task, once the work behind it ends. ctx carries the PlatformContext the work ran under.

type Config

type Config struct {
	// Tools names the tools whose calls become tasks, and how.
	Tools map[string]Mode
	// Sources resolves a Native tool's accepted id to its seed state.
	Sources *Sources
	// Detacher executes a Detached tool's calls. With none, those calls
	// are answered directly.
	Detacher Detacher
	// Resolve identifies the caller of a tasks/* request.
	Resolve Resolver
}

Config is what the middleware needs.

type CreateResult

type CreateResult struct {
	mcp.ResultBase
	ResultType string `json:"resultType"`
	// contains filtered or unexported fields
}

CreateResult is the answer to a tools/call that became a task: the task's seed state under resultType "task".

func NewCreateResult

func NewCreateResult(s *Snapshot) *CreateResult

NewCreateResult renders a task's seed state as the tools/call answer.

type Detacher

type Detacher interface {
	Start(ctx context.Context, toolName string, run func(ctx context.Context) (mcp.Result, error)) (*Snapshot, error)
}

Detacher executes a tool call apart from the request that asked for it. Start creates the task durably, starts run on a context that outlives the request, and returns the task's seed state; run is the rest of the tools/call chain.

type GetResult

type GetResult struct {
	mcp.ResultBase
	ResultType string `json:"resultType"`

	Result json.RawMessage `json:"result,omitempty"`
	Error  *jsonrpc.Error  `json:"error,omitempty"`
	// contains filtered or unexported fields
}

GetResult is the answer to tasks/get: the task with its outcome inlined once it has one.

type Mode

type Mode int

Mode is how a tool's call becomes a task.

const (
	// Native is a tool that keeps its own record of the work and accepts the
	// call's Claim with that record's id (run_script and its run).
	Native Mode = iota + 1
	// Detached is a call executed apart from its request by the Detacher,
	// which keeps the task (the exports).
	Detached
)

type Resolver

type Resolver func(ctx context.Context, req mcp.Request) context.Context

Resolver attaches the caller's PlatformContext to a tasks/* request, which passes none of the tools/call layers that would.

type Snapshot

type Snapshot struct {
	ID            string
	Status        string
	StatusMessage string
	CreatedAt     time.Time
	UpdatedAt     time.Time
	// TTL is how long after CreatedAt the task may be discarded; zero is
	// unlimited.
	TTL time.Duration
	// PollInterval is how often a client should ask again.
	PollInterval time.Duration
	// Result is the tool's result on a completed task, in its wire form
	// (EncodeResult).
	Result json.RawMessage
	// Error is the JSON-RPC error on a failed task.
	Error *jsonrpc.Error
}

Snapshot is a task's state as its Source reports it.

func (*Snapshot) Terminal

func (s *Snapshot) Terminal() bool

Terminal reports whether the task has ended.

type Source

type Source interface {
	// Prefix is the id prefix of the tasks this Source holds.
	Prefix() string
	// Get reports a task's state.
	Get(ctx context.Context, id string) (*Snapshot, error)
	// Cancel asks for the task to stop. It is cooperative: the task may
	// still end another way if it finished first.
	Cancel(ctx context.Context, id string) error
}

Source holds one kind of task. Both calls run with the caller's PlatformContext on ctx and apply the Source's own reading rule, answering ErrNotFound for a task the caller may not follow.

type Sources

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

Sources routes a task id to the Source that holds it.

func NewSources

func NewSources(sources ...Source) *Sources

NewSources builds the routing over sources; a nil Source is skipped.

func (*Sources) Add

func (s *Sources) Add(src Source)

Add registers one more Source; a nil Source is skipped.

func (*Sources) For

func (s *Sources) For(id string) Source

For returns the Source holding id, or nil.

Jump to

Keyboard shortcuts

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