fix(gns-2): replace Basic Auth password with Bearer PAT for MCP
This commit is contained in:
143
scripts/test-kilo-mcp-integration.py
Normal file
143
scripts/test-kilo-mcp-integration.py
Normal file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
test-kilo-mcp-integration.py
|
||||
Тест интеграции MCP через mcp_settings.json (legacy Kilo Code path).
|
||||
Проверяет конечную цепочку: mcp_settings.json → stdio bridge → forgejo-mcp → Gitea API
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
MCP_SETTINGS_PATH = os.path.expanduser(
|
||||
"~/.config/Code/User/globalStorage/kilocode.kilo-code/settings/mcp_settings.json"
|
||||
)
|
||||
|
||||
STDIO_SCRIPT = "/home/swp/Projects/APAW/scripts/mcp-gitea-stdio.cjs"
|
||||
|
||||
def load_settings():
|
||||
if not os.path.exists(MCP_SETTINGS_PATH):
|
||||
raise FileNotFoundError(f"MCP settings not found: {MCP_SETTINGS_PATH}")
|
||||
with open(MCP_SETTINGS_PATH) as f:
|
||||
return json.load(f)
|
||||
|
||||
def validate_settings(data):
|
||||
assert "mcpServers" in data, "Missing mcpServers key"
|
||||
assert "forgejo-gitea" in data["mcpServers"], "Missing forgejo-gitea server"
|
||||
srv = data["mcpServers"]["forgejo-gitea"]
|
||||
assert "command" in srv, "Missing command"
|
||||
assert "args" in srv, "Missing args"
|
||||
assert "env" in srv, "Missing env"
|
||||
print(f"✅ Settings valid: command={srv['command']}, args={srv['args']}")
|
||||
return srv
|
||||
|
||||
def test_stdio_rpc(server_config):
|
||||
print("\n[1] Initialize stdio bridge...")
|
||||
env = {**os.environ, **server_config.get("env", {})}
|
||||
cmd = [server_config["command"]] + server_config["args"]
|
||||
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
env=env,
|
||||
cwd="/home/swp/Projects/APAW",
|
||||
)
|
||||
|
||||
def send(method, params=None, call_id=1):
|
||||
req = json.dumps({"jsonrpc": "2.0", "method": method, "params": params or {}, "id": call_id}) + "\n"
|
||||
proc.stdin.write(req)
|
||||
proc.stdin.flush()
|
||||
|
||||
def recv():
|
||||
line = proc.stdout.readline()
|
||||
return json.loads(line) if line.strip() else None
|
||||
|
||||
# initialize
|
||||
send("initialize", {
|
||||
"protocolVersion": "2024-11-05",
|
||||
"capabilities": {},
|
||||
"clientInfo": {"name": "test-kilo-mcp", "version": "1.0"}
|
||||
}, 1)
|
||||
resp = recv()
|
||||
assert resp and "result" in resp, f"Initialize failed: {resp}"
|
||||
print("✅ Initialize OK")
|
||||
|
||||
# tools/list
|
||||
send("tools/list", {}, 2)
|
||||
resp = recv()
|
||||
tools = resp.get("result", {}).get("tools", [])
|
||||
assert len(tools) > 50, f"Expected >50 tools, got {len(tools)}"
|
||||
print(f"✅ Tools: {len(tools)}")
|
||||
|
||||
# get_issue #110
|
||||
print("\n[2] Call get_issue #110...")
|
||||
send("tools/call", {
|
||||
"name": "get_issue",
|
||||
"arguments": {"owner": "UniqueSoft", "repo": "APAW", "index": 110}
|
||||
}, 3)
|
||||
resp = recv()
|
||||
print(f" Raw resp keys: {list(resp.keys())}")
|
||||
content_arr = resp.get("result", {}).get("content", [])
|
||||
print(f" Content array len: {len(content_arr)}")
|
||||
if content_arr:
|
||||
content_text = content_arr[0].get("text", "")
|
||||
print(f" Content text len: {len(content_text)}")
|
||||
if not content_text:
|
||||
# fallback: parse result directly
|
||||
content_text = json.dumps(resp.get("result", {}))
|
||||
else:
|
||||
content_text = json.dumps(resp.get("result", {}))
|
||||
assert content_text, "Empty content"
|
||||
issue = json.loads(content_text) if content_text.startswith("{") else {"raw": content_text}
|
||||
if "number" not in issue:
|
||||
# direct result without wrapper
|
||||
issue = resp.get("result", {})
|
||||
assert issue.get("number") == 110, f"Unexpected issue: {issue}"
|
||||
print(f"✅ Issue #{issue['number']} - {issue.get('title', 'N/A')}")
|
||||
|
||||
# checkpoint
|
||||
print("\n[3] Verify checkpoint in body...")
|
||||
assert "## GNS Checkpoint" in (issue.get("body") or ""), "No checkpoint"
|
||||
print("✅ Checkpoint present")
|
||||
|
||||
# budget/depth check
|
||||
print("\n[4] Extract checkpoint YAML...")
|
||||
body = issue.get("body", "")
|
||||
import re
|
||||
match = re.search(r"```yaml\n(.*?)\n```", body, re.S)
|
||||
assert match, "No YAML block in issue body"
|
||||
yaml_block = match.group(1)
|
||||
assert "budget:" in yaml_block, "No budget in checkpoint"
|
||||
assert "depth:" in yaml_block, "No depth in checkpoint"
|
||||
print("✅ Budget and depth found in checkpoint")
|
||||
|
||||
proc.stdin.close()
|
||||
proc.wait(timeout=5)
|
||||
print("✅ Stdio bridge closed cleanly")
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("Kilo Code MCP Integration Test")
|
||||
print("=" * 60)
|
||||
print(f"Settings path: {MCP_SETTINGS_PATH}")
|
||||
|
||||
try:
|
||||
data = load_settings()
|
||||
srv = validate_settings(data)
|
||||
test_stdio_rpc(srv)
|
||||
print("\n" + "=" * 60)
|
||||
print("✅ ALL KILO MCP INTEGRATION TESTS PASSED")
|
||||
print("=" * 60)
|
||||
return 0
|
||||
except Exception as e:
|
||||
print(f"\n❌ FAILED: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user