Toolport v1.17.0
Toolport 1.17.0 brings one permission policy to Claude Code and Cursor, makes
agent rules project-aware and safe around hand edits, hardens approval and Teams
trust boundaries, and fixes fresh Codex gateway startup on Omarchy.
Security
-
A process that bound the approval broker's endpoint after the app had gone could
approve gated calls in its place, and be handed the arguments first. The gateway
dialed whateverapproval-endpoint.jsonnamed and believed whatever came back. The
descriptor survives a crash or a force-kill, and nothing authenticated the peer that
answered: the literal bytes"approved"were a complete decision. Because the
request is written before the reply is read, such a peer also received the call's
real arguments, including the rehydrated values behind a PII release. The gateway now
opens every dial with a random challenge that the broker must answer with an
HMAC-SHA256 proof of the shared token, and sends nothing until the proof checks out;
a peer that cannot read the owner-only descriptor cannot produce it, so it sees no
request and its answer is never read. The failure is reported asunreachable, so a
restarted app is still found on the re-read, and it is still fail-closed. On Unix the
broker also listens on a socket file in a0700directory under the data dir, which
a current gateway prefers, so such a peer cannot even connect on that path; the
loopback listener stays (and is all there is on Windows), and the challenge protects
both the same way. A gateway from before this change still reads only the loopback
address, still reaches the broker, and is still answered. (SBS-867)What this does not claim: a process running as the same user as Toolport can read
the descriptor andregistry.jsonalike, and can switch human approval off directly;
that is a sandboxing question (SBS-185), not an authentication one. -
Teams: a member's consent to a review server no longer follows the server's id
when its command changes. Team servers that run a local command or point at a LAN
address arrive off and stay off until the member reviews and enables them; that
enablement was carried across syncs by id alone, so an org config that kept the id
and swapped the command re-enabled the new command with no re-consent, and a public
remote server that had been auto-enabled (no member action at all) became a local
command that ran on the next gateway start. Consent is now bound to what the member
enabled - transport, command, args, env keys, cwd, url - and is carried over only
when the new entry matches; a changed definition arrives off and is counted in the
"needs review" notice, which now counts only the servers that are actually off rather
than every review server including the ones already consented to. A rename or a tool
allow-list change does not re-prompt. (SBS-1017) -
A form elicitation relayed from an MCP server now says which server is asking.
When a server asks the user for input (MCP elicitation in form mode, whether as a
moderninput_requiredresult or a legacy server-initiated request), the client
renders it in the same chrome as Toolport's own approval prompts, so a server-authored
"your session expired, re-enter your token" was indistinguishable from a genuine one.
Toolport now appendsToolport source: the "<server>" MCP server (not Toolport)to the
message, the form-mode counterpart of the verifiedToolport destination:line URL
mode already carried; a server that pre-writes that line to name itself as something
else has it replaced. (SBS-891)
Added
-
Agent permissions: the same rules now reach Cursor, through a guard hook. Cursor has
hooks but no settings-level rule list, so Toolport installs a small guard into
~/.cursor/hooks.jsonthat runstoolport-gateway --toolport-guard cursorbefore a
shell command runs, an MCP tool is called, or a file is read, and answers allow / deny /
ask from the permission rules you already wrote -Bash(...)for shell commands,
Read(...)for file reads,mcp__server__toolfor MCP tools, with Claude Code's
matching semantics (wildcards, the word-boundary trailing*, compound commands
judged per part, wrappers stripped). Three modes: Off (default), Observe (installed,
every call recorded in Agent activity with what the rules would have decided, nothing
blocked) and Enforce (Never and Ask first take effect; Ask uses Cursor's own prompt;
the hook is installed fail-closed). Only Toolport's own entries are ever added or
removed; a Preview shows the bytes first.Edit/WebFetchrules have no Cursor
event and the tab says so. See
docs/agent-permissions.md. (SBS-1059) -
Agent permissions: rules Claude Code enforces on its own native tool calls. A new
Agent permissions tab holds a policy in Claude Code's own rule syntax (Bash(rm -rf *),
Read(./.env),WebFetch(domain:...),mcp__server__tool, each set to never / ask
first / always allow) and writes it into every Claude Code profile'ssettings.json
underpermissions, so Claude Code itself refuses, or asks before, a matching shell
command, file read or edit, web fetch or MCP call - on every call, whatever any hook
says. Off by default and empty by default; presets (never delete recursively, never
force-push, ask before any push, never read.envor SSH keys) are one-click adds.
Only the rule strings Toolport added are ever added or removed, so a rule you already
had in the file stays; a profile that appears later picks the policy up at the next
start. Claude Code only for now, and the tab says so. See
docs/agent-permissions.md. (SBS-1058) -
Agent rules: start a new set from a rules file you already have. The tab opened on an
empty editor, and the first thing it asked of someone with a~/.claude/CLAUDE.mdor a
~/.codex/AGENTS.mdwas to retype it. Start from a file lists the rules files the
detected clients already read (the user's own text: sentinel-block targets such as
AGENTS.mdandGEMINI.md, the other.mdfiles in a rules directory, and Claude Code's
~/.claude/CLAUDE.md), with a file picker for anything else, and creates a new set from the
file's text - not selected for you, since selecting applies. The file is read and never
written, anything Toolport had
written into it is left out and the import says so, and a remainder that still looks like
Toolport's markers is refused up front. See
docs/agent-rules.md. (SBS-1035) -
Agent rules: apply a rule set inside a project folder. A new Projects section
registers a folder you choose (Toolport never scans for repositories) and applies a set to
the files the repo's clients read there: the rootAGENTS.md(Codex, Cursor, Copilot CLI,
Kiro, Roo Code, Cline, Devin, Goose, Pi, Oh My Pi),GEMINI.md(Gemini CLI, Antigravity)
and.claude/rules/toolport-rules.md(Claude Code, VS Code), each offered only when a
detected client reads it and each naming the clients it reaches. Files are switched on per
project and written only by that project's own Apply, never at startup; switching a
file off or removing the project removes what Toolport wrote; your repo's own text is left
byte-for-byte; a per-file Preview shows the exact bytes first. This is what brings Cursor
and GitHub Copilot into agent rules, which have no user-level file Toolport could write.
Zed is left out on purpose (it reads only the first of nine candidate files, so Toolport
could not honestly report Applied). See
docs/agent-rules.md for the per-client
citations. (SBS-1037) -
Agent rules: a block you edited by hand in a client's file is no longer silently put
back. Toolport wrote its block intoAGENTS.md(or its own file in a rules directory),
you tuned it there, and the next startup or the next time you toggled a client Toolport
rewrote it from the set with no warning. Now a block written for the current set revision
whose body differs on disk reads Edited on disk instead of "Not applied yet"; every
automatic apply (startup, saving, switching sets, toggling clients) leaves it alone; and the
row offers View diff, with Pull into set (the file's version becomes your unsaved
draft) and Overwrite this file (the set goes back over that one file; Re-apply does it for every switched-on client).
A change to the set itself is a newer revision and is written as before. Team
instructions are unchanged: org rules stay authoritative over a member's edit.
(SBS-1036)
Fixed
-
A gateway launched by Codex no longer stops before answering its first call.
Codex starts each MCP child as a process-group leader, which made the gateway's
terminal-session detach fail; its login-shell PATH probe could then receive SIGTTIN
as a background group and stop the whole gateway. Normal Unix startup now handles
that launch shape and leaves the client's terminal session before any probe or
downstream spawn. (SBS-1063) -
Linux gateways launched without the desktop session environment can reach the
Secret Service again. Orca and some AI clients start MCP children with only
HOMEandUSER; on Omarchy that left the gateway without a D-Bus address, so
vaulted servers such as Linear appeared in the cached catalog but every call failed
withno route for tool. When the address is absent, the gateway now recovers the
current user's standard systemd session bus after verifying the runtime directory
and Unix socket are owned by that user. Explicit environment values are left alone.
(SBS-1060) -
Team Instructions: losing a write race no longer deletes the winner's block. When
the team changed or was cleared while an apply was writing its files, the apply that
lost the compare-and-set removed every file it had just written. If the apply that won
had written its own block to those same paths (same markers), the loser stripped it;
if the winner's write had failed, the loser stripped the only good block while the UI
reported the new config. The lost apply now hands its written paths to whichever team
is connected, whose next reconcile sees them as stale and rewrites them; only when no
team remains at all (a disconnect won) is the block removed, which is what disconnect
does to everything it has on record anyway. The other half of this ticket - a path
whose cleanup failed being dropped from the record and stranded - was already fixed
alongside SBS-917. (SBS-914)
Full changelog: https://github.com/tsouth89/toolport/blob/v1.17.0/CHANGELOG.md