Toolport v1.12.0
Two features ship for the first time. PII pseudonymization replaces personal data in
tool results with tokens before the model sees them, restoring the real values only
for the server that provided them. OAuth client credentials let a headless server —
one nobody can click a browser sign-in for — get a real token. Both are off or opt-in
by default.
Several things that were only safe within one process are now safe across processes:
rate-limit counters, OAuth token refresh, and the pseudonym map. Each client spawns
its own gateway, so one process was never the real shape.
Upgrading a Teams deployment: the instructions receipt hash changes once in this
release. See Changed below before rolling it out.
Added
- PII pseudonymization. Emails, phone numbers, card numbers, IBANs, IP addresses
and provider-shaped API keys become stable tokens (⟦EMAIL_1⟧) before the model
sees them, and are restored on the way out. The mapping stays in memory. Off by
default, and a reduction rather than a guarantee: a value no detector recognizes
passes through, as does everything once the per-session cap is reached. (SBS-346) - OAuth client credentials for headless servers. Discovers the endpoint,
negotiates the auth method, and reacquires before expiry. Never falls back to a
browser flow, which would be unusable where this is needed. (SBS-524) - Old gateway binaries are cleaned up instead of accumulating (~18 MB a release).
Keeps anything running, named by a client config, known to be relaunching, or
recent enough to still be cached. (SOU-484) - Apps still launching an obsolete gateway are named. An app caches its spawn
command at startup, so stopping the process is not enough. Settings and a launch
notification list which apps need restarting, each entry clears itself, and Settings
now reports processes it could not stop. (SOU-435) - Keyboard shortcuts.
Ctrl/Cmd+1–6switch view,/orCtrl/Cmd+Ffocuses
search,Ctrl/Cmd+Nadds a server,Ctrl/Cmd+Rrefreshes,?lists them.
(SBS-143) - The window reopens where you left it instead of resetting to a fixed centered
geometry on every launch. (SBS-144) npxservers start about four times fewer processes. Toolport resolves the
entry point directly instead of thecmd.exe→npx→ shim → server chain, which
came to roughly 423 processes for 72 servers on one machine. Version ranges and
@lateststill go throughnpx. Because this skips the install step a server stays
on the cached version;TOOLPORT_NO_DIRECT_SPAWN=1restores the old path. (SOU-550)- Modern MCP extensions. Opaque client extension settings pass through to
downstream servers and compatible declarations aggregate inserver/discover;
io.modelcontextprotocol/taskshandles stay bound to the server that created them
and survive router rebuilds; clients can detect Toolport viaapp.toolport/gateway,
which reports discovery, code-mode, agent-control and approval state. (SOU-453) - MCP Apps. Catalog fetches negotiate the HTML MIME type, Apps hosts get UI-linked
tools even under lazy or grouped discovery, andui://resources route through
their owning tool. App HTML stays byte-faithful for host CSP, and app-only tools
stay out of model-facing search. (SOU-453) - Code mode can validate a script without running it, and a script that fails
partway reports the calls it already made instead of discarding them. (SBS-646,
SBS-647) - The gateway binary supports
--helpand--version, and rejects unknown flags.
Changed
- The team-instructions receipt hash now uses SHA-256 instead of Rust's default
hasher, whose algorithm carries no guarantee across compiler releases. This
changes every member's reported hash once. The Teams coverage dashboard will show
one round of drift that is not real drift; it reconverges as members report in on
this version. Same width and format as before. (SBS-460)
Security
- A pseudonym only resolves for the server that produced it. Tool results are
attacker-controlled, so an injected result could otherwise talk the model into
putting a CRM's token into a URL for an unrelated fetch tool, sending the real value
to whoever wrote the injection. Calls carrying another server's token are refused.
The cost is deliberate: passing a record between servers no longer works unattended.
(SBS-605) - The pseudonym map is cleared when a conversation ends and on a fresh handshake,
on every transport. It previously lived for the whole gateway process with no
eviction. (SBS-605) - Retry fields on a resumed request get the same pseudonym handling as the arguments
beside them, so a host answering a prompt from model context no longer relays a
literal token downstream. (SBS-606) - OAuth token refresh is serialized across the app and the gateway. They share one
keychain and could spend the same refresh token twice, which a provider with reuse
detection answers by revoking the whole family. (SBS-479) - Rate-limit counters are safe across concurrent gateways. Each client spawns its
own and they overwrote one another's counts, so org caps under-counted and did not
hold. Overlapping caps sharing a window no longer double-count. (SBS-680, SBS-609) - An empty quarantine store fails closed. A truncated file silently re-exposed
every tool held after high-risk drift or baseline tamper. (SBS-654) - A cleartext-auth refusal no longer echoes URL-embedded credentials into the error,
where they reached the activity view and logs. (SBS-636) - OAuth hardening (SOU-451): authorization responses bind to the validated issuer,
and stored credentials refuse to cross a changed issuer; discovery checks
path-specific protected-resource metadata before the origin fallback and rejects
metadata for a different resource; BearerWWW-Authenticatechallenges are honored
and validated through the existing TLS and SSRF guards; runtimeinsufficient_scope
challenges preserve prior scopes and open a bounded consent step-up; servers
advertising Client ID Metadata Documents use Toolport's stable HTTPS identity, with
Dynamic Client Registration as the fallback.
Fixed
- Reading a resource whose URI contains non-ASCII characters no longer fails. The
template matcher walked the URI by byte, so backtracking through a multi-byte
character crashed the router. (SBS-620) - A code-mode script's return value is no longer silently corrupted: a
Datecame
back as{}and aBigIntasnull, both reported as success. Values that cannot
be represented now error instead. (SBS-631) - Connect, rescope, disconnect and migrate leave a restart reminder in the panel
rather than only a toast that fades, with wording matched to the action. (SBS-336) - The "Stop old gateways" panel no longer reads as though it contradicts itself. It
could report nothing running directly above a list of apps still launching one —
both true, since a client spawns the gateway on its next tool call. It now says so,
and each row shows the process id so near-identical entries can be told apart. - The Activity list no longer comes up short when the audit log holds an unreadable
line, which used to consume a slot in the page instead of being skipped. (SBS-677) - Servers launched through
npx.batkeep their package identity on import and paste;
only.exe,.cmdand.ps1were recognized as package runners. (SBS-664) - A registry change saved in the app could briefly revert on screen when the disk
watcher read the file outside the lock guarding the in-memory copy. (SOU-329) - OAuth loopback callbacks reject an empty authorization code instead of showing a
success page and sending an invalid token exchange. - The onboarding "What is Toolport for Teams?" link opens the explainer page rather
than the app sign-in, the right destination before you have a team. (SBS-461)
Maintenance
cargo clippy --all-targetsis error-free. A deny-by-defaultnever_loopwas the
last hard failure blocking a clippy gate in CI. (SBS-434)- Code mode's real limits are documented and pinned by tests: a script that never
calls a tool is bounded by iteration and recursion counts, not the wall clock. Both
fail closed. (SBS-430) - Tests pin that pseudonyms resolve as the last step before dispatch, an ordering that
had regressed once without anything catching it. (SBS-614) - Team URLs come from one place, CodeRev reviews once per PR, and text files check out
with LF endings on every platform. (SBS-461)
Thanks
Ten people sent patches this cycle, including two new clients, a fix that stops
installs stripping comments out of hand-edited configs, and the CI job that now guards
the gateway's security suite:
- Vermitrude - Factory Droid CLI support, and
--help/--versionon the gateway binary, which previously accepted unknown
flags silently (#579, #627). - slegarraga - removed a dead data-directory
shim and corrected three pieces of CONTRIBUTING that had drifted from the code
(#638, #639, #642). - rohankumardubey - put the headless gateway
security smoke suite into CI, where it had never run, and exposed sidebar and toggle
state to screen readers (#580, #621). - syf2211 - turned raw stack traces into readable
headlines for DNS, TLS, 429 and 5xx connection failures, and made catalog search
include the category so searching a visible heading actually matches (#611, #614). - alexgaribay - Kimi CLI support, and a fix for
duplicate Tauri context creation across startup paths (#658, #662). - arimu1 - installing the gateway no longer strips
comments out of JSONC client configs (Zed, VS Code, Kilo Code) (#592). - adity982 - Crush MCP client support (#407).
- georgeatparallel - Parallel Search in the
curated catalog (#615). - aryansk - documented the gateway's public
environment overrides (#640). - AshSgDe29071999 - documented curated stacks
and replaced a hardcoded count that broke whenever one was added (#616).
Full changelog: https://github.com/tsouth89/toolport/blob/main/CHANGELOG.md