Skip to content

Releases: pbednarcik/FlexMCP

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 29 Oct 15:04

v0.3.1 hardens input-schema validation against requests that are small to send and costly to check. Upgrading is recommended for any server that validates tool input (WithInputSchemaValidation).

Fixes

  • Long numbers no longer cost seconds of CPU. The schema validator reads every number exactly, and its work grows with how many digits a literal has and how far its exponent reaches. A request with a few hundred literals like 1e-999999 used to cost seconds. Arguments holding a number with more than 1,100 digits, or with a decimal scale past 1,100 either way, are now refused as out of range before the validator reads them. Every number a float64 can hold fits within these bounds.
  • Deep nesting no longer multiplies the cost. Under a recursive schema, the validator's error tree grows with the square of the nesting depth: a 20 KB request could allocate about 800 MB. Arguments nested deeper than 128 levels (objects and arrays, the arguments object counting as the first) are now refused before validation, with value is nested deeper than 128 levels.
  • Validation refusals are bounded and honour the size limit. A refusal now cuts the place it names as the validator's own lines already did, so a long property name no longer makes the answer twice the request's size. Every validation refusal, on input and output, synchronous or in a task, now passes WithToolResultSizeLimit.

Changes you may notice

  • These refusals are isError tool results, like every validation failure. Their text follows the existing form; for an ordinary short path it is unchanged.
  • The two new input refusals apply whatever the schema says: a past-bounds number is refused even where no keyword reads it, and so is a deeply nested argument.
  • Output validation is unchanged: a tool may still return large integers in structured content.
  • The limits are described in Tools.

Known issues

  • The validator records every failure in a request, so a request whose many values all fail still costs memory in proportion: about 1 KB per failing value, more when the values sit deep. A 200 KB request of 100,000 failing values measured 92 MB when they sat three levels deep, and 471 MB at 126 levels. This is not new in this release. Put a request body limit in front of a server that validates input from untrusted clients. A validator that stops early is planned.

Install

go get github.com/pbednarcik/flexmcp@v0.3.1

The OpenTelemetry adapter is unchanged: github.com/pbednarcik/flexmcp/otel@v0.2.0.

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 29 Oct 06:47

v0.3.0 adds the 2026-07-28 Tasks extension (io.modelcontextprotocol/tasks) to the server and the client.

Highlights

  • Long-running tools as tasks. A tool handler can answer a tools/call with a task by returning server.NewTaskResult(ctx, handlerID, ...). The client then polls tasks/get, and can cancel with tasks/cancel or answer input with tasks/update.
    • FlexMCP stores nothing about a task. A TaskHandler you provide owns the work and its state.
    • server.NewMemoryTasks is a ready-made in-memory handler: MemoryTasks.Run hands the call over when the request allows it, and otherwise runs the work synchronously.
  • Unguessable task ids, bound to the caller. A task id is sealed with an HMAC, not looked up. Set WithTaskKey so ids survive a restart and work across instances, and WithTaskCaller so one caller cannot read another's tasks.
  • Client support. GetExtensionTask, CancelExtensionTask, UpdateExtensionTask and WaitForExtensionTask. A refused id is a typed mcp.TaskRefusedError; mcp.IsTaskGone tells you to call the tool again.
  • Both eras kept apart. The 2025-11-25 tasks (AddTaskTool, params.task) serve initialize-era requests only. On a 2026-07-28 request, params.task is ignored, task-only tools are hidden, and execution is dropped from tools/list.
  • Works with Claude Code. Checked live against Claude Code 2.1.312, which declares the extension on its tools/call and tasks/get and polls at the interval the server asks for. It does not declare it on every call, so a tool must still answer synchronously when no task is possible; MemoryTasks.Run does.
  • Documented and runnable. See Tasks and examples/tasks_extension.

Changes you may notice

  • The task result options are WithTaskResultPollInterval, WithTaskResultTTL, WithTaskResultStatusMessage and WithTaskResultCreatedAt. The WithTask* names already belong to the 2025-11-25 tasks.
  • Run handed-over work under server.DetachTaskContext(ctx). It keeps the request's values and drops its cancellation, its session and its task stamp. MemoryTasks.Run does this for you.
  • On a 2026-07-28 request, tasks/get, tasks/cancel and tasks/update fire only the untyped hooks (BeforeAny, OnSuccess, OnError). The typed task hooks are for earlier revisions.
  • On a 2026-07-28 connection, the client's old GetTask, CancelTask, WaitForTask, TaskResult and ListTasks return ErrLegacyTaskMethod.
  • WithExtensions copies its map. Given a tasks entry without a task handler, it panics at construction.
  • A client may leave without cancelling its task, so choose a TTL that bounds abandoned work. MemoryTasks defaults to one hour.
  • mcp.WithModelImmediateResponse is deprecated. The server never sends it in the answer to a task-augmented call.

Fixes

  • Output schema validation now judges a result's raw structured content when the result carries it. Before, raw content that broke the schema could be sent unchecked.
  • A tool re-registered while a call is in flight:
    • its Mcp-Param-* header bindings are now enforced on that call;
    • a 2025-11-25 task-augmented call now runs the registration the tool filters authorized.
  • Tool filters on a 2026-07-28 tools/call see the same tool that tools/list showed them.

Known issues

  • At a very small result-size limit, the answer that hands a call over can be replaced by a size error after the task has started. Keep the limit well above the size of a task answer.

Install

go get github.com/pbednarcik/flexmcp@v0.3.0

The OpenTelemetry adapter is unchanged: github.com/pbednarcik/flexmcp/otel@v0.2.0.

v0.3.0-rc.1

v0.3.0-rc.1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 28 Oct 18:24

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 26 Oct 20:32

FlexMCP is a high-performance Go implementation of the Model Context Protocol, tuned for busy servers that answer many complex tool calls. It began as a fork of mark3labs/mcp-go v1.1.1 and has since been largely reworked. This is its first release with notes.

Highlights

  • Both protocol eras. The 2026-07-28 revision first, and the earlier revisions a client may still open with initialize. The server is stateless: sessions, the GET stream, resumption, the event store, server-initiated requests and the HTTP+SSE server transport are gone.
  • Closer to the specification. The server was checked against the 2026-07-28 specification requirement by requirement. Request ids are handled exactly, Origin is validated, and OAuth keeps the MUSTs: HTTPS-only authorization servers, PKCE on by default, and a token sent only to its own server.
  • Fast and lean. _meta and a tool call's arguments are decoded in one pass, input is validated without a second decode, header bindings are read once, and ServerTool.ArgumentsOnDemand lets a tool skip building the arguments map. In our benchmarks a single in-process tool call is served up to 3 times faster than with mcp-go and up to 14 times faster than with the official Go SDK, with less than half of mcp-go's allocations (benchmarks on two machines).
  • Hardened. Bounded request bodies, HTTP timeouts, DNS-rebinding checks, bounded task lifetimes, and a typed-nil handler error answered instead of a panic.
  • Upstream fixes. Fixes from mcp-go are ported by hand, through upstream's main after v1.3.0, each commit naming the pull request it ports.

Upgrading from mcp-go

  • The module path is github.com/pbednarcik/flexmcp; the OpenTelemetry adapter is its own module, github.com/pbednarcik/flexmcp/otel.
  • Some client APIs and behaviours changed: read Client changes and Request ids and progress tokens first.
  • The default client name in clientInfo is now flexmcp.

Install

go get github.com/pbednarcik/flexmcp@v0.2.0
go get github.com/pbednarcik/flexmcp/otel@v0.2.0