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
- Variables
- func Complete(ctx context.Context, res mcp.Result, err error)
- func Declared(req mcp.Request) bool
- func EncodeResult(res *mcp.CallToolResult) (json.RawMessage, error)
- func IsTask(res mcp.Result) bool
- func Middleware(cfg Config) mcp.Middleware
- func Register(server *mcp.Server, sources *Sources) error
- func WithCompletion(ctx context.Context, fn CompletionFunc) context.Context
- type AckResult
- type Claim
- type CompletionFunc
- type Config
- type CreateResult
- type Detacher
- type GetResult
- type Mode
- type Resolver
- type Snapshot
- type Source
- type Sources
Constants ¶
const ( MethodGet = "tasks/get" MethodUpdate = "tasks/update" MethodCancel = "tasks/cancel" )
The extension's methods.
const ( StatusWorking = "working" StatusCompleted = "completed" StatusFailed = "failed" StatusCancelled = "cancelled" //nolint:misspell // the extension's wire value )
Task statuses.
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.
const ExtensionID = "io.modelcontextprotocol/tasks"
ExtensionID is the extension's identifier, the key a client and the server declare it under.
Variables ¶
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.
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 ¶
Complete hands the outcome of a task's work to the receiver installed on ctx, if any.
func Declared ¶
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 ¶
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 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.
type CompletionFunc ¶
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 Resolver ¶
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.
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.