@suiflex/suitest-mcp 0.1.1 → 0.1.2
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.
package/package.json
CHANGED
|
@@ -12,7 +12,10 @@ Every tool takes a single ``config_path`` argument and returns the structured
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
|
+
import os
|
|
15
16
|
import sys
|
|
17
|
+
import urllib.error
|
|
18
|
+
import urllib.request
|
|
16
19
|
from typing import TYPE_CHECKING, TextIO
|
|
17
20
|
|
|
18
21
|
from suitest_lifecycle.tools import KWARG_TOOLS, TOOLS
|
|
@@ -147,7 +150,7 @@ def handle(message: dict[str, object]) -> dict[str, object] | None:
|
|
|
147
150
|
{
|
|
148
151
|
"protocolVersion": PROTOCOL_VERSION,
|
|
149
152
|
"capabilities": {"tools": {}},
|
|
150
|
-
"serverInfo": {"name": "suitest-lifecycle", "version": "0.1.
|
|
153
|
+
"serverInfo": {"name": "suitest-lifecycle", "version": "0.1.2"},
|
|
151
154
|
},
|
|
152
155
|
)
|
|
153
156
|
if method in ("notifications/initialized", "initialized"):
|
|
@@ -194,7 +197,39 @@ def handle(message: dict[str, object]) -> dict[str, object] | None:
|
|
|
194
197
|
return None
|
|
195
198
|
|
|
196
199
|
|
|
200
|
+
def verify_credentials() -> str | None:
|
|
201
|
+
"""Check SUITEST_API_URL + SUITEST_API_KEY; return an error string if unusable.
|
|
202
|
+
|
|
203
|
+
Both must be set, and the key must authenticate against the URL
|
|
204
|
+
(``GET /api/v1/api-keys/whoami`` — the key pins the workspace/project every
|
|
205
|
+
tool publishes into). Any failure must abort the connection: a server that
|
|
206
|
+
accepts empty or mismatched credentials silently drops all publishes.
|
|
207
|
+
"""
|
|
208
|
+
api_url = os.environ.get("SUITEST_API_URL", "").strip().rstrip("/")
|
|
209
|
+
api_key = os.environ.get("SUITEST_API_KEY", "").strip()
|
|
210
|
+
if not api_url or not api_key:
|
|
211
|
+
return (
|
|
212
|
+
"SUITEST_API_URL and SUITEST_API_KEY are both required "
|
|
213
|
+
"(set them in the mcpServers env block); refusing to start"
|
|
214
|
+
)
|
|
215
|
+
req = urllib.request.Request(
|
|
216
|
+
f"{api_url}/api/v1/api-keys/whoami",
|
|
217
|
+
headers={"Authorization": f"Bearer {api_key}"},
|
|
218
|
+
)
|
|
219
|
+
try:
|
|
220
|
+
with urllib.request.urlopen(req, timeout=10):
|
|
221
|
+
return None
|
|
222
|
+
except urllib.error.HTTPError as exc:
|
|
223
|
+
return f"SUITEST_API_KEY rejected by {api_url} (HTTP {exc.code}); refusing to start"
|
|
224
|
+
except (urllib.error.URLError, OSError) as exc:
|
|
225
|
+
return f"SUITEST_API_URL {api_url} unreachable ({exc}); refusing to start"
|
|
226
|
+
|
|
227
|
+
|
|
197
228
|
def serve(stdin: TextIO = sys.stdin, stdout: TextIO = sys.stdout) -> None:
|
|
229
|
+
error = verify_credentials()
|
|
230
|
+
if error is not None:
|
|
231
|
+
sys.stderr.write(f"suitest-mcp: {error}\n")
|
|
232
|
+
raise SystemExit(1)
|
|
198
233
|
for line in stdin:
|
|
199
234
|
line = line.strip()
|
|
200
235
|
if not line:
|