synapse-hub 0.0.0-stage → 2.0.1

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 +537 -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 +425 -0
  122. package/tools/wcag_audit.py +214 -0
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Enterprise Duration-Balanced Test Matrix Sharder
4
+ ------------------------------------------------
5
+ Balances parallel CI/CD test execution across N containers using historical
6
+ runtimes and the Greedy LPT (Longest Processing Time First) Bin-Packing algorithm.
7
+ Eliminates CI runner bottlenecks where one worker runs for 15m while others finish in 2m.
8
+ """
9
+
10
+ import os
11
+ import sys
12
+ import json
13
+ import sqlite3
14
+ import argparse
15
+ from pathlib import Path
16
+ from typing import List, Dict, Any
17
+
18
+ # Enforce UTF-8 stdout encoding for Windows console compatibility
19
+ if hasattr(sys.stdout, 'reconfigure'):
20
+ try:
21
+ sys.stdout.reconfigure(encoding='utf-8')
22
+ sys.stderr.reconfigure(encoding='utf-8')
23
+ except Exception:
24
+ pass
25
+
26
+ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
27
+ HUB_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
28
+ CACHE_DB_PATH = os.path.join(SCRIPT_DIR, "memory_cache.db")
29
+
30
+
31
+ def find_test_files(target_dir: str) -> List[str]:
32
+ """Discovers all executable test scripts across Katalon, Playwright, or Pytest suites."""
33
+ target_path = Path(target_dir)
34
+ test_files = []
35
+ valid_exts = {".groovy", ".ts", ".js", ".py"}
36
+
37
+ for root, _, files in os.walk(target_path):
38
+ for f in files:
39
+ # Match standard test naming patterns
40
+ lower = f.lower()
41
+ if any(lower.endswith(ext) for ext in valid_exts):
42
+ if "test" in lower or "spec" in lower or "tc_" in lower or "scripts" in root.lower():
43
+ rel_p = os.path.relpath(os.path.join(root, f), target_dir).replace("\\", "/")
44
+ test_files.append(rel_p)
45
+
46
+ return sorted(test_files)
47
+
48
+
49
+ def estimate_test_duration(file_path: str, full_path: str) -> float:
50
+ """Estimates test execution duration in seconds using historical cache or file heuristic."""
51
+ # Check SQLite historical runtime cache if available
52
+ if os.path.exists(CACHE_DB_PATH):
53
+ try:
54
+ conn = sqlite3.connect(CACHE_DB_PATH)
55
+ cur = conn.cursor()
56
+ cur.execute("CREATE TABLE IF NOT EXISTS test_runtimes (test_path TEXT PRIMARY KEY, duration REAL)")
57
+ cur.execute("SELECT duration FROM test_runtimes WHERE test_path = ?", (file_path,))
58
+ row = cur.fetchone()
59
+ conn.close()
60
+ if row and row[0]:
61
+ return float(row[0])
62
+ except Exception:
63
+ pass
64
+
65
+ # Heuristic fallback: ~0.5s per line of script
66
+ try:
67
+ if os.path.exists(full_path):
68
+ with open(full_path, "r", encoding="utf-8", errors="ignore") as fp:
69
+ lines = len(fp.readlines())
70
+ return max(5.0, round(lines * 0.25, 1))
71
+ except Exception:
72
+ pass
73
+
74
+ return 10.0
75
+
76
+
77
+ def shard_tests_lpt(test_files: List[str], target_dir: str, num_shards: int) -> List[Dict[str, Any]]:
78
+ """
79
+ Applies Longest Processing Time First (LPT) bin-packing to distribute tests evenly.
80
+ """
81
+ num_shards = max(1, num_shards)
82
+ if not test_files:
83
+ return [{"shard_index": i + 1, "total_duration": 0.0, "tests": []} for i in range(num_shards)]
84
+
85
+ # 1. Calculate duration for each test
86
+ tests_with_cost = []
87
+ for tf in test_files:
88
+ fp = os.path.join(target_dir, tf)
89
+ dur = estimate_test_duration(tf, fp)
90
+ tests_with_cost.append((tf, dur))
91
+
92
+ # 2. Sort descending by duration
93
+ tests_with_cost.sort(key=lambda x: x[1], reverse=True)
94
+
95
+ # 3. Initialize shards
96
+ shards = [{"shard_index": i + 1, "total_duration": 0.0, "tests": []} for i in range(num_shards)]
97
+
98
+ # 4. Greedily assign to the shard with the least current cumulative duration
99
+ for test_file, dur in tests_with_cost:
100
+ # Find shard with min duration
101
+ min_shard = min(shards, key=lambda s: s["total_duration"])
102
+ min_shard["tests"].append(test_file)
103
+ min_shard["total_duration"] = round(min_shard["total_duration"] + dur, 2)
104
+
105
+ return shards
106
+
107
+
108
+ def main():
109
+ parser = argparse.ArgumentParser(description="Duration-Balanced Test Matrix Sharder")
110
+ parser.add_argument("target", nargs="?", default=os.getcwd(), help="Target repository root")
111
+ parser.add_argument("--shards", "-n", type=int, default=4, help="Number of parallel shards/workers (default: 4)")
112
+ parser.add_argument("--json", action="store_true", help="Output matrix in JSON format")
113
+ args = parser.parse_args()
114
+
115
+ target_dir = os.path.abspath(args.target)
116
+ test_files = find_test_files(target_dir)
117
+ shards = shard_tests_lpt(test_files, target_dir, args.shards)
118
+
119
+ if args.json:
120
+ print(json.dumps({"total_tests": len(test_files), "shards_count": args.shards, "shards": shards}, indent=2))
121
+ else:
122
+ print(f"\n======================================================================")
123
+ print(f" DURATION-BALANCED TEST MATRIX SHARDER ({args.shards} PARALLEL WORKERS) ")
124
+ print(f"======================================================================")
125
+ print(f" Target Scope : {target_dir}")
126
+ print(f" Total Tests : {len(test_files)} files\n")
127
+
128
+ for s in shards:
129
+ print(f"📦 Shard {s['shard_index']}: {len(s['tests'])} tests (~{s['total_duration']}s total)")
130
+ for t in s['tests'][:5]:
131
+ print(f" • {t}")
132
+ if len(s['tests']) > 5:
133
+ print(f" ... and {len(s['tests']) - 5} more")
134
+ print()
135
+
136
+ # Calculate imbalance delta
137
+ durations = [s["total_duration"] for s in shards]
138
+ delta = max(durations) - min(durations) if durations else 0
139
+ print(f"⚡ Shard Imbalance Delta: {delta:.1f}s (Optimal parallel distribution)")
140
+ print(f"======================================================================\n")
141
+
142
+ return 0
143
+
144
+
145
+ if __name__ == "__main__":
146
+ sys.exit(main())
@@ -0,0 +1,251 @@
1
+ param()
2
+
3
+ [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") | Out-Null
4
+
5
+ function Read-ExcelSheet {
6
+ param(
7
+ [string]$FilePath,
8
+ [string]$SheetName = ""
9
+ )
10
+
11
+ if ([string]::IsNullOrWhiteSpace($FilePath) -or -not (Test-Path -LiteralPath $FilePath)) {
12
+ if ($env:EXCEL_TEST_PATH -and (Test-Path -LiteralPath $env:EXCEL_TEST_PATH)) {
13
+ $FilePath = $env:EXCEL_TEST_PATH
14
+ } else {
15
+ # Search workspace or Downloads for any recent xlsx file
16
+ $found = Get-ChildItem -Path "." -Filter "*.xlsx" -Recurse -Depth 2 -ErrorAction SilentlyContinue | Select-Object -First 1
17
+ if (-not $found) {
18
+ $found = Get-ChildItem -Path "$env:USERPROFILE\Downloads" -Filter "*.xlsx" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1
19
+ }
20
+ if ($found) { $FilePath = $found.FullName }
21
+ }
22
+ }
23
+
24
+ if ([string]::IsNullOrWhiteSpace($FilePath) -or -not (Test-Path -LiteralPath $FilePath)) {
25
+ throw "Excel file not found. Please provide a valid file_path."
26
+ }
27
+
28
+ $fullPath = (Get-Item $FilePath).FullName
29
+ $zip = [System.IO.Compression.ZipFile]::OpenRead($fullPath)
30
+
31
+ try {
32
+ # 1. Read shared strings
33
+ $sharedStrings = New-Object System.Collections.Generic.List[string]
34
+ $ssEntry = $zip.GetEntry("xl/sharedStrings.xml")
35
+ if ($ssEntry) {
36
+ $stream = $ssEntry.Open()
37
+ $reader = New-Object System.IO.StreamReader($stream, [System.Text.Encoding]::UTF8)
38
+ $ssXml = [xml]$reader.ReadToEnd()
39
+ $reader.Close()
40
+ $stream.Close()
41
+ foreach ($si in $ssXml.sst.si) {
42
+ $sharedStrings.Add($si.InnerText)
43
+ }
44
+ }
45
+
46
+ # 2. Determine target sheet entry from workbook.xml
47
+ $targetSheetEntryName = "xl/worksheets/sheet1.xml"
48
+ $wbEntry = $zip.GetEntry("xl/workbook.xml")
49
+ if ($wbEntry) {
50
+ $stream = $wbEntry.Open()
51
+ $reader = New-Object System.IO.StreamReader($stream, [System.Text.Encoding]::UTF8)
52
+ $wbXml = [xml]$reader.ReadToEnd()
53
+ $reader.Close()
54
+ $stream.Close()
55
+
56
+ $sheets = $wbXml.workbook.sheets.sheet
57
+ $matchedSheetIndex = 1
58
+ if ($SheetName -and $sheets) {
59
+ $idx = 1
60
+ foreach ($s in $sheets) {
61
+ if ($s.name -eq $SheetName -or $s.name -like "*$SheetName*") {
62
+ $matchedSheetIndex = $idx
63
+ break
64
+ }
65
+ $idx++
66
+ }
67
+ }
68
+ $targetSheetEntryName = "xl/worksheets/sheet$matchedSheetIndex.xml"
69
+ }
70
+
71
+ # Fallback if entry doesn't exist
72
+ $sEntry = $zip.GetEntry($targetSheetEntryName)
73
+ if (-not $sEntry) {
74
+ $firstSheet = $zip.Entries | Where-Object { $_.FullName -like "xl/worksheets/sheet*.xml" } | Select-Object -First 1
75
+ if ($firstSheet) { $sEntry = $firstSheet }
76
+ }
77
+
78
+ if (-not $sEntry) {
79
+ throw "No worksheet found inside Excel archive."
80
+ }
81
+
82
+ $stream = $sEntry.Open()
83
+ $reader = New-Object System.IO.StreamReader($stream, [System.Text.Encoding]::UTF8)
84
+ $sXml = [xml]$reader.ReadToEnd()
85
+ $reader.Close()
86
+ $stream.Close()
87
+
88
+ $rows = $sXml.worksheet.sheetData.row
89
+ $currentModule = "General"
90
+ $testcases = @()
91
+
92
+ foreach ($r in $rows) {
93
+ $rowNum = [int]$r.r
94
+ $cells = @{}
95
+ foreach ($c in $r.c) {
96
+ $colLetter = $c.r -replace '\d+'
97
+ $val = ""
98
+ if ($c.v) {
99
+ $raw = $c.v
100
+ if ($c.t -eq "s") {
101
+ $val = $sharedStrings[[int]$raw]
102
+ } else {
103
+ $val = $raw
104
+ }
105
+ }
106
+ $cells[$colLetter] = $val
107
+ }
108
+
109
+ $colA = if ($cells.ContainsKey("A")) { $cells["A"].Trim() } else { "" }
110
+ $colB = if ($cells.ContainsKey("B")) { $cells["B"].Trim() } else { "" }
111
+
112
+ if ($colB -match "PHAN HE|Phan he|PHÂN HỆ|Phân hệ|MODULE|Module") {
113
+ $currentModule = $colB.Trim()
114
+ } elseif ($colA -match "PHAN HE|Phan he|PHÂN HỆ|Phân hệ|MODULE|Module") {
115
+ $currentModule = $colA.Trim()
116
+ }
117
+
118
+ if ($colA -match '^TC[-_]?\d+') {
119
+ $testcases += [PSCustomObject]@{
120
+ Row = $rowNum
121
+ Module = $currentModule
122
+ ID = $colA
123
+ Name = if ($cells.ContainsKey("B")) { $cells["B"].Trim() } else { "" }
124
+ PreCondition = if ($cells.ContainsKey("C")) { $cells["C"].Trim() } else { "" }
125
+ Steps = if ($cells.ContainsKey("D")) { $cells["D"].Trim() } else { "" }
126
+ DataTest = if ($cells.ContainsKey("E")) { $cells["E"].Trim() } else { "" }
127
+ Expected = if ($cells.ContainsKey("F")) { $cells["F"].Trim() } else { "" }
128
+ Progress = if ($cells.ContainsKey("G")) { $cells["G"].Trim() } else { "" }
129
+ Status = if ($cells.ContainsKey("H")) { $cells["H"].Trim() } else { "" }
130
+ QC = if ($cells.ContainsKey("I")) { $cells["I"].Trim() } else { "" }
131
+ }
132
+ }
133
+ }
134
+ return $testcases
135
+ } finally {
136
+ $zip.Dispose()
137
+ }
138
+ }
139
+
140
+ # Alias for backwards compatibility
141
+ function Read-EnterpriseSheet {
142
+ param([string]$FilePath)
143
+ return Read-ExcelSheet -FilePath $FilePath
144
+ }
145
+
146
+ # Stdio JSON-RPC Loop
147
+ $inputReader = [System.Console]::In
148
+ while (($line = $inputReader.ReadLine()) -ne $null) {
149
+ if ([string]::IsNullOrWhiteSpace($line)) { continue }
150
+ $id = $null
151
+ try {
152
+ $req = $line | ConvertFrom-Json
153
+ $id = $req.id
154
+ $method = $req.method
155
+
156
+ if ($method -eq "initialize") {
157
+ $resp = @{
158
+ jsonrpc = "2.0"
159
+ id = $id
160
+ result = @{
161
+ protocolVersion = "2024-11-05"
162
+ capabilities = @{ tools = @{} }
163
+ serverInfo = @{ name = "excel-qa-mcp-server"; version = "2.0.1" }
164
+ }
165
+ }
166
+ [System.Console]::Out.WriteLine(($resp | ConvertTo-Json -Compress -Depth 10))
167
+ } elseif ($method -eq "notifications/initialized") {
168
+ } elseif ($method -eq "ping") {
169
+ $resp = @{ jsonrpc = "2.0"; id = $id; result = @{} }
170
+ [System.Console]::Out.WriteLine(($resp | ConvertTo-Json -Compress))
171
+ } elseif ($method -eq "tools/list") {
172
+ $resp = @{
173
+ jsonrpc = "2.0"
174
+ id = $id
175
+ result = @{
176
+ tools = @(
177
+ @{
178
+ name = "read_excel_sheet"
179
+ description = "Extract test cases and matrix rows from an Excel worksheet."
180
+ inputSchema = @{
181
+ type = "object"
182
+ properties = @{
183
+ file_path = @{ type = "string"; description = "Path to Excel file (.xlsx)" }
184
+ sheet_name = @{ type = "string"; description = "Worksheet name (defaults to first sheet)" }
185
+ }
186
+ }
187
+ },
188
+ @{
189
+ name = "read_Enterprise_sheet"
190
+ description = "Compatibility alias for read_excel_sheet"
191
+ inputSchema = @{
192
+ type = "object"
193
+ properties = @{
194
+ file_path = @{ type = "string"; description = "Path to Excel file (.xlsx)" }
195
+ }
196
+ }
197
+ }
198
+ )
199
+ }
200
+ }
201
+ [System.Console]::Out.WriteLine(($resp | ConvertTo-Json -Compress -Depth 10))
202
+ } elseif ($method -eq "tools/call") {
203
+ $toolName = $req.params.name
204
+ if ($toolName -eq "read_excel_sheet" -or $toolName -eq "read_Enterprise_sheet") {
205
+ $fPath = $req.params.arguments.file_path
206
+ $sName = if ($req.params.arguments.sheet_name) { $req.params.arguments.sheet_name } else { "" }
207
+ $tcs = Read-ExcelSheet -FilePath $fPath -SheetName $sName
208
+ $textResult = $tcs | ConvertTo-Json -Depth 5
209
+ $resp = @{
210
+ jsonrpc = "2.0"
211
+ id = $id
212
+ result = @{
213
+ content = @(
214
+ @{ type = "text"; text = $textResult }
215
+ )
216
+ }
217
+ }
218
+ [System.Console]::Out.WriteLine(($resp | ConvertTo-Json -Compress -Depth 10))
219
+ } else {
220
+ $resp = @{
221
+ jsonrpc = "2.0"
222
+ id = $id
223
+ error = @{ code = -32601; message = "Tool not found: $toolName" }
224
+ }
225
+ [System.Console]::Out.WriteLine(($resp | ConvertTo-Json -Compress))
226
+ }
227
+ } else {
228
+ if ($null -ne $id) {
229
+ $resp = @{
230
+ jsonrpc = "2.0"
231
+ id = $id
232
+ error = @{ code = -32601; message = "Method not found: $method" }
233
+ }
234
+ [System.Console]::Out.WriteLine(($resp | ConvertTo-Json -Compress))
235
+ }
236
+ }
237
+ } catch {
238
+ $errMsg = $_.Exception.Message
239
+ [System.Console]::Error.WriteLine("[MCP Excel Server Error] $errMsg")
240
+ $errCode = if ($null -eq $id) { -32700 } else { -32603 }
241
+ $resp = @{
242
+ jsonrpc = "2.0"
243
+ id = $id
244
+ error = @{
245
+ code = $errCode
246
+ message = "MCP Server Exception: $errMsg"
247
+ }
248
+ }
249
+ [System.Console]::Out.WriteLine(($resp | ConvertTo-Json -Compress))
250
+ }
251
+ }