Repository navigation
fix(mcp): annotate tools, confirm deletes, fence app output, expire sessions - #83
Merged
Merged
Conversation
…essions - ToolAnnotations on all 13 tools: readOnlyHint on the six read tools, destructiveHint on remove_app, update_app, stop_app and launch_app (its upsert overwrites an existing app); openWorldHint false. - remove_app raises ToolError unless confirm=true. - Pod logs (last 64 KiB) and inline files (16 KiB each) are returned inside untrusted-<nonce> markers the content cannot close, with a notice to treat them as data; list_apps lists inline file paths only. - Device-flow sessions are evicted after MCP_SESSION_TTL_SECONDS idle (default 8h); a missing session id is refused instead of sharing an "anonymous" bucket. Closes #48 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016pvMUQJoLkBDk6B94TTm45
|
📄 Docs preview for |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #48
What changes
Tool annotations on all 13 tools, using the MCP
ToolAnnotationshints.openWorldHint: falseis set everywhere.readOnlyHintdescribe_cluster,list_apps,get_app,get_app_status,get_app_logs,get_app_metricsdestructiveHintremove_app,update_app,stop_app, pluslaunch_appauthenticate,start_app,restart_applaunch_appisn't in the issue's list, but its idempotent upsert overwrites an existing app's spec, so it counts as destructive.idempotentHintis set where retries are safe.The issue counts 7 read tools, but only 6 tools are actually read-only.
authenticatechanges session state, so it isn't marked read-only.remove_appneedsconfirm: true. Without it, the tool raises aToolErrortelling the agent to ask the user and call again.Fenced untrusted output (
untrusted.py). App-authored content (pod logs, inline source files) is wrapped in<untrusted-{16 hex nonce}>…</untrusted-…>next to anoticeto treat it as data. The content can't close the fence early because it can't know the nonce.get_app_logsreturns{notice, logs, truncated}with the last 64 KiB.get_appand the tools that return an app (update_app,stop_app,start_app,restart_app) fence each inline file, capped at the first 16 KiB, withtruncatedFiles.list_appsdropsinline.filesand listspathsonly.Sessions.
TokenState.last_usedis tracked, and logins idle longer thanMCP_SESSION_TTL_SECONDS(default 8h) are evicted on each access.MissingSessionErrorinstead of falling back to a shared"anonymous"bucket.authenticatereportsunavailable, and gated tools get aToolError. Passthrough bearer callers aren't affected.Docs: MCP page sections on annotations, untrusted output and sessions;
MCP_SESSION_TTL_SECONDSin configuration.Upgrade notes
get_app_logsoutput shape changed:logsis now the fenced string, alongsidenoticeandtruncated.list_appsno longer returns inline file contents.confirm: truetoremove_app.Testing
tests/test_safety.py):remove_appraisesToolErrorand the app survivesget_app_logs,get_app,list_apps,stop_app): the injected text, which includes a fake closing marker, sits only inside the nonce fence, andlist_appsdoesn't contain it at alltruncatedFilesauthenticatewithout a sessiontools/listover HTTP returned the expectedreadOnlyHint/destructiveHinton all 13 tools.launch_appwith an injection-ladenindex.html, thenlist_apps→{"paths": ["index.html"]}with no injected text.get_app→ the file inside<untrusted-4a20cf76c133ceb1>…</untrusted-4a20cf76c133ceb1>, with the fake</untrusted-0000…>left inert inside it.get_app_logs→ fenced,truncated: false.remove_appwithoutconfirm→ToolError; withconfirm: true→ deleted.🤖 Generated with Claude Code
https://claude.ai/code/session_016pvMUQJoLkBDk6B94TTm45