Improve MCP tool selection guidance

This commit is contained in:
Mikei386
2026-08-21 20:34:40 +02:00
parent 6f14f62dd1
commit a194a2941d
8 changed files with 184 additions and 31 deletions
+19
View File
@@ -19,6 +19,25 @@ Prompts heraus, verhindert den früher beobachteten Kontextverbrauch von über
TinySearch und SearXNG sind interne Abhängigkeiten des Web-MCPs und werden
nicht direkt als allgemeine Werkzeuge angeboten.
## Entscheidungshilfe für das Modell
Die Server- und Werkzeugbeschreibungen grenzen die Zuständigkeiten absichtlich
deutlich voneinander ab. Das Modell soll pro Aufgabe zunächst genau **einen**
passenden Server wählen:
| Aufgabe | Werkzeugserver | Nicht zusätzlich verwenden |
|---|---|---|
| Aktuelle öffentliche Informationen, Quellen, GitHub/Hugging Face, Produkte | Web | HA, ARR, Unraid |
| Entitäten, Zustände, Historie, Automationen und Dashboards | Home Assistant | Web, Unraid |
| Serien, Filme, fehlende Episoden und Indexer-Releases | Sonarr und Radarr | Web |
| Lesende NAS-, Docker-, Array-, Netzwerk- und Logdiagnose | Unraid (Systemdiagnose) | MUA |
| Ausdrücklich benötigte MUA-Verwaltungsaktion | MUA | Unraid-Diagnose nicht parallel |
Ein leeres Ergebnis ist kein Grund, dieselbe Frage über mehrere unpassende
Werkzeuge oder leicht veränderte Suchbegriffe erneut auszuführen. Das Modell
soll die Grenze transparent nennen und gezielt nachfragen, wenn eine Freigabe
oder ein anderes Werkzeug benötigt wird.
## Sicherheitsmodell
- Kein MCP-Port wird auf eine Host-Adresse veröffentlicht.
+3
View File
@@ -92,6 +92,9 @@ services:
# The local fork adds bounded read-only Sonarr pseudo-actions. Keep the
# patch explicit until upstream publishes a self-contained 2.x image.
- ${ARR_SONARR_PATCH:-./patches/mcp_sonarr.py}:/usr/local/lib/python3.13/site-packages/arr_mcp/mcp/mcp_sonarr.py:ro
# Upstream's generic "Execute any Radarr API action" text gives small
# models no routing boundary. This overlay changes guidance only.
- ${ARR_RADARR_PATCH:-./patches/mcp_radarr.py}:/usr/local/lib/python3.13/site-packages/arr_mcp/mcp/mcp_radarr.py:ro
networks: [tools, egress]
mcp-unraid-official:
+38
View File
@@ -0,0 +1,38 @@
"""Radarr action-routed MCP tool with model-oriented routing guidance."""
import json
from typing import Any
from agent_utilities.mcp_utilities import dispatch, run_blocking
from fastmcp import FastMCP
from pydantic import Field
from arr_mcp.auth import get_radarr_client
def register_radarr_tools(mcp: FastMCP) -> None:
@mcp.tool(tags={"radarr"})
async def radarr_action(
action: str = Field(
description=(
"Choose one Radarr operation. Common read choices include get_movie for the "
"movie library and get_system_status/get_health for Radarr diagnostics. Use "
"list_actions only when an unusual Radarr operation is genuinely required. "
"Never guess a modifying action and never change Radarr without explicit user approval."
)
),
params_json: str = Field(
default="{}",
description=(
"JSON object encoded as a string containing only parameters required by the "
"selected Radarr action. Use \"{}\" for actions without parameters; never "
"invent movie IDs, paths, profile IDs or monitoring settings."
),
),
) -> Any:
"""USE ONLY for movies managed by Radarr: inspect the movie library, wanted/queue/history state, releases, profiles, or Radarr health. DO NOT use for TV episodes (use Sonarr), public-web research, media playback, filesystem copying, or direct downloads. Prefer read actions; any mutation requires explicit user approval."""
client = get_radarr_client()
kwargs = {k: v for k, v in json.loads(params_json).items() if v is not None}
return await run_blocking(
dispatch, client, action, kwargs, service="arr-radarr"
)
+3 -3
View File
@@ -411,14 +411,14 @@ def register_sonarr_tools(mcp: FastMCP) -> None:
@mcp.tool(tags={"sonarr"})
async def sonarr_action(
action: str = Field(
description="Sonarr action. Read with find_series {query}, get_season_summary {series_id, season_number}, or search_releases {series_id, season_number}. To download missing episodes, first call preview_episode_search {series_id, season_number, episode_numbers:[2,3,...]}, show its exact preview to the user, then only after explicit approval call start_episode_search with the same scope plus confirm:true and approval_ticket. Monitoring is never changed."
description="Choose one Sonarr operation. Normal choices: find_series to resolve a TV-series name; get_season_summary to list present/missing episodes; search_releases to query Sonarr's configured indexers without downloading; preview_episode_search before any download search; start_episode_search only after the user explicitly approves that exact preview. Use list_actions only for an unusual read operation."
),
params_json: str = Field(
default="{}",
description="JSON string of parameters to pass to the action.",
description="JSON object encoded as a string. Common forms: find_series {\"query\":\"Title\"}; get_season_summary/search_releases {\"series_id\":123,\"season_number\":2}; preview_episode_search {\"series_id\":123,\"season_number\":2,\"episode_numbers\":[2,3]}. For start_episode_search reuse the exact preview scope and add confirm:true plus approval_ticket.",
),
) -> Any:
"""Query Sonarr through a server-side allowlist (read-only by default; write actions when ARR_MCP_WRITE=1)."""
"""USE ONLY for TV-series tasks managed by Sonarr: identify a series, inspect missing episodes, search configured indexers, or start an explicitly approved missing-episode search. DO NOT use for movies (use Radarr), public-web research, media playback, filesystem copying, or direct URL downloads. Read-only by default; monitoring is never changed."""
if action in {"list_actions", "help", "actions"}:
return {
"service": "sonarr",