Skip to content

MCP tools: ownership checks and cleanup after the access gate #15962

Description

@juliusmarminge

Follow-ups from the MCP access declarations (#16335, which replaced #15961). I audited all 72 T3 MCP tools; these gaps are outside what the gate checks, because they depend on who owns a resource rather than on the caller's modes.

Ownership checks missing

  • device_screenshot with an explicit deviceId doesn't check that device belongs to the calling thread's sessions, so a thread can screenshot a device another thread opened (apps/server/src/mcp/toolkits/device/handlers.ts, the deviceId branch).
  • Preview tab ownership isn't enforced on the server: the broker uses tab ownership only to pick a host and forwards threadId/tabId to the desktop (PreviewAutomationBroker.ts). Confirm the desktop refuses another thread's tab, or check it here.
  • t3_attachment_discard doesn't check that the pending upload belongs to the caller (toolkits/attachment/handlers.ts).

Annotations that don't match behavior

  • preview_snapshot is annotated read-only but writes a PNG to disk with save: true.
  • preview_open declares Destructive: false, but browserTool overwrites it to true.

Cleanup left after #16335

  • feat(server): every T3 MCP tool declares who may call it #16335 removed the per-handler copies of the caller checks (readMutationCaller, readFullAccessCaller, readWritableThread, and the copies in ThreadMetadataMcpService and the pull-request handlers). OrchestratorMcpService still repeats some internally: loadCaller, assertLiveCallerForOtherThread/ForOtherProject, and its own mode checks in send, interrupt and scheduled-task updates. These can shrink to the checks only it can make, such as a task belonging to its parent.
  • OrchestratorMcpService.loadCaller doesn't check whether the calling thread is deleted. The declarations cover this for every call, but the service-level helper is still inconsistent with threadAccess.loadCaller.

Decided

  • t3_thread_launch with scratch: true stays open to any caller within its own modes, including Supervised (Julius, 2026-10-05).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions