Skip to main content

Context & State

Context

Context is an optional first argument of a handler function. It provides request metadata and response control.

Reading metadata

export function myMethod(ctx: Context, input: string): string {
const rid = ctx.requestId;
const tid = ctx.traceId;
const sid = ctx.sessionId;
const me = ctx.skillId;
const who = ctx.callerId;
const mtd = ctx.method;
// ...
}

LLM context

When a skill is invoked as an MCP tool, the host returns the result to the LLM. LLM context lets you prepend additional instructions or hints that the LLM sees before the tool output. The final response the LLM receives looks like:

<llm context lines>
---
<tool result>

This is useful for guiding the LLM's interpretation of the result — for example, warning about binary content, suggesting next steps, or adding formatting hints.

  • setLLMContext(text) — sets the LLM context (replaces any previous value).
  • appendLLMContext(text) — appends a line to the existing LLM context. Call multiple times to build up multi-line context.
ctx.setLLMContext("Warning: file contains binary data");
ctx.appendLLMContext("Tip: use --format json");

Persistent state (Go, Rust)

Each skill can store state between invocations. State is passed in the request and returned in the response.

note

State helpers are currently available in Go and Rust SDKs only.

Save and load

type MyState struct {
Counter int `msgpack:"counter"`
LastInput string `msgpack:"last_input"`
}

func Process(ctx *sdk.Context, input string) (string, error) {
var state MyState
version, _ := sdk.UnmarshalState(ctx.Request().State, &state)

state.Counter++
state.LastInput = input

stateBytes, _ := sdk.MarshalState(1, state)
resp := ctx.Response()
resp.State = stateBytes

return fmt.Sprintf("Call #%d", state.Counter), nil
}

State versioning

When the state structure changes, use the version number for migration:

var state MyState
version, _ := sdk.UnmarshalState(req.State, &state)

switch version {
case 0:
// First run, no state
case 1:
// Old version — migrate
state.NewField = "default"
case 2:
// Current version
}

stateBytes, _ := sdk.MarshalState(2, state)

Notes

  • State is stored on the host side and persists across restarts
  • State size is limited (recommended up to 1 MB)
  • Empty state is normal for the first invocation
  • Each skill can only access its own state