synapse-hub 0.0.0-stage → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/.agents/agents/failure-analyst.md +47 -0
  2. package/.agents/agents/live-explorer.md +41 -0
  3. package/.agents/agents/orchestrator.md +43 -0
  4. package/.agents/agents/pom-crafter.md +81 -0
  5. package/.agents/agents/quality-gatekeeper.md +47 -0
  6. package/.agents/agents/test-runner.md +43 -0
  7. package/.agents/rules/context-engineering.md +88 -0
  8. package/.agents/rules/git-push-protocol.md +101 -0
  9. package/.agents/rules/graphify.md +14 -0
  10. package/.agents/rules/lessons-learned.md +23 -0
  11. package/.agents/rules/mandatory-playwright-live.md +29 -0
  12. package/.agents/rules/skill-precedence.md +42 -0
  13. package/.agents/rules/systematic-debugging.md +99 -0
  14. package/.agents/skills/agent-orchestration-multi-agent-optimize/SKILL.md +239 -0
  15. package/.agents/skills/antigravity-test-sentinel/SKILL.md +64 -0
  16. package/.agents/skills/api-network-mocking-interception/SKILL.md +142 -0
  17. package/.agents/skills/api-spec-to-e2e-matrix/SKILL.md +70 -0
  18. package/.agents/skills/architecture-decision-records/SKILL.md +441 -0
  19. package/.agents/skills/auth-session-and-cookie-manager/SKILL.md +72 -0
  20. package/.agents/skills/backend-load-and-stress-patterns/SKILL.md +214 -0
  21. package/.agents/skills/bats-testing-patterns/SKILL.md +100 -0
  22. package/.agents/skills/bats-testing-patterns/resources/implementation-playbook.md +614 -0
  23. package/.agents/skills/clean-pom-crafter/SKILL.md +75 -0
  24. package/.agents/skills/clean-pom-crafter/examples/standard_test_case.groovy +28 -0
  25. package/.agents/skills/clean-pom-crafter/references/pom_patterns.groovy +138 -0
  26. package/.agents/skills/code-refactoring-refactor-clean/SKILL.md +64 -0
  27. package/.agents/skills/code-refactoring-refactor-clean/resources/implementation-playbook.md +879 -0
  28. package/.agents/skills/db-state-verifier-and-seeder/SKILL.md +123 -0
  29. package/.agents/skills/e2e-testing-patterns/SKILL.md +103 -0
  30. package/.agents/skills/e2e-testing-patterns/resources/implementation-playbook.md +522 -0
  31. package/.agents/skills/failure-autopsy-and-healing/SKILL.md +54 -0
  32. package/.agents/skills/failure-autopsy-and-healing/references/healing_matrix.md +64 -0
  33. package/.agents/skills/failure-autopsy-and-healing/references/qa_investigation_protocol.md +56 -0
  34. package/.agents/skills/failure-autopsy-and-healing/scripts/triage_failures.sh +98 -0
  35. package/.agents/skills/file-and-report-validator/SKILL.md +90 -0
  36. package/.agents/skills/flaky-test-sentinel-and-quarantine/SKILL.md +114 -0
  37. package/.agents/skills/github-actions-templates/SKILL.md +334 -0
  38. package/.agents/skills/graphify-impact-analyzer/SKILL.md +78 -0
  39. package/.agents/skills/katalon-cli-runner/SKILL.md +76 -0
  40. package/.agents/skills/katalon-cli-runner/references/groovy-patterns.md +209 -0
  41. package/.agents/skills/katalon-cli-runner/references/katalon-api.md +155 -0
  42. package/.agents/skills/katalon-cli-runner/references/runner_commands.md +67 -0
  43. package/.agents/skills/lam-script-generator/SKILL.md +83 -0
  44. package/.agents/skills/playwright-live-interaction/SKILL.md +86 -0
  45. package/.agents/skills/playwright-live-interaction/references/advanced_superpowers.md +160 -0
  46. package/.agents/skills/playwright-live-interaction/references/compact_accessibility_snapshots.md +75 -0
  47. package/.agents/skills/playwright-live-interaction/references/recipes.md +388 -0
  48. package/.agents/skills/playwright-live-interaction/references/swarm_orchestration.md +134 -0
  49. package/.agents/skills/security-dast-sentinel/SKILL.md +176 -0
  50. package/.agents/skills/self-healing-locator/SKILL.md +73 -0
  51. package/.agents/skills/synthetic-test-data-generator/SKILL.md +135 -0
  52. package/.agents/skills/token-and-context-optimizer/SKILL.md +70 -0
  53. package/.agents/skills/visual-regression-sentinel/SKILL.md +62 -0
  54. package/.agents/skills/wcag-audit-patterns/SKILL.md +77 -0
  55. package/.agents/skills/wcag-audit-patterns/resources/implementation-playbook.md +541 -0
  56. package/.agents/skills/web-vitals-and-performance-profiler/SKILL.md +65 -0
  57. package/.agents/templates/completion_report.md +57 -0
  58. package/.agents/workflows/graphify.md +10 -0
  59. package/.agents/workflows/test-impact.md +15 -0
  60. package/.agents/workflows/verify.md +34 -0
  61. package/AGENTS.md +115 -0
  62. package/README.md +394 -2
  63. package/bin/agent-qa.js +90 -0
  64. package/package.json +59 -4
  65. package/skills_manifest.json +262 -0
  66. package/templates/PROJECT_AI_GUIDE_TEMPLATE.md +97 -0
  67. package/templates/PROJECT_STATE_TEMPLATE.md +20 -0
  68. package/tools/TOOLS_RUNBOOK.md +298 -0
  69. package/tools/agent_canary.py +501 -0
  70. package/tools/analyze_project.py +242 -0
  71. package/tools/api_drift_sentinel.py +208 -0
  72. package/tools/auto_heal.py +189 -0
  73. package/tools/browser_helpers.js +593 -0
  74. package/tools/bug_reporter.py +224 -0
  75. package/tools/cache_resolver.py +846 -0
  76. package/tools/check_env.py +288 -0
  77. package/tools/ci_healing_hook.py +128 -0
  78. package/tools/cli.py +402 -0
  79. package/tools/config_decoupler.py +253 -0
  80. package/tools/db_sandbox.py +341 -0
  81. package/tools/distill_log.py +152 -0
  82. package/tools/e2e_flow_prober.ps1 +65 -0
  83. package/tools/flaky_detector.py +222 -0
  84. package/tools/fuzz_payloads.py +197 -0
  85. package/tools/generate_allure_report.ps1 +30 -0
  86. package/tools/generate_api_matrix.py +193 -0
  87. package/tools/generate_tc_from_story.py +182 -0
  88. package/tools/generate_test_reports.ps1 +135 -0
  89. package/tools/git_pre_commit_guard.py +203 -0
  90. package/tools/heal_pr_automator.py +195 -0
  91. package/tools/heuristic_locator_matcher.py +202 -0
  92. package/tools/infer_linter.py +238 -0
  93. package/tools/lint_ai_docs.py +254 -0
  94. package/tools/lookup_tc.py +165 -0
  95. package/tools/lookup_xpath.py +167 -0
  96. package/tools/matrix_sharder.py +146 -0
  97. package/tools/mcp_excel_server.ps1 +251 -0
  98. package/tools/mcp_server.py +490 -0
  99. package/tools/micro_mutator.py +309 -0
  100. package/tools/network_mock_shield.py +170 -0
  101. package/tools/omni_emitter.py +500 -0
  102. package/tools/omni_parser.py +435 -0
  103. package/tools/omni_transpiler.py +168 -0
  104. package/tools/pinpoint_failure.py +88 -0
  105. package/tools/project_state.py +169 -0
  106. package/tools/repo_map.json +12 -0
  107. package/tools/repo_map.py +277 -0
  108. package/tools/repo_map.txt +7 -0
  109. package/tools/safety_firewall.py +245 -0
  110. package/tools/setup_project.py +265 -0
  111. package/tools/smart_visual_masker.py +134 -0
  112. package/tools/test_impact.py +321 -0
  113. package/tools/tms_sync_bridge.py +342 -0
  114. package/tools/trace_data_flow.py +240 -0
  115. package/tools/traffic_session_converter.py +256 -0
  116. package/tools/universal_ir.py +480 -0
  117. package/tools/validate_groovy_scripts.py +173 -0
  118. package/tools/verify_all.py +496 -0
  119. package/tools/verify_all.sh +4 -0
  120. package/tools/visual_diff_canvas.py +142 -0
  121. package/tools/visual_som_helper.py +418 -0
  122. package/tools/wcag_audit.py +214 -0
