mirror of
https://github.com/usestrix/strix.git
synced 2026-09-11 22:51:18 +00:00
fix(mcp): k8s_enumerate even distribution + load_skill summary paragraphs
- k8s_enumerate: distribute max_urls evenly across namespaces instead of truncating first namespaces. Remove cross-product from short_forms. - load_skill: summary_only now returns title + first paragraph (up to 500 chars) instead of just the # heading line. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
86780fa89c
commit
94e4e997d3
3 changed files with 28 additions and 22 deletions
|
|
@ -489,11 +489,22 @@ def register_tools(mcp: FastMCP, sandbox: SandboxManager) -> None:
|
|||
result["failed_skills"] = failed
|
||||
|
||||
if summary_only:
|
||||
# Return just names and first-line descriptions
|
||||
result["skill_summaries"] = {
|
||||
name: content.split("\n", 1)[0][:200]
|
||||
for name, content in loaded_content.items()
|
||||
}
|
||||
# Return title + first non-empty paragraph for context
|
||||
summaries: dict[str, str] = {}
|
||||
for name, content in loaded_content.items():
|
||||
lines = content.strip().splitlines()
|
||||
summary_parts: list[str] = []
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if not stripped:
|
||||
if summary_parts and not summary_parts[-1].startswith("#"):
|
||||
break # end of first paragraph
|
||||
continue
|
||||
summary_parts.append(stripped)
|
||||
if len(summary_parts) >= 4:
|
||||
break
|
||||
summaries[name] = " ".join(summary_parts)[:500]
|
||||
result["skill_summaries"] = summaries
|
||||
else:
|
||||
# Apply max_content_length: truncate largest skills first
|
||||
total_len = sum(len(c) for c in loaded_content.values())
|
||||
|
|
|
|||
|
|
@ -1304,28 +1304,22 @@ def register_analysis_tools(mcp: FastMCP, sandbox: SandboxManager) -> None:
|
|||
total += 1
|
||||
by_namespace[ns] = urls
|
||||
|
||||
# Also generate short-form names for targets that resolve short names
|
||||
# Also generate short-form names (service only, no namespace cross-product)
|
||||
short_forms: list[str] = []
|
||||
for svc in service_ports:
|
||||
short_forms.append(f"{scheme}://{svc}")
|
||||
for ns in ns_list:
|
||||
short_forms.append(f"{scheme}://{svc}.{ns}")
|
||||
|
||||
# Cap output
|
||||
# Cap output — distribute evenly across namespaces
|
||||
omitted = 0
|
||||
if total > max_urls:
|
||||
per_ns = max(max_urls // len(by_namespace), 1)
|
||||
new_total = 0
|
||||
for ns in by_namespace:
|
||||
if total <= max_urls:
|
||||
break
|
||||
excess = total - max_urls
|
||||
if excess >= len(by_namespace[ns]):
|
||||
total -= len(by_namespace[ns])
|
||||
omitted += len(by_namespace[ns])
|
||||
by_namespace[ns] = []
|
||||
else:
|
||||
by_namespace[ns] = by_namespace[ns][:-excess]
|
||||
omitted += excess
|
||||
total -= excess
|
||||
if len(by_namespace[ns]) > per_ns:
|
||||
omitted += len(by_namespace[ns]) - per_ns
|
||||
by_namespace[ns] = by_namespace[ns][:per_ns]
|
||||
new_total += len(by_namespace[ns])
|
||||
total = new_total
|
||||
|
||||
result: dict[str, Any] = {
|
||||
"total_urls": total,
|
||||
|
|
|
|||
|
|
@ -546,9 +546,10 @@ class TestLoadSkillTool:
|
|||
assert "skill_summaries" in result
|
||||
assert "idor" in result["skill_summaries"]
|
||||
assert "xss" in result["skill_summaries"]
|
||||
# Summaries should be short strings (first line)
|
||||
# Summaries should include title + first paragraph (up to 500 chars)
|
||||
for summary in result["skill_summaries"].values():
|
||||
assert len(summary) <= 200
|
||||
assert len(summary) <= 500
|
||||
assert len(summary) > 10 # not just empty
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_max_content_length_no_truncation_when_under(self, mcp_no_scan):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue