diff --git a/directory/crawlers.py b/directory/crawlers.py index a766ff3..90cb262 100644 --- a/directory/crawlers.py +++ b/directory/crawlers.py @@ -1675,7 +1675,9 @@ def _mcp_parse_response(r): # Per-server caps so a padded multi-tool server can't bloat our row/index. -_MAX_TOOLS = 60 +# One hundred still bounds each row while avoiding silent capability loss for +# legitimate MCP servers whose tool inventories have grown beyond sixty. +_MAX_TOOLS = 100 _MAX_TOOL_DESC = 160 @@ -1687,7 +1689,9 @@ def _summarize_tools(tools: list) -> list: that exposes 24 tools is 24 discoverable capabilities, not one. """ out = [] - for t in tools[:_MAX_TOOLS]: + for t in tools: + if len(out) >= _MAX_TOOLS: + break if not isinstance(t, dict): continue name = str(t.get("name") or "").strip() diff --git a/tests/test_mcp_tool_summarization.py b/tests/test_mcp_tool_summarization.py new file mode 100644 index 0000000..f1098e6 --- /dev/null +++ b/tests/test_mcp_tool_summarization.py @@ -0,0 +1,30 @@ +import unittest + +from directory import crawlers + + +class McpToolSummarizationTests(unittest.TestCase): + def test_keeps_one_hundred_valid_capabilities_within_the_cap(self): + tools = [None, {"description": "missing a name"}] + tools.extend( + { + "name": f"tool-{index}", + "description": "x" * (crawlers._MAX_TOOL_DESC + 20), + } + for index in range(105) + ) + + summarized = crawlers._summarize_tools(tools) + + self.assertEqual(crawlers._MAX_TOOLS, 100) + self.assertEqual(len(summarized), 100) + self.assertEqual(summarized[0]["name"], "tool-0") + self.assertEqual(summarized[-1]["name"], "tool-99") + self.assertEqual( + summarized[0]["description"], + "x" * crawlers._MAX_TOOL_DESC + "…", + ) + + +if __name__ == "__main__": + unittest.main()