Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion tools/mcp_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,26 @@ def _make_tool_handler(server_name: str, tool_name: str, tool_timeout: float):
``handler(args_dict, **kwargs) -> str``
"""

def _coerce_json_strings(args: dict) -> dict:
"""Coerce string values that are valid JSON into native types.

LLMs sometimes emit array/bool/number params as JSON-encoded strings.
MCP servers validate against inputSchema and reject string where array/bool/int expected.
"""
coerced = {}
for k, v in args.items():
if isinstance(v, str):
try:
parsed = json.loads(v)
# Only coerce if result is a non-string type (list, dict, bool, int, float)
if not isinstance(parsed, str):
coerced[k] = parsed
continue
except (json.JSONDecodeError, ValueError):
pass
coerced[k] = v
return coerced

def _handler(args: dict, **kwargs) -> str:
with _lock:
server = _servers.get(server_name)
Expand All @@ -1018,7 +1038,7 @@ def _handler(args: dict, **kwargs) -> str:
})

async def _call():
result = await server.session.call_tool(tool_name, arguments=args)
result = await server.session.call_tool(tool_name, arguments=_coerce_json_strings(args))
# MCP CallToolResult has .content (list of content blocks) and .isError
if result.isError:
error_text = ""
Expand Down Expand Up @@ -1469,6 +1489,19 @@ def _select_utility_schemas(server_name: str, server: MCPServerTask, config: dic
required_method,
)
continue
# Some servers (e.g. gitmcp) have the method on the session object but
# return "Method not found" at the transport layer. Only register if
# the server advertises the capability in its server_info.
server_info = getattr(server.session, "server_info", None) or getattr(server, "_server_info", None)
if server_info is not None:
capabilities = getattr(server_info, "capabilities", None) or {}
if isinstance(capabilities, dict):
if handler_key in {"list_resources", "read_resource"} and not capabilities.get("resources"):
logger.debug("MCP server '%s': skipping '%s' (server capabilities missing 'resources')", server_name, handler_key)
continue
if handler_key in {"list_prompts", "get_prompt"} and not capabilities.get("prompts"):
logger.debug("MCP server '%s': skipping '%s' (server capabilities missing 'prompts')", server_name, handler_key)
continue
selected.append(entry)
return selected

Expand Down
Loading