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
{{ message }}
Repository navigation
Commit 9b8271f
Browse filesBrowse the repository at this point in the historyBrowse files
Compact retrieve_tools entries (tool_response_mode: compact, Spec 085) omitted call_with, so agents picked the call_tool_read/write/destructive variant from the tool name and could route a tool such as windows:PowerShell through the wrong variant although the proxy already had the upstream classification. Each compact entry now carries the same call_with route as full mode, including the call_tool_read fallback for unannotated tools, and the tool descriptions, usage instructions and REST docs make that route authoritative over names, descriptions, command text and apparent intent. The old name-keyword decision rules are removed, which also makes every response smaller (about 50 to 220 tokens per retrieve_tools call on the goldens).
Review: maintainer read, live-instance check in compact and full mode with annotated, destructive and unannotated tools, opencode Sol 6.1 cross-review; follow-up commit pins the exact golden delta and aligns docs.
Co-authored-by: copystring <copystring@users.noreply.github.com>
Copy file name to clipboardExpand all lines: docs/api/rest-api.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -758,7 +758,7 @@ See [Routing Modes](../features/routing-modes.md) for details on each mode.
758
758
759
759
The MCP endpoints (not REST) additionally expose progressive-disclosure discovery in the `retrieve_tools` routing mode:
760
760
761
-
-**`tool_response_mode`** config (`full` default | `compact`, hot-reloadable via `POST /api/v1/config/apply`) controls `retrieve_tools` serialization only. In `compact` mode each entry is `{id, score, sig, desc, lossy}` — a one-line parameter signature (`*` = required, `~` = lossy) plus a first-sentence description— instead of full `inputSchema`, and the response carries one top-level `hint` line. Ranking is identical between modes.
761
+
-**`tool_response_mode`** config (`full` default | `compact`, hot-reloadable via `POST /api/v1/config/apply`) controls `retrieve_tools` serialization only. In `compact` mode each entry is `{id, score, sig, desc, lossy, call_with}` — a one-line parameter signature (`*` = required, `~` = lossy), a first-sentence description, and the same dispatch route as full mode — instead of full `inputSchema`, and the response carries one top-level `hint` line. If upstream tier annotations are unavailable, `call_with` preserves the existing read fallback. Ranking is identical between modes.
762
762
-**`detail`** — optional per-call `retrieve_tools` parameter (`compact` | `full`) overriding the configured mode for that call.
763
763
-**`describe_tool`** — built-in second-stage tool (retrieve_tools mode only): accepts 1–5 `server:tool` ids and returns full definitions (`name`, `description`, `inputSchema`, `server`, `annotations`, `call_with`) with per-id errors for ids that do not resolve. It applies the same visibility pipeline as search (profile scope, agent-token scope, quarantine, tool approval, disabled) and never returns a definition `retrieve_tools` could not. Per-id error codes: `not_found`, `quarantined`, `pending_approval`, `changed`, `disabled` (Spec 099 retired `invisible`: an out-of-scope id now reports `not_found`, indistinguishable from an id that does not exist — see the [breaking-change note](https://github.com/smart-mcp-proxy/mcpproxy-go/blob/main/CHANGELOG.md)).
764
764
-**`describe_tool` check mode (Spec 099)** — the same built-in with `check: true` answers availability instead of definitions: up to 50 ids, an optional `filters` object (`read_only_only`, `exclude_destructive`, `exclude_open_world` — the REST body of `POST /api/v1/preflight` calls the same object `policy`), and a response of `{verdict, checked_at, request_id, results[]}` carrying the same reason codes this endpoint returns. It is the in-band twin of `POST /api/v1/preflight`, evaluated by the same evaluator, and differs deliberately: always the agent-token disclosure tier (never a hash, never `server_not_in_scope`), the session's own scope with no `profile` parameter, no hash pins (`expect_hashes` is a reserved field name and is rejected), and no wait budget. See [Required-Tools Preflight](../features/tools-preflight.md#in-band-describe_tool-check-mode).
Copy file name to clipboardExpand all lines: docs/configuration.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1396,7 +1396,7 @@ Controls only the *serialization* of `retrieve_tools` responses (Spec 085) — n
1396
1396
1397
1397
| Field | Type | Default | Description |
1398
1398
|-------|------|---------|-------------|
1399
-
|`tool_response_mode`| string |`"full"`|`full` returns complete `inputSchema` entries (pre-Spec-085 behavior, byte-identical). `compact` returns one-line signatures instead: per entry `id`, `score`, `sig`, first-sentence `desc`, and a `lossy` flag, plus one top-level `hint` line. |
1399
+
|`tool_response_mode`| string |`"full"`|`full` returns complete `inputSchema` entries (pre-Spec-085 behavior). `compact` returns one-line signatures instead: per entry `id`, `score`, `sig`, first-sentence `desc`, a `lossy` flag and the same `call_with` route as full mode, plus one top-level `hint` line. |
1400
1400
1401
1401
-**Compact signatures**: `*` marks a required parameter (never elided), `~` marks a lossy collapse (nested objects, long enums — call `describe_tool` for the full schema), short enums/defaults are inlined (e.g. `(origin*:str, ttl:int=3600)`).
1402
1402
-**Per-call override**: the `detail` parameter on `retrieve_tools` (`compact` | `full`) overrides the configured mode for that call only.
|`tool_response_mode`| string |`"full"`|`full`, `compact`|`full` returns each result with its complete `inputSchema` (pre-Spec-085 behaviour, byte-identical). `compact` returns a one-line signature instead: per entry `id`, `score`, `sig`, a first-sentence `desc` and a `lossy` flag, plus one top-level `hint`. An empty value means `full`. |
111
+
|`tool_response_mode`| string |`"full"`|`full`, `compact`|`full` returns each result with its complete `inputSchema` (pre-Spec-085 behaviour). `compact` returns a one-line signature instead: per entry `id`, `score`, `sig`, a first-sentence `desc`, a `lossy` flag and the same `call_with` route as full mode, plus one top-level `hint`. An empty value means `full`. |
112
112
113
113
-**Compact signatures**: `*` marks a required parameter (never elided), `~`
114
114
marks a lossy collapse (nested objects, long enums), and short enums/defaults
description="Execute a READ-ONLY tool. WORKFLOW: 1) Call retrieve_tools first to find tools, 2) Use the exact 'name' field from results, 3) Build args from the 'sig' signature ('*'=required; if lossy '~', call describe_tool first). DECISION RULE: Use this when the tool name contains: search, query, list, get, fetch, find, check, view, read, show, describe, lookup, retrieve, browse, explore, discover, scan, inspect, analyze, examine, validate, verify. Examples: search_files, get_user, list_repositories, query_database, find_issues, check_status. This is the DEFAULT choice when unsure - most tools are read-only."
1168
+
description="Execute a READ-ONLY tool. Use this variant only when retrieve_tools returns call_with=call_tool_read. The upstream annotations and call_with are authoritative over a tool's name, description, command text, or the requested outcome. Build args from the 'sig' signature ('*'=required; if lossy '~', call describe_tool first)."
1169
1169
title="Call Tool (Read)"
1170
1170
nameExample="github:get_user"
1171
1171
sensitivityDesc="Classify data being accessed: public, internal, private, or unknown. Helps track sensitive data access patterns."
description="Execute a STATE-MODIFYING tool. WORKFLOW: 1) Call retrieve_tools first to find tools, 2) Use the exact 'name' field from results, 3) Build args from the 'sig' signature ('*'=required; if lossy '~', call describe_tool first). DECISION RULE: Use this when the tool name contains: create, update, modify, add, set, send, edit, change, write, post, put, patch, insert, upload, submit, assign, configure, enable, register, subscribe, publish, move, copy, rename, merge. Examples: create_issue, update_file, send_message, add_comment, set_status, edit_page. Use only when explicitly modifying state."
1179
+
description="Execute a STATE-MODIFYING tool. Use this variant only when retrieve_tools returns call_with=call_tool_write. The upstream annotations and call_with are authoritative over a tool's name, description, command text, or the requested outcome. Build args from the 'sig' signature ('*'=required; if lossy '~', call describe_tool first)."
1180
1180
title="Call Tool (Write)"
1181
1181
nameExample="github:create_issue"
1182
1182
sensitivityDesc="Classify data being modified: public, internal, private, or unknown. Helps track sensitive data changes."
description="Execute a DESTRUCTIVE tool. WORKFLOW: 1) Call retrieve_tools first to find tools, 2) Use the exact 'name' field from results, 3) Build args from the 'sig' signature ('*'=required; if lossy '~', call describe_tool first). DECISION RULE: Use this when the tool name contains: delete, remove, drop, revoke, disable, destroy, purge, reset, clear, unsubscribe, cancel, terminate, close, archive, ban, block, disconnect, kill, wipe, truncate, force, hard. Examples: delete_repo, remove_user, drop_table, revoke_access, clear_cache, terminate_session. Use for irreversible or high-impact operations."
1190
+
description="Execute a DESTRUCTIVE tool. Use this variant only when retrieve_tools returns call_with=call_tool_destructive. The upstream annotations and call_with are authoritative over a tool's name, description, command text, or the requested outcome. This variant does not bypass authorization, quarantine, approval, or other dispatch gates. Build args from the 'sig' signature ('*'=required; if lossy '~', call describe_tool first)."
1191
1191
title="Call Tool (Destructive)"
1192
1192
nameExample="github:delete_repo"
1193
1193
sensitivityDesc="Classify data being deleted: public, internal, private, or unknown. Important for tracking destructive operations on sensitive data."
// retrieve_tools - THE PRIMARY TOOL FOR DISCOVERING TOOLS - Enhanced with clear instructions
1345
1345
retrieveToolsOpts:= []mcp.ToolOption{
1346
-
mcp.WithDescription("🔍 CALL THIS FIRST to discover relevant tools! This is the primary tool discovery mechanism that searches across ALL upstream MCP servers using intelligent BM25 full-text search. Always use this before attempting to call any specific tools. Use natural language to describe what you want to accomplish (e.g., 'create GitHub repository', 'query database', 'weather forecast'). Results include 'annotations' (tool behavior hints like destructiveHint) and 'call_with' recommendation indicating which tool variant to use (call_tool_read/write/destructive). Then use the recommended variant with an 'intent' parameter. Compact mode returns one-line signatures ('sig': '*'=required, '~'=lossy) with first-sentence 'desc'; call describe_tool for full schemas. NOTE: Quarantined servers are excluded from search results for security. Use 'quarantine_security' tool to examine and manage quarantined servers. TO ADD NEW SERVERS: Use 'list_registries' then 'search_servers' to find and add new MCP servers."+retrieveToolsReachNote+retrieveToolsDiagnosticsNote),
1346
+
mcp.WithDescription("🔍 CALL THIS FIRST to discover relevant tools! This is the primary tool discovery mechanism that searches across ALL upstream MCP servers using intelligent BM25 full-text search. Always use this before attempting to call any specific tools. Use natural language to describe what you want to accomplish (e.g., 'create GitHub repository', 'query database', 'weather forecast'). Follow each result's call_with route exactly; upstream annotations determine that route and take precedence over tool names, descriptions, command text, and requested outcome. Compact results preserve the same call_with route as full results, including the existing read fallback when upstream tier annotations are unavailable. Never infer a route from a tool's name or intent. Compact mode returns one-line signatures ('sig': '*'=required, '~'=lossy) with first-sentence 'desc'; call describe_tool for full schemas. NOTE: Quarantined servers are excluded from search results for security. Use 'quarantine_security' tool to examine and manage quarantined servers. TO ADD NEW SERVERS: Use 'list_registries' then 'search_servers' to find and add new MCP servers."+retrieveToolsReachNote+retrieveToolsDiagnosticsNote),
usageInstructions="TOOL SELECTION GUIDE: Use each result's 'call_with' value as the exact variant to call (call_tool_read, call_tool_write, or call_tool_destructive). The route comes from upstream annotations and overrides tool names, descriptions, command wording, and apparent user intent. When no upstream tier annotations exist, call_with preserves the existing read fallback; do not infer a different route from tool names or intent. "+
2447
2444
"INTENT TRACKING: Always provide intent_reason (why you're calling this tool) and intent_data_sensitivity (public/internal/private/unknown) to enable activity auditing."
Copy file name to clipboardExpand all lines: internal/server/mcp_entry_builder.go
+29-6Lines changed: 29 additions & 6 deletions
Original file line number
Diff line number
Diff line change
@@ -15,7 +15,7 @@ import (
15
15
// "hint") to every compact-mode retrieve_tools response (Spec 085 FR-009).
16
16
// It explains the lossy marker and the describe_tool second stage; being part
17
17
// of the serialized payload it counts toward every measured response size.
18
-
constcompactModeHint="sig legend: name*:type = required param, ~ = collapsed/lossy (details omitted), (~) = schema unavailable. Before calling a tool whose entry is lossy:true, call describe_tool with its id to get the full input schema."
18
+
constcompactModeHint="sig legend: name*:type = required param, ~ = collapsed/lossy (details omitted), (~) = schema unavailable. Follow the call_with route exactly; it matches the full tool result, including the existing read fallback when no tier annotations are available. Never infer a route from the name, description, command text, or requested outcome. Before calling a lossy entry, call describe_tool for its full input schema."
19
19
20
20
// toolEntryOpts carries the per-request options that shape one retrieve_tools
21
21
// result entry (Spec 085 entry-builder seam, research.md R5).
@@ -47,8 +47,9 @@ type toolEntryOpts struct {
47
47
// built inline before the extraction — byte-identical under
48
48
// json.Marshal, guarded by the T011 golden test (FR-006/SC-003).
0 commit comments