141 lines
4.2 KiB
Python
Executable File
141 lines
4.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
CI Tool Name Parity Check
|
|
|
|
Validates that MCP server tool names match the capability registry.
|
|
Fails CI if:
|
|
- A tool exists but isn't registered
|
|
- A registered tool no longer exists
|
|
"""
|
|
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def get_registry_tools():
|
|
"""Load tool names from capability registry."""
|
|
with open("capability_registry_v2.json", "r") as f:
|
|
registry = json.load(f)
|
|
|
|
registry_tools = {}
|
|
for server_name, server_info in registry["mcp_servers"].items():
|
|
# Extract base tool names (remove operation type)
|
|
tools = []
|
|
for tool_desc in server_info["tools"]:
|
|
tool_name = tool_desc.split(" (")[0] # Remove "(operation_type)"
|
|
tools.append(tool_name)
|
|
registry_tools[server_name] = set(tools)
|
|
|
|
return registry_tools
|
|
|
|
|
|
def get_actual_tools():
|
|
"""Get actual tool names from MCP servers by examining source code."""
|
|
actual_tools = {}
|
|
|
|
# Extract tools from Cloudflare Safe server source
|
|
try:
|
|
with open("mcp/cloudflare_safe/server.py", "r") as f:
|
|
content = f.read()
|
|
|
|
# Look for tool function definitions
|
|
import re
|
|
|
|
tool_pattern = r"def (cf_\w+)\("
|
|
tools_found = set(re.findall(tool_pattern, content))
|
|
|
|
# Filter out internal functions
|
|
valid_tools = {tool for tool in tools_found if not tool.startswith("_")}
|
|
actual_tools["cloudflare_safe"] = valid_tools
|
|
except Exception as e:
|
|
print(f"⚠️ Could not extract tools from cloudflare_safe: {e}")
|
|
|
|
# Extract tools from WAF Intelligence server source
|
|
try:
|
|
with open("mcp/waf_intelligence/mcp_server.py", "r") as f:
|
|
content = f.read()
|
|
|
|
tool_pattern = r"def (waf_\w+)\("
|
|
tools_found = set(re.findall(tool_pattern, content))
|
|
|
|
valid_tools = {tool for tool in tools_found if not tool.startswith("_")}
|
|
actual_tools["waf_intelligence"] = valid_tools
|
|
except Exception as e:
|
|
print(f"⚠️ Could not extract tools from waf_intelligence: {e}")
|
|
|
|
# Extract tools from Oracle Answer server source
|
|
try:
|
|
with open("mcp/oracle_answer/server.py", "r") as f:
|
|
content = f.read()
|
|
|
|
tool_pattern = r"def (\w+)\("
|
|
tools_found = set(re.findall(tool_pattern, content))
|
|
|
|
# Look for oracle_answer specifically
|
|
oracle_tools = {tool for tool in tools_found if "oracle" in tool.lower()}
|
|
actual_tools["oracle_answer"] = oracle_tools
|
|
except Exception as e:
|
|
print(f"⚠️ Could not extract tools from oracle_answer: {e}")
|
|
|
|
return actual_tools
|
|
|
|
|
|
def check_tool_parity():
|
|
"""Compare registry tools with actual tools."""
|
|
registry_tools = get_registry_tools()
|
|
actual_tools = get_actual_tools()
|
|
|
|
errors = []
|
|
|
|
for server_name in set(registry_tools.keys()) | set(actual_tools.keys()):
|
|
reg_tools = registry_tools.get(server_name, set())
|
|
act_tools = actual_tools.get(server_name, set())
|
|
|
|
# Check for tools in registry but not in actual
|
|
missing_in_actual = reg_tools - act_tools
|
|
if missing_in_actual:
|
|
errors.append(
|
|
f"❌ {server_name}: Tools registered but not found: {missing_in_actual}"
|
|
)
|
|
|
|
# Check for tools in actual but not in registry
|
|
missing_in_registry = act_tools - reg_tools
|
|
if missing_in_registry:
|
|
errors.append(
|
|
f"❌ {server_name}: Tools found but not registered: {missing_in_registry}"
|
|
)
|
|
|
|
# Report parity
|
|
if not missing_in_actual and not missing_in_registry:
|
|
print(f"✅ {server_name}: Tool parity verified ({len(reg_tools)} tools)")
|
|
|
|
return errors
|
|
|
|
|
|
def main():
|
|
"""Main CI check function."""
|
|
print("🔍 CI Tool Name Parity Check")
|
|
print("=" * 50)
|
|
|
|
errors = check_tool_parity()
|
|
|
|
if errors:
|
|
print("\n❌ Registry drift detected:")
|
|
for error in errors:
|
|
print(error)
|
|
print(
|
|
"\n💡 Fix: Update capability_registry_v2.json to match actual MCP server tools"
|
|
)
|
|
sys.exit(1)
|
|
else:
|
|
print("\n✅ All MCP server tools match capability registry")
|
|
sys.exit(0)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|