s14: MCP handler defaults can be overridden by tool input, bypassing host policy
Los mantenedores suelen responder en 8 días
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 72/100
Línea de trabajo
Empieza en s14_mcp_plugin/code.py alrededor de la línea 357, donde se construyen los handlers de MCP, y lee permission_hook para ver cómo mcp_tool_policies se indexa por el nombre con prefijo. Ejecuta el repro mínimo de FakeClient del issue para confirmar que una clave 'tool' en la entrada sobrescribe el valor por defecto. Se considera terminado cuando los kwargs en tiempo de llamada ya no pueden cambiar la herramienta enrutada y una llamada a status con una clave 'tool' extra es rechazada o no se enruta al trigger.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
In s14_mcp_plugin/code.py, MCP handlers are built like this (around line 357):
handlers[prefixed] = (
lambda *, client=server, tool=raw_name, **kwargs:
client.call_tool(tool, kwargs)
)
The default arguments fix the late-binding problem described in README §5. However, tool and client are still ordinary keyword parameters. If the model's tool input contains a "tool" key, it replaces the default. The call is then routed to a different server tool than the one that permission_hook checked.
Why it matters for this lesson
permission_hook looks up mcp_tool_policies by the prefixed name only. With the default MCP_HOST_POLICY, ("deploy", "status") is allow, and ("deploy", "trigger") is confirm. So this tool call:
{"name": "mcp__deploy__status", "input": {"service": "web", "tool": "trigger"}}
passes as status without asking the user. The deploy server then runs call_tool("trigger", {"service": "web"}) and returns [deploy] Triggered: web.
The model might send this input by mistake, or because content it read told it to. Lesson 6 says the host policy decides what runs, and this input gets around that policy. The input schema is not validated before dispatch, so the extra key is not rejected.
Minimal repro (no API key needed)
class FakeClient:
def call_tool(self, tool, args):
return f"server ran {tool!r} with {args}"
server = FakeClient()
handlers = {}
for raw_name in ["status", "trigger"]:
prefixed = f"mcp__deploy__{raw_name}"
handlers[prefixed] = (
lambda *, client=server, tool=raw_name, **kwargs:
client.call_tool(tool, kwargs)
)
print(handlers["mcp__deploy__status"](**{"service": "web", "tool": "trigger"}))
# server ran 'trigger' with {'service': 'web'}
I also reproduced this with the unmodified s14_mcp_plugin/code.py. I used a scripted fake Anthropic client that returns the tool call above. The status call ran trigger without a permission prompt.
Suggested fix
Bind the values in a closure so that call-time arguments cannot reach them:
def make_handler(client, tool):
return lambda **kwargs: client.call_tool(tool, kwargs)
handlers[prefixed] = make_handler(server, raw_name)
With this change, the same input calls status with an extra tool argument. The demo server's status function rejects that argument with MCP error: TypeError: ... unexpected keyword argument 'tool', and nothing is deployed. functools.partial would not fix this, because keyword arguments given at call time also override the keywords stored in a partial.
If you want a short line in the README, §5 could say that default arguments solve late binding but remain overridable by caller kwargs.
Thanks for the great course! I found this while building a Traditional Chinese walkthrough of it.
- Lenguaje dominante
- Python
- Estrellas
- 79.5k
- Forks
- 12.7k
- Merge medio
- 7 d 17 h
- PR fusionados (30 d)
- 4
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de shareAI-lab/learn-claude-code
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
shareAI-lab/learn-claude-code#583 ·
Los mantenedores suelen responder en 8 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
shareAI-lab/learn-claude-code#528 ·
Los mantenedores suelen responder en 8 días
-
s17: IDLE teammates cannot resume their own in-progress tasksPosiblemente ocupada @hichipli la tomó hace 66 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 84/100
shareAI-lab/learn-claude-code#519 ·
Los mantenedores suelen responder en 8 días
-
s09: select_relevant_memories 的 "recent" 拼接顺序与切片不合理,不是真正的最近 2k 上下文Posiblemente ocupada @siri666942 la tomó hace 84 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
shareAI-lab/learn-claude-code#517 ·
Los mantenedores suelen responder en 8 días
-
plan_approval_response 不会唤醒 idle teammateQuizá libre de nuevo Un pull request para esta issue se cerró sin fusionarse. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
shareAI-lab/learn-claude-code#455 ·
Los mantenedores suelen responder en 8 días
Todos los issues de shareAI-lab/learn-claude-code
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 69/100
jejjohnson/gaussx#752 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
521xueweihan/HelloGitHub#4270 ·
-
enhancement owner: den-haag
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
Los mantenedores suelen responder en 6 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
ok-oldking/ok-wuthering-waves#1828 ·
Los mantenedores suelen responder en 1 día
-
lesson-submission pending-review
Dificultad 1/5 Menos de una hora Aptitud para principiantes 65/100
Ikalus1988/MisakaNet#4512 ·
Los mantenedores suelen responder en 1 día