You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(quarantine): atomic Block (approve+disable) endpoint for tools (MCP-2198) (#653)
* feat(quarantine): atomic Block (approve+disable) endpoint for tools (MCP-2198)
Add an atomic "block" = approve+disable for quarantined tools, performed
server-side as a single all-or-nothing write per tool so a tool is never
observably left in the approved+enabled state.
- internal/runtime/tool_quarantine.go: BlockTools / BlockAllTools — promote
status to approved (ReasonUserApprove) AND set Disabled in one
SaveToolApproval; emit tool_blocked activity + tools_blocked SSE. Block only
ever disables, so config-denied tools need no special handling.
- internal/httpapi/server.go: POST /api/v1/servers/{id}/tools/block
(handleBlockTools), mirrors handleApproveTools — {tools:[...]} or
{block_all:true}; 400 if neither.
- internal/server/mcp.go: block_tool / block_all_tools ops on quarantine_security.
- internal/server/server.go: controller passthroughs.
- Tests: httpapi + runtime (end state approved && Disabled; specific/all/empty).
Backend lane of GH #632 (parent MCP-2196).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
* fix(quarantine): single-line OAS block description + MCP block_tool tests
Addresses CodexReviewer request_changes on PR #653:
1. The /servers/{id}/tools/block @description swag annotation was split
across multiple comment lines, so swag truncated the generated
oas/swagger.yaml description at the first line. Collapse it to a
single line and regenerate (make swagger) so the full sentence is
emitted.
2. Add internal/server coverage for the new quarantine_security MCP ops
block_tool / block_all_tools: dispatch routing, required-arg errors
(missing name / tool_name), and the atomic approve+disable success
path (RV-3). A runtime-backed proxy helper shares storage with the
runtime so the handlers' runtime.BlockTools path executes for real.
Related #653
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
- **`code_execution`** - Execute JavaScript to orchestrate multiple tools (disabled by default)
371
-
- **`upstream_servers`** - CRUD operations for server management. Spec 049: list/get entries carry a conditional `tools` count block only when a server has ≥1 non-callable tool.
**Intent Declaration (Spec 018)**: Tool variants enable granular IDE permission control. The `operation_type` is automatically inferred from the tool variant (`call_tool_read` → "read", etc.). Optional `intent` fields for audit:
376
+
**Intent Declaration (Spec 018)**: Tool variants enable granular IDE permission control; `operation_type` is inferred from the variant (`call_tool_read` → "read"). Optional `intent` fields for audit:
377
377
```json
378
378
{
379
379
"intent": {
@@ -406,6 +406,7 @@ See [docs/configuration.md](docs/configuration.md) for complete reference.
// + /servers/disable_all but scoped to a single server's tools.
@@ -4665,6 +4672,70 @@ func (s *Server) handleApproveTools(w http.ResponseWriter, r *http.Request) {
4665
4672
})
4666
4673
}
4667
4674
4675
+
// handleBlockTools handles POST /api/v1/servers/{id}/tools/block
4676
+
// A block is an atomic approve+disable performed in the runtime so the pair is
4677
+
// all-or-nothing — a tool is never left approved+enabled. Mirrors
4678
+
// handleApproveTools: accepts either {"tools":[...]} or {"block_all":true}.
4679
+
//
4680
+
// @Summary Block (approve+disable) tools for a server
4681
+
// @Description Atomically approves AND disables the given tools (or all pending/changed tools when block_all=true) for a server. The approve and disable land in a single write per tool, so a tool is never left in the approved+enabled state. The "blocked" field counts tools actually blocked.
0 commit comments