Documentation
¶
Overview ¶
Package budget provides MCP response budget enforcement utilities.
MCP tool servers commonly need to keep list-style responses within a model-context-friendly token budget. This package wraps results in an Envelope with pagination and truncation metadata, and provides small helpers for extracting paging arguments from untyped MCP parameter maps and rendering MCP tool-response JSON.
The defaults target ~2000 tokens (~8000 bytes of serialized JSON), a reasonable starting point for tool responses consumed inline by an LLM. Callers override the limits via Config.
The package is dependency-free (stdlib only).
Index ¶
- Constants
- func Clamp(v, min, max int) int
- func EstimateTokens(payload []byte) int
- func EstimateTokensFromString(s string) int
- func ExtractLimit(params map[string]any, defaultVal int) int
- func ExtractPagination(params map[string]any) (limit, offset int)
- func ToolError(code, message string) string
- func ToolJSON(v any) string
- type Config
- type Envelope
Examples ¶
Constants ¶
const ( // DefaultLimit is the default number of items returned in a list response. DefaultLimit = 10 // MaxLimit is the maximum number of items a caller can request. MaxLimit = 25 // DefaultMaxTokens is the target token budget for a single response (~2000 tokens). DefaultMaxTokens = 2000 // DefaultMaxBytes is the target byte budget for a single response (~8000 bytes). DefaultMaxBytes = 8000 )
Variables ¶
This section is empty.
Functions ¶
func EstimateTokens ¶
EstimateTokens approximates the token count from a byte payload. It uses a conservative ~4 characters per token heuristic, which is reasonable for JSON payloads where punctuation and short keys dominate.
func EstimateTokensFromString ¶
EstimateTokensFromString is a convenience wrapper around EstimateTokens.
func ExtractLimit ¶
ExtractLimit gets the "limit" parameter from a map, clamped between 1 and MaxLimit. If the key is missing or not a valid number, defaultVal is returned (itself clamped).
func ExtractPagination ¶
ExtractPagination gets limit and offset from a params map. Limit is clamped to [1, MaxLimit] and offset is clamped to [0, max int]. Missing keys use DefaultLimit and 0 respectively.
Example ¶
limit, offset := ExtractPagination(map[string]any{
"limit": 7,
"offset": 3,
})
fmt.Printf("%d %d\n", limit, offset)
Output: 7 3
func ToolError ¶
ToolError returns a JSON error response string with the given code and message. Callers wrap this in their MCP framework's error response type.
func ToolJSON ¶
ToolJSON marshals v to a JSON string suitable for MCP tool responses. On marshal failure it returns a JSON error object.
Example ¶
env := Envelope{
Items: []string{"alpha"},
Count: 1,
Total: 1,
Truncated: false,
}
fmt.Println(ToolJSON(env))
Output: {"items":["alpha"],"count":1,"total":1}
Types ¶
type Config ¶
type Config struct {
Limit int // max items to include (default DefaultLimit, max MaxLimit)
MaxBytes int // max response bytes (default DefaultMaxBytes)
MaxTokens int // max estimated tokens (default DefaultMaxTokens)
}
Config holds budget parameters for a response.
type Envelope ¶
type Envelope struct {
Items any `json:"items"`
Count int `json:"count"` // items in this response
Total int `json:"total,omitempty"` // total available (before truncation)
Truncated bool `json:"truncated,omitempty"` // true if items were omitted
Hint string `json:"hint,omitempty"` // progressive disclosure hint
}
Envelope wraps list responses with pagination and truncation metadata. Callers serialize this to JSON via ToolJSON and return the resulting string in their MCP framework's response type.
func Apply ¶
Apply takes a slice of items and a hint template, and returns an Envelope that respects the budget config. Items beyond the limit are counted but not included in the response. The hintTemplate is a format string that receives the total count as its first %d argument (e.g., "%d tasks found. Use task_get for details.").
If hintTemplate is empty and the response is truncated, a generic hint is used.
Example ¶
items := []string{"alpha", "beta", "gamma"}
env := Apply(items, Config{Limit: 2}, "%d items available. Add filters to narrow results.")
fmt.Printf("%d %d %t %s\n", env.Count, env.Total, env.Truncated, env.Hint)
Output: 2 3 true 3 items available. Add filters to narrow results.