Release Notes - ChristianPresley/zig-sdk GitHub Wiki
This page tells you what each release of zig-sdk contains. The source is the file CHANGELOG.md of the repository1. Each GitHub release has the same section of the changelog2. The Versioning page tells you how the version numbers change.
Applies to: zig-sdk 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.5.0 and 0.5.1.
A patch release with two fixes for the stop of the servers. A cancel of serve now stops the server the same way as shutdown. The stop of the accept loops no longer leaves traces in Debug builds on Windows or a panic on macOS. It supports MCP specification revision 2026-07-28 only, on Zig 0.16.0. The file CHANGELOG.md has the full list, and the tag is v0.5.1.
- A cancel of
serveof the HTTP, gRPC and Unix socket servers sets the stop flag ofshutdown. A new call ofserveon the same server then accepts no connections. After the cancel, the connections of the HTTP server obey the stop flag, so a connection that waits ends within 60 seconds. - The accept loops of the HTTP, gRPC and Unix socket servers stop with
util.wake.cancelAcceptLooporutil.wake.cancelUnixAcceptLoop. On Windows, the cancel usually comes before the wake connection, so a Debug build no longer writes a stack trace oferror.Unexpected. - On a POSIX system,
util.wake.wakeIpconnects with a socket that does not block. A late cancel signal of std no longer makes the second connect fail withEISCONNon macOS.
A minor release with time limits for the keychain storage on Linux and a fix for Unix sockets on Windows. One change breaks the public API. It supports MCP specification revision 2026-07-28 only, on Zig 0.16.0. The file CHANGELOG.md has the full list, and the tag is v0.5.0.
-
KeychainTokenStorage.Options.timeoutandsecret_service.Options.timeoutset the time limit for each answer of the D-Bus bus and of the Secret Service. The default is 25 seconds. A service that does not answer in time giveserror.KeychainUnavailable. Before, the Secret Service backend waited without a limit. -
KeychainTokenStorage.Options.prompt_timeoutandsecret_service.Options.prompt_timeoutset the time limit for the answer of the user to a prompt. The default is 5 minutes. A prompt without an answer in time giveserror.KeychainLocked. - The D-Bus client connects to an abstract address with a socket that does not block. Before, this connect waited without a limit, and a cancel did not stop it.
See Authorization.
- On Windows, the Unix socket transport sees each close of the peer. The Windows driver of Unix sockets can lose the close when a receive starts at about the same time. Before, the server kept such a connection and its place in
limits.unix_socket.max_connectionsuntil shutdown. A request of the client waited until its timeout. Now each read first waits in a poll of the socket. See Transport Unix Socket.
- For an
httpURL, the proxy can read the requests, because that tunnel has no TLS. For anhttpsURL, the proxy sees only the host and the port of the server. - The warning of the scope
mcp_routerfor an error response with a null id also has the error code of the response.
- On Windows, the fake D-Bus server of the keychain tests serves each connection in its own task.
-
dbus.Connection.openhas a fifth parameter, the time limit for each answer of the bus. Null waits without a limit, as before. At the limit, the functions of the connection returndbus.Error.Timeout, and the connection is then not usable.
A minor release with new options for the clients and fixes for the transports. It adds options for one request, HTTP proxies and a CA bundle for the OAuth client. It also corrects the failure paths of the client transports and the HTTP/2 connection of the gRPC transport. Four changes break the public API. It supports MCP specification revision 2026-07-28 only, on Zig 0.16.0. The file CHANGELOG.md has the full list, and the tag is v0.4.0.
-
RequestOptions.log_levelsets the log level of one request. It replacesOptions.log_levelof the client for that request. -
RequestOptions.metaadds_metaentries to one request, for exampletraceparent. A key thatmeta.validateKeyrefuses, or a key that the SDK owns, gives the newerror.InvalidMeta. Then the client sends nothing.meta.isSdkOwnedRequestKeytells which keys the SDK owns. - The client parses each notification into scratch memory and resets that memory after the frame. Thus a long
subscriptions/listenstream does not make the request arena larger. -
RequestOptions.inline_notificationscalls the notification callbacks of a request on the reader task of the transport. A notification then gets to its callback before the response of another request that the server wrote after it. The stdio, Unix socket and WebSocket transports obey the option. -
Diagnostics.http_statusgives the HTTP status of the last response, also when the request failed. Thus a caller can tell a wrong path from a response that is not valid.
See Client Guide.
- The stdio, Unix socket and WebSocket clients make a request fail with
error.InvalidResponsewhen the router cannot read its response. Before, the request waited until its timeout. The router logs a warning in the scopemcp_routerfor each frame that it drops. - The stdio client takes
on_notificationanduserdataas spawn options.stdio.Client.exitStatusgives the exit status of the last server process that ended. - When the stdio server process ends its output and no restart is left, the client closes the input of the process and reaps it. A process that does not exit gets a termination signal after
limits.shutdown_grace, also at a restart. - The HTTP client transport applies
max_response_bytesto each SSE event, and not to the whole stream. Thus many progress notifications do not stop a long tool call. The SSE parser limits an event tomax_event_bytes(4 MiB) and ignores an event ID overmax_id_bytes(256). - The memory link (
memory.ClientLink) gives the frames of one request to the sink one at a time. Its doc comments tell its limits.
See Transports.
- The server sends the acknowledgment of a
subscriptions/listenstream before the first event of the stream, on all transports. Before, an event could get to the client before the acknowledgment. See Server Guide.
-
OAuthClient.Options.ca_bundlesets the CA certificates that the OAuth client trusts for itshttpsrequests. A private CA then works without a change to the CA store of the system. -
OAuthClientreads the stored token record again before a refresh and after the server refuses a refresh. Thus two clients with one storage can use one grant with refresh token rotation. - When the stored record has another client ID than the registration of
OAuthClient, the client takes the registration of the record with its tokens. When these tokens are for another DPoP key, the client keeps its own registration and tokens. -
HttpClient.Options.proxyandOAuthClient.Options.proxysend the connections through an HTTP proxy with aCONNECTtunnel. The new moduletransport.proxyreads the proxy variables from the environment that the application gives. By default, the clients connect directly, as before.
See Authorization and Client Guide.
- The gRPC clients keep a response that the server sends before it reads the request message, for example an authorization challenge. Before, the client could lose that response.
- After a complete response, the gRPC server resets a stream with the code
NO_ERRORwhen the request did not end. Before, it sentCANCEL. -
http2.Connection.Stream.stopWaitsstops the waits on a stream without a reset, because Zig 0.16.0 can lose a cancel. The gRPC server uses it to stop the task that watches a stream for a reset. The channels reset the stream of a call withclient.CallStream. -
Stream.cancelwakes each task that waits on the stream. - The connection frees a peer stream that it refuses for its headers. The HPACK decoder reads the whole header block after a size error, thus the dynamic tables of the two peers stay the same.
- A server connection ignores a header block on a peer stream that it reset, for the last 64 such streams (
remembered_resets). Before, such a block ended the connection. - The reset for an oversized header block cannot stop the connection. Before, the read task held the connection lock while it waited for the write lock.
- A stream that gets a cancel before its headers go out gets no id and sends no headers. Before, the server kept such a stream open until the connection ended.
See Transport gRPC.
-
util.loopback.connectandutil.loopback.listenmake at most five tries when an error can go away. On Windows, Zig 0.16.0 gives some of these errors aserror.Unexpected. The tests of the SDK use the functions for their own sockets.
- The
methodandparamsarguments ofRequestOptions.on_notificationandHooks.on_notificationare valid only during the call. A callback that keeps a part of them must copy it. - The fields
on_notificationanduserdataofstdio.Clientare gone. Use the spawn options with the same names. - Over the memory link, the callback of the acknowledgment of a listen stream runs while the server holds the lock of the stream. The callback must not publish an event of the same server.
-
sse.Parser.feedreturnssse.Parser.FeedErrorwith the new errorerror.EventTooLarge.
A minor release with fixes for the limits of release 0.2.0. It removes two fields of mcp.Limits, thus it changes the public API. It supports MCP specification revision 2026-07-28 only, on Zig 0.16.0. The file CHANGELOG.md has the full list. The tag is v0.3.0.
- The Streamable HTTP server obeys
http.head_timeoutandhttp.idle_timeout. A slow client cannot keep a connection without end. - At a shutdown, the HTTP server closes a connection that waits for a request at once. It does not wait for the peer.
- The servers of all transports check
json_max_depthbefore the parse. A deeper message gets-32700. - The server checks
max_filter_bytesfor asubscriptions/listenfilter. - The client obeys
listen_ack_timeouton all transports. The field moved fromhttpto the top level ofmcp.Limits. - The HTTP client gives each SSE event to the request when its bytes arrive. Before, an event waited for the next bytes.
- The HTTP/2 connection of the gRPC transport answers a frame that is too large with
FRAME_SIZE_ERROR. - Removed:
Limits.cancel_notify_timeoutandLimits.max_step_up_attempts. Each authorization client keeps its own optionmax_step_up_attempts.
See Limits and Security.
The second release. It supports MCP specification revision 2026-07-28 only, on Zig 0.16.0. It has the work of milestones M10 to M12. The file CHANGELOG.md has the full list. The tag is v0.2.0.
- The Unix socket transport, with a private directory and an owner-only socket file on POSIX and on Windows. See Transport Unix Socket.
- The WebSocket transport on RFC 6455 connections with the subprotocol
mcp. See Transport WebSocket. - The typed gRPC binding of the Google Cloud proto files, next to the JSON-RPC tunnel. See Transport gRPC.
- Rate limits for each caller: tool calls and log messages. See Limits and Security.
- RSA and RSA-PSS certificate keys, and the hybrid key exchange X25519MLKEM768 as the first choice.
- The AEGIS cipher suites as an option, and record padding.
- The certificate_authorities extension, name constraints, revocation with CRLs and OCSP stapling, and the check of the extended key usage.
- The fixes of the internal security review. The file
docs/security/tls-review.mdlists them.
See TLS and Certificates.
- The authorization extensions: client credentials, enterprise-managed authorization, DPoP-bound tokens and workload identity federation.
- Refresh tokens, and the token storage in memory, in encrypted files or in the keychain of the host.
- An OAuth 2.1 authorization server. See Authorization Server.
See Authorization.
- All keywords of JSON Schema 2020-12, with a regular expression engine that runs in linear time.
- The Skills extension and the MCP Apps extension. See Skills Extension and Apps Extension.
- Client icon rules, default request timeouts and more checks of the client and of the server.
- The requirement matrix maps each normative sentence of the specification to a test or a reason. See Conformance.
- The CI job
conformancealso gates the scenarios that the suite does not score, and runs the authorization server scenarios. - Interoperability jobs for WebSocket and for the typed gRPC binding. See Interoperability.
- The documentation site:
zig build sitebuilds a first page and the API reference of the modulesmcpandmcp_grpc. The workflowdocs.ymldeploys it to GitHub Pages. -
zig build lint-docshas the warning rules of the project profile and runs in strict mode. See Style Guide (STE). - The new build steps
site,extract-requirements,spec-matrixandconformance-authorization-server.
-
tls.verify.verifyChaintakes(certs, trust, ChainOptions). -
mcp.tls.PrivateKey.publicKeyBytestakes a larger buffer. -
Registration.pre_registeredofOAuthClientis a list of credentials, each bound to an issuer.
- Five defects gave a peer a way to stop the process or to access memory out of bounds. The defects were in the TLS record layer, the TLS message parsers, the HPACK decoder, the
grpc-timeoutparser and the JWT time claims. The fuzz job found three of them. - The HTTP/1.1 client, the WebSocket client and the authorization fetcher refuse control characters in a request head.
- The TLS chain validation checks the extended key usage and the basic constraints of each intermediate. The client compares the host name only with the subject alternative names.
The first release. It supports MCP specification revision 2026-07-28 only, on Zig 0.16.0. The tag is v0.1.0.
- Protocol types for revision 2026-07-28, and the JSON-RPC envelope with its parser and writers.
- The server engine: tools, resources, resource templates, prompts, completion, pagination, multi round-trip requests and subscriptions. See Server Guide and Resource Templates.
- The SDK derives the JSON Schema of a tool from a Zig type at compile time.
- A JSON Schema 2020-12 validator for a subset of the keywords. The server checks tool arguments against the input schema and structured output against the output schema. See JSON Schema Support.
- The stdio transport for servers and clients. The client manages the server process with process groups on POSIX and a job object on Windows. It stops the server with
SIGTERMand thenSIGKILL, and it can start the server again withmax_restarts. See Transport stdio. - The Streamable HTTP transport for servers and clients, with SSE responses and header mirroring. The client runs on an HTTP/1.1 connection of the SDK. See Transport Streamable HTTP.
- The gRPC transport in the module
mcp_grpc: a JSON-RPC tunnel over HTTP/2 with its own protobuf format, HPACK, HTTP/2 connection and gRPC layers. Metadata mirrors the HTTP headers. An error before the first message travels in the trailers. See Transport gRPC. - An in-memory link for tests.
- A TLS 1.3 server in the SDK with ECDSA P-256, P-384 and Ed25519 certificates. It supports the key exchange groups X25519, P-256 and P-384, HelloRetryRequest, ALPN and server name indication. The HTTP transport serves HTTPS with the
tlsoption. - A TLS 1.3 client in the SDK. It verifies the chain against a CA set, the std bundle, a pinned leaf or a self-signed policy. It checks the host name or the IP address, the CA constraints and ALPN, and it can send a client certificate. The server can ask for client certificates.
- A precheck rejects malformed peer certificates before the std parser reads them. The first fuzz run found that the std parser reads out of bounds on a certificate that is too short.
See TLS and Certificates.
-
mcp.Clientwith typed requests, progress and log callbacks, and the multi round-trip driver with application hooks. - A result cache:
Client.Options.cacheandRequestOptions.cache_mode. The client uses a result with a positivettlMsagain until it expires, until a list-changed notification arrives, or untilinvalidateCacheruns. - The client sends a request again when it lost the stream before a response byte:
RequestOptions.retrywithauto,neverorforce, up tolimits.max_lost_stream_retries.
See Client Guide.
- An OAuth 2.1 client. It discovers the protected resource metadata and the authorization server metadata, and it has three registration methods. It uses PKCE S256,
resourceindicators andissvalidation. It selects the scope with step-up limits and keeps credentials per issuer. The HTTP client transport answers401and403challenges with it. - Helpers for resource servers: the protected resource metadata, bearer token checks with
WWW-Authenticatechallenges, and JWT verification with HS256, ES256, RS256 and PS256. The request context has the principal. The HTTP server uses them with theauthoption.
See Authorization.
- Servers: the
tasksoption,task_supportfor each tool, the.start_taskoutcome,tasks/get,tasks/updateandtasks/cancel, input requests inside a task, cancellation and the-32021gate. - Clients:
callToolwaits for a task and answers its input requests with the hooks.callToolOrTask,getTask,updateTask,cancelTaskandawaitTaskgive full control. The HTTP client mirrors the task id intoMcp-Name.
See Tasks Extension.
- The build steps
test,fmt,examples,docs,lint-docs,census,commit-policy,conformance-server,conformance-client,gen-bibliography,gen-dictionary,bench,check-versionandchangelog-section. - A conformance fixture server and a CI job that runs the official conformance suite. The fixture server also serves gRPC. The CI job
grpc-interopcalls it from a Nodehttp2peer and fromcurl. See Conformance and Interoperability. - Benchmarks for the request dispatch, HPACK decoding and the TLS handshake, with a baseline and a nightly smoke run.
- Fuzz targets for every parser. The nightly workflow runs them.
- CI with its own Zig installation step, a consumer build through
b.dependency, a nightly workflow and a release workflow. The release workflow verifies the signed tag and publishes the section of the changelog.
- KEEPACHANGELOG: "Keep a Changelog" 1.1.0.
- GH-RELEASE-NOTES: Release notes on GitHub.