@@ -0,0 +1,490 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Enterprise Model Context Protocol (MCP) Standard Server
4
+ -------------------------------------------------------
5
+ Exposes centralized tools/ capabilities as standardized JSON-RPC 2.0 MCP Tools
6
+ compatible with Google Antigravity, Cursor, Claude Desktop, Windsurf, and any MCP client.
7
+ Communicates via standard JSON-RPC stdio.
8
+ """
9
+
10
+ import os
11
+ import sys
12
+ import json
13
+ import traceback
14
+ from typing import Dict, Any, List
15
+
16
+ # Enforce UTF-8 stdio encoding
17
+ if hasattr(sys.stdout, 'reconfigure'):
18
+ try:
19
+ sys.stdout.reconfigure(encoding='utf-8')
20
+ sys.stderr.reconfigure(encoding='utf-8')
21
+ sys.stdin.reconfigure(encoding='utf-8')
22
+ except Exception:
23
+ pass
24
+
25
+ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
26
+ HUB_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
27
+ sys.path.insert(0, SCRIPT_DIR)
28
+
29
+ import verify_all
30
+ import analyze_project
31
+ import setup_project
32
+ import auto_heal
33
+ import safety_firewall
34
+ import api_drift_sentinel
35
+ import cache_resolver
36
+ import distill_log
37
+ import micro_mutator
38
+ import heal_pr_automator
39
+ import matrix_sharder
40
+ import tms_sync_bridge
41
+ import db_sandbox
42
+ import traffic_session_converter
43
+ import visual_som_helper
44
+
45
+ SERVER_NAME = "enterprise-agent-qa"
46
+ SERVER_VERSION = "2.0.0"
47
+
48
+ MCP_TOOLS = [
49
+ {
50
+ "name": "verify_all_gates",
51
+ "description": "Validates the 8 Quality Gates Definition of Done (UTF-8, paths, Clean POM, AI docs, blacklist, security, infer linter, micro-mutator).",
52
+ "inputSchema": {
53
+ "type": "object",
54
+ "properties": {
55
+ "repo_path": {"type": "string", "description": "Absolute or relative path to the target repository. Defaults to CWD."}
56
+ }
57
+ }
58
+ },
59
+ {
60
+ "name": "analyze_project",
61
+ "description": "Executes 5-in-1 project health and AST intelligence analysis, creating PROJECT_HEALTH_REPORT.md and repo_map.txt.",
62
+ "inputSchema": {
63
+ "type": "object",
64
+ "properties": {
65
+ "repo_path": {"type": "string", "description": "Target project repository directory to audit."}
66
+ }
67
+ }
68
+ },
69
+ {
70
+ "name": "setup_project",
71
+ "description": "Autonomous 1-click bootstrap of any test project: detects stack, generates PROJECT_AI_GUIDE.md, installs Git hook, and maps AST.",
72
+ "inputSchema": {
73
+ "type": "object",
74
+ "properties": {
75
+ "repo_path": {"type": "string", "description": "Path to target project to bootstrap."}
76
+ }
77
+ }
78
+ },
79
+ {
80
+ "name": "auto_heal_failure",
81
+ "description": "Diagnoses test failures in 0.1s from JUnit XML and queries semantic memory cache for proven patches.",
82
+ "inputSchema": {
83
+ "type": "object",
84
+ "properties": {
85
+ "target_dir": {"type": "string", "description": "Target project root directory."},
86
+ "junit_xml_path": {"type": "string", "description": "Optional direct path to failing JUnit XML report."}
87
+ }
88
+ }
89
+ },
90
+ {
91
+ "name": "check_action_safety",
92
+ "description": "Action Safety Firewall: verifies whether an intended UI action (click, fill) touches destructive elements (Delete, Pay, Drop).",
93
+ "inputSchema": {
94
+ "type": "object",
95
+ "properties": {
96
+ "action_type": {"type": "string", "description": "Action type (e.g. click, fill, submit)."},
97
+ "element_text": {"type": "string", "description": "Text or label of target DOM element."},
98
+ "selector": {"type": "string", "description": "CSS or XPath selector of element."},
99
+ "force": {"type": "boolean", "description": "Force bypass firewall."}
100
+ }
101
+ }
102
+ },
103
+ {
104
+ "name": "check_contract_drift",
105
+ "description": "Compares two OpenAPI / Swagger specifications and detects breaking changes (removed endpoints, changed types, newly required params).",
106
+ "inputSchema": {
107
+ "type": "object",
108
+ "properties": {
109
+ "old_spec_path": {"type": "string", "description": "Path to baseline OpenAPI JSON file."},
110
+ "new_spec_path": {"type": "string", "description": "Path to current OpenAPI JSON file."}
111
+ },
112
+ "required": ["old_spec_path", "new_spec_path"]
113
+ }
114
+ },
115
+ {
116
+ "name": "query_memory_cache",
117
+ "description": "Queries the 0-token SQLite semantic memory cache for known UI exceptions and proven repair patches.",
118
+ "inputSchema": {
119
+ "type": "object",
120
+ "properties": {
121
+ "error_signature": {"type": "string", "description": "Exception trace or error message to lookup."}
122
+ },
123
+ "required": ["error_signature"]
124
+ }
125
+ },
126
+ {
127
+ "name": "distill_log",
128
+ "description": "Filters verbose CLI or Gradle build logs by 95%, retaining only actionable stacktraces and pointers.",
129
+ "inputSchema": {
130
+ "type": "object",
131
+ "properties": {
132
+ "raw_log_text": {"type": "string", "description": "Raw terminal log output to compress."}
133
+ },
134
+ "required": ["raw_log_text"]
135
+ }
136
+ },
137
+ {
138
+ "name": "run_micro_mutation",
139
+ "description": "Injects AST micro-mutants (flipping operators, booleans) to verify that AI-generated test assertions are robust.",
140
+ "inputSchema": {
141
+ "type": "object",
142
+ "properties": {
143
+ "target_path": {"type": "string", "description": "Path to test script or directory to mutate."}
144
+ }
145
+ }
146
+ },
147
+ {
148
+ "name": "plan_healing_pr",
149
+ "description": "Calculates composite confidence score for healed locators and formats an automated Pull Request draft.",
150
+ "inputSchema": {
151
+ "type": "object",
152
+ "properties": {
153
+ "page_file": {"type": "string", "description": "Page Class path."},
154
+ "old_locator": {"type": "string", "description": "Original stale selector."},
155
+ "new_locator": {"type": "string", "description": "Healed replacement selector."},
156
+ "aom_score": {"type": "number", "description": "AOM match score 0.0-1.0."},
157
+ "spatial_score": {"type": "number", "description": "Spatial score 0.0-1.0."},
158
+ "visual_score": {"type": "number", "description": "Visual SSIM score 0.0-1.0."}
159
+ },
160
+ "required": ["page_file", "old_locator", "new_locator"]
161
+ }
162
+ },
163
+ {
164
+ "name": "shard_test_matrix",
165
+ "description": "Distributes test cases evenly across N parallel CI/CD runners using Duration-Balanced Bin-Packing.",
166
+ "inputSchema": {
167
+ "type": "object",
168
+ "properties": {
169
+ "target_dir": {"type": "string", "description": "Target project root directory."},
170
+ "num_shards": {"type": "integer", "description": "Number of parallel workers (default 4)."}
171
+ }
172
+ }
173
+ },
174
+ {
175
+ "name": "pull_alm_story",
176
+ "description": "Pulls User Story and Acceptance Criteria (Given-When-Then) from Jira, Xray, or TestRail for test generation context.",
177
+ "inputSchema": {
178
+ "type": "object",
179
+ "properties": {
180
+ "issue_key": {"type": "string", "description": "ALM Issue Key (e.g. PROJ-1042)."}
181
+ },
182
+ "required": ["issue_key"]
183
+ }
184
+ },
185
+ {
186
+ "name": "report_alm_defect",
187
+ "description": "Creates an automated Bug Ticket in Jira/TMS with full diagnostic reproduction steps, stack trace, and screenshot attachments.",
188
+ "inputSchema": {
189
+ "type": "object",
190
+ "properties": {
191
+ "project_key": {"type": "string", "description": "Target project key (e.g. PROJ)."},
192
+ "test_case_id": {"type": "string", "description": "Failing test case ID."},
193
+ "summary": {"type": "string", "description": "Defect summary."},
194
+ "error_message": {"type": "string", "description": "Exact failure error message."},
195
+ "stack_trace": {"type": "string", "description": "Exception stack trace."},
196
+ "screenshot_path": {"type": "string", "description": "Path to FAILED screenshot image."}
197
+ },
198
+ "required": ["project_key", "test_case_id", "summary", "error_message"]
199
+ }
200
+ },
201
+ {
202
+ "name": "manage_db_sandbox",
203
+ "description": "Zero-pollution ephemeral database manager: creates baseline snapshot, restores pristine DB state, or executes transaction savepoints.",
204
+ "inputSchema": {
205
+ "type": "object",
206
+ "properties": {
207
+ "action": {"type": "string", "enum": ["snapshot", "restore", "audit_and_purge"], "description": "Sandbox operation to execute."},
208
+ "db_path": {"type": "string", "description": "Path to database file (optional for SQLite)."},
209
+ "snapshot_id": {"type": "string", "description": "Snapshot identifier (default: pristine_baseline)."}
210
+ },
211
+ "required": ["action"]
212
+ }
213
+ },
214
+ {
215
+ "name": "convert_traffic_session",
216
+ "description": "Shift-Right Replay: Transforms recorded HTTP Archive (.har) or RUM session into PII-sanitized Playwright test suite.",
217
+ "inputSchema": {
218
+ "type": "object",
219
+ "properties": {
220
+ "input_file": {"type": "string", "description": "Path to .har or JSON network session file."},
221
+ "test_name": {"type": "string", "description": "Generated test suite name."}
222
+ },
223
+ "required": ["input_file"]
224
+ }
225
+ },
226
+ {
227
+ "name": "resolve_visual_som_coordinates",
228
+ "description": "Multimodal Vision Grounding: Resolves click coordinates (x, y) on HTML5 Canvas or Shadow DOM using Set-of-Marks (SoM).",
229
+ "inputSchema": {
230
+ "type": "object",
231
+ "properties": {
232
+ "image_path": {"type": "string", "description": "Path to screenshot image."},
233
+ "target_label": {"type": "string", "description": "Target element label or text."},
234
+ "mark_id": {"type": "integer", "description": "Specific Mark ID to click."}
235
+ }
236
+ }
237
+ }
238
+ ]
239
+
240
+
241
+ def handle_tool_call(name: str, arguments: Dict[str, Any]) -> str:
242
+ """Executes the corresponding internal tool function and returns text response."""
243
+ if name == "verify_all_gates":
244
+ repo = arguments.get("repo_path") or os.getcwd()
245
+ mode = verify_all.detect_repo_mode(repo)
246
+ passed = True
247
+ gates = [
248
+ ("Gate 1: UTF-8 No BOM", verify_all.gate_1_bom_check),
249
+ ("Gate 2: Path Portability", verify_all.gate_2_path_portability),
250
+ ("Gate 3: Clean POM", verify_all.gate_3_clean_pom),
251
+ ("Gate 4: AI Docs Linter", verify_all.gate_4_ai_docs_lint),
252
+ ("Gate 5: Temp Blacklist", verify_all.gate_5_cleanup_blacklist),
253
+ ("Gate 6: Credential Security", verify_all.gate_6_credential_security),
254
+ ("Gate 7: Infer Linter", verify_all.gate_7_infer_linter),
255
+ ("Gate 8: AST Mutation Sentinel", verify_all.gate_8_micro_mutator),
256
+ ]
257
+ results = []
258
+ for g_name, g_fn in gates:
259
+ res = g_fn(repo, mode=mode)
260
+ results.append(f"{g_name}: {'PASS' if res else 'FAIL'}")
261
+ if not res:
262
+ passed = False
263
+ summary = "100% ALL 8 GATES PASSED" if passed else "VERIFICATION FAILED"
264
+ return f"[{summary}]\n" + "\n".join(results)
265
+
266
+ elif name == "analyze_project":
267
+ repo = arguments.get("repo_path") or os.getcwd()
268
+ code = analyze_project.run_full_analysis(repo)
269
+ return f"Project Analysis finished with exit code {code}. Report saved at {os.path.join(repo, 'PROJECT_HEALTH_REPORT.md')}."
270
+
271
+ elif name == "setup_project":
272
+ repo = arguments.get("repo_path") or os.getcwd()
273
+ code = setup_project.run_setup(repo)
274
+ return f"Project Setup finished with exit code {code}."
275
+
276
+ elif name == "auto_heal_failure":
277
+ target = arguments.get("target_dir") or os.getcwd()
278
+ xml = arguments.get("junit_xml_path")
279
+ plan = auto_heal.diagnose_and_plan_heal(target, xml)
280
+ return json.dumps(plan, indent=2)
281
+
282
+ elif name == "check_action_safety":
283
+ auth = safety_firewall.inspect_and_authorize(
284
+ action_type=arguments.get("action_type", "click"),
285
+ text=arguments.get("element_text", ""),
286
+ selector=arguments.get("selector", ""),
287
+ force=arguments.get("force", False)
288
+ )
289
+ return json.dumps(auth, indent=2)
290
+
291
+ elif name == "check_contract_drift":
292
+ old_data = api_drift_sentinel.load_spec(arguments["old_spec_path"])
293
+ new_data = api_drift_sentinel.load_spec(arguments["new_spec_path"])
294
+ analysis = api_drift_sentinel.compare_specs(old_data, new_data)
295
+ return api_drift_sentinel.generate_markdown_report(analysis, arguments["old_spec_path"], arguments["new_spec_path"])
296
+
297
+ elif name == "query_memory_cache":
298
+ res = cache_resolver.query_cache(arguments["error_signature"])
299
+ return json.dumps(res, indent=2) if res else "No matching solution found in memory cache."
300
+
301
+ elif name == "distill_log":
302
+ distilled = distill_log.distill_log_content(arguments["raw_log_text"])
303
+ return distilled
304
+
305
+ elif name == "run_micro_mutation":
306
+ target = arguments.get("target_path") or os.getcwd()
307
+ mutants = micro_mutator.scan_directory_for_mutants(target) if os.path.isdir(target) else micro_mutator.generate_mutants_for_code(open(target).read(), target)
308
+ return json.dumps({"total_mutants": len(mutants), "sample_mutants": mutants[:5]}, indent=2)
309
+
310
+ elif name == "plan_healing_pr":
311
+ conf = heal_pr_automator.calculate_healing_confidence(
312
+ arguments.get("aom_score", 0.95),
313
+ arguments.get("spatial_score", 0.90),
314
+ arguments.get("visual_score", 0.92)
315
+ )
316
+ pr = heal_pr_automator.generate_pr_draft(arguments["page_file"], arguments["old_locator"], arguments["new_locator"], conf)
317
+ return json.dumps({"confidence": conf, "pr": pr}, indent=2)
318
+
319
+ elif name == "shard_test_matrix":
320
+ target = arguments.get("target_dir") or os.getcwd()
321
+ num_shards = arguments.get("num_shards", 4)
322
+ files = matrix_sharder.find_test_files(target)
323
+ shards = matrix_sharder.shard_tests_lpt(files, target, num_shards)
324
+ return json.dumps({"total_tests": len(files), "shards": shards}, indent=2)
325
+
326
+ elif name == "pull_alm_story":
327
+ bridge = tms_sync_bridge.TMSBridge()
328
+ story = bridge.pull_story_acceptance_criteria(arguments["issue_key"])
329
+ return json.dumps(story, indent=2)
330
+
331
+ elif name == "report_alm_defect":
332
+ bridge = tms_sync_bridge.TMSBridge()
333
+ ticket = bridge.report_defect(
334
+ project_key=arguments["project_key"],
335
+ test_case_id=arguments["test_case_id"],
336
+ summary=arguments["summary"],
337
+ error_message=arguments["error_message"],
338
+ stack_trace=arguments.get("stack_trace", ""),
339
+ screenshot_path=arguments.get("screenshot_path", "")
340
+ )
341
+ return json.dumps(ticket, indent=2)
342
+
343
+ elif name == "manage_db_sandbox":
344
+ action = arguments["action"]
345
+ sandbox = db_sandbox.DBSandbox(db_path=arguments.get("db_path", ""))
346
+ if action == "snapshot":
347
+ res = sandbox.create_snapshot(arguments.get("snapshot_id", "pristine_baseline"))
348
+ elif action == "restore":
349
+ res = sandbox.restore_snapshot(arguments.get("snapshot_id", "pristine_baseline"))
350
+ elif action == "audit_and_purge":
351
+ res = sandbox.audit_and_purge_pollution()
352
+ else:
353
+ raise ValueError(f"Unknown sandbox action: {action}")
354
+ return json.dumps(res, indent=2)
355
+
356
+ elif name == "convert_traffic_session":
357
+ input_file = arguments["input_file"]
358
+ test_name = arguments.get("test_name", "ProductionTrafficReplay")
359
+ with open(input_file, "r", encoding="utf-8", errors="ignore") as f:
360
+ data = json.load(f)
361
+ converter = traffic_session_converter.TrafficConverter(sanitize_pii=True)
362
+ requests = converter.parse_har(data)
363
+ test_code = converter.generate_playwright_test(requests, test_name=test_name)
364
+ return json.dumps({"total_requests": len(requests), "generated_test": test_code}, indent=2)
365
+
366
+ elif name == "resolve_visual_som_coordinates":
367
+ helper = visual_som_helper.VisualSoMHelper()
368
+ img = arguments.get("image_path", "screenshot.png")
369
+ lbl = arguments.get("target_label")
370
+ mid = arguments.get("mark_id")
371
+ marked_img, marks_map = helper.generate_som_overlay(img, [])
372
+ resolved = helper.resolve_mark_coordinates(marks_map, target_mark_id=mid, target_label=lbl)
373
+ return json.dumps({"marked_image": marked_img, "resolved_target": resolved}, indent=2)
374
+
375
+ raise ValueError(f"Unknown MCP tool: {name}")
376
+
377
+
378
+ def process_message(msg: Dict[str, Any]) -> Dict[str, Any]:
379
+ """Processes an incoming JSON-RPC 2.0 message."""
380
+ method = msg.get("method")
381
+ msg_id = msg.get("id")
382
+
383
+ if method == "initialize":
384
+ return {
385
+ "jsonrpc": "2.0",
386
+ "id": msg_id,
387
+ "result": {
388
+ "protocolVersion": "2024-11-05",
389
+ "capabilities": {
390
+ "tools": {}
391
+ },
392
+ "serverInfo": {
393
+ "name": SERVER_NAME,
394
+ "version": SERVER_VERSION
395
+ }
396
+ }
397
+ }
398
+
399
+ elif method in ("notifications/initialized", "initialized"):
400
+ return None # No response needed for notification
401
+
402
+ elif method == "tools/list":
403
+ return {
404
+ "jsonrpc": "2.0",
405
+ "id": msg_id,
406
+ "result": {
407
+ "tools": MCP_TOOLS
408
+ }
409
+ }
410
+
411
+ elif method == "tools/call":
412
+ params = msg.get("params", {})
413
+ tool_name = params.get("name")
414
+ arguments = params.get("arguments", {})
415
+ try:
416
+ output_text = handle_tool_call(tool_name, arguments)
417
+ return {
418
+ "jsonrpc": "2.0",
419
+ "id": msg_id,
420
+ "result": {
421
+ "content": [
422
+ {
423
+ "type": "text",
424
+ "text": output_text
425
+ }
426
+ ],
427
+ "isError": False
428
+ }
429
+ }
430
+ except Exception as e:
431
+ return {
432
+ "jsonrpc": "2.0",
433
+ "id": msg_id,
434
+ "result": {
435
+ "content": [
436
+ {
437
+ "type": "text",
438
+ "text": f"Error executing {tool_name}: {str(e)}\n{traceback.format_exc()}"
439
+ }
440
+ ],
441
+ "isError": True
442
+ }
443
+ }
444
+
445
+ elif method == "ping":
446
+ return {"jsonrpc": "2.0", "id": msg_id, "result": {}}
447
+
448
+ return {
449
+ "jsonrpc": "2.0",
450
+ "id": msg_id,
451
+ "error": {
452
+ "code": -32601,
453
+ "message": f"Method not found: {method}"
454
+ }
455
+ }
456
+
457
+
458
+ def run_stdio_server():
459
+ """Runs the MCP server over standard input/output."""
460
+ while True:
461
+ try:
462
+ line = sys.stdin.readline()
463
+ if not line:
464
+ break
465
+ line = line.strip()
466
+ if not line:
467
+ continue
468
+
469
+ msg = json.loads(line)
470
+ response = process_message(msg)
471
+ if response is not None:
472
+ sys.stdout.write(json.dumps(response) + "\n")
473
+ sys.stdout.flush()
474
+ except KeyboardInterrupt:
475
+ break
476
+ except Exception as e:
477
+ err_resp = {
478
+ "jsonrpc": "2.0",
479
+ "id": None,
480
+ "error": {
481
+ "code": -32700,
482
+ "message": f"Parse error: {str(e)}"
483
+ }
484
+ }
485
+ sys.stdout.write(json.dumps(err_resp) + "\n")
486
+ sys.stdout.flush()
487
+
488
+
489
+ if __name__ == "__main__":
490
+ run_stdio_server()