test_kestra_mcp_stdio.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import json
  2. import os
  3. import subprocess
  4. from pathlib import Path
  5. import pytest
  6. ROOT = Path(__file__).resolve().parents[2]
  7. COMPOSE = ROOT / "deploy/docker/docker-compose.yml"
  8. pytestmark = pytest.mark.skipif(
  9. os.getenv("KESTRA_INTEGRATION") != "1",
  10. reason="set KESTRA_INTEGRATION=1 for the local Kestra MCP contract",
  11. )
  12. def test_kestra_mcp_stdio_initializes_and_exposes_only_governed_groups():
  13. messages = [
  14. {
  15. "jsonrpc": "2.0",
  16. "id": 1,
  17. "method": "initialize",
  18. "params": {
  19. "protocolVersion": "2025-06-18",
  20. "capabilities": {},
  21. "clientInfo": {"name": "dataops-v51", "version": "1.0"},
  22. },
  23. },
  24. {
  25. "jsonrpc": "2.0",
  26. "method": "notifications/initialized",
  27. "params": {},
  28. },
  29. {"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}},
  30. ]
  31. payload = "\n".join(
  32. json.dumps(message, separators=(",", ":")) for message in messages
  33. ) + "\n"
  34. result = subprocess.run(
  35. [
  36. "docker",
  37. "compose",
  38. "-f",
  39. str(COMPOSE),
  40. "--profile",
  41. "kestra-mcp",
  42. "run",
  43. "--rm",
  44. "-T",
  45. "--no-deps",
  46. "kestra-mcp",
  47. ],
  48. cwd=ROOT,
  49. input=payload,
  50. check=True,
  51. capture_output=True,
  52. text=True,
  53. timeout=60,
  54. )
  55. responses = {
  56. item["id"]: item
  57. for line in result.stdout.splitlines()
  58. if line.strip()
  59. for item in [json.loads(line)]
  60. if "id" in item
  61. }
  62. assert responses[1]["result"]["serverInfo"]["name"]
  63. tools = responses[2]["result"]["tools"]
  64. assert tools
  65. names = {tool["name"] for tool in tools}
  66. assert any("flow" in name for name in names)
  67. assert any("execution" in name for name in names)
  68. for forbidden in ("namespace_file", "kv_", "tenant", "auditlog"):
  69. assert not any(forbidden in name for name in names)