common-qa-mcp 0.1.1 → 0.3.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.
- package/README.md +25 -70
- package/dist/adapters/factory.d.ts +17 -7
- package/dist/adapters/factory.d.ts.map +1 -1
- package/dist/adapters/factory.js +61 -7
- package/dist/adapters/factory.js.map +1 -1
- package/dist/adapters/http.d.ts +50 -0
- package/dist/adapters/http.d.ts.map +1 -0
- package/dist/adapters/http.js +109 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/remoteMcp/adapter.d.ts +10 -1
- package/dist/adapters/remoteMcp/adapter.d.ts.map +1 -1
- package/dist/adapters/remoteMcp/adapter.js +31 -3
- package/dist/adapters/remoteMcp/adapter.js.map +1 -1
- package/dist/adapters/simplifyqa/adapter.d.ts +154 -0
- package/dist/adapters/simplifyqa/adapter.d.ts.map +1 -0
- package/dist/adapters/simplifyqa/adapter.js +1150 -0
- package/dist/adapters/simplifyqa/adapter.js.map +1 -0
- package/dist/adapters/simplifyqa/mapper.d.ts +63 -0
- package/dist/adapters/simplifyqa/mapper.d.ts.map +1 -0
- package/dist/adapters/simplifyqa/mapper.js +409 -0
- package/dist/adapters/simplifyqa/mapper.js.map +1 -0
- package/dist/adapters/types.d.ts +48 -1
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/walnut/adapter.d.ts +231 -0
- package/dist/adapters/walnut/adapter.d.ts.map +1 -0
- package/dist/adapters/walnut/adapter.js +1083 -0
- package/dist/adapters/walnut/adapter.js.map +1 -0
- package/dist/adapters/walnut/mapper.d.ts +29 -9
- package/dist/adapters/walnut/mapper.d.ts.map +1 -1
- package/dist/adapters/walnut/mapper.js +136 -24
- package/dist/adapters/walnut/mapper.js.map +1 -1
- package/dist/cli.js +5 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +32 -14
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +41 -19
- package/dist/config.js.map +1 -1
- package/dist/connection.d.ts +6 -2
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +37 -14
- package/dist/connection.js.map +1 -1
- package/dist/domain/types.d.ts +195 -1
- package/dist/domain/types.d.ts.map +1 -1
- package/dist/drafts/store.d.ts +4 -1
- package/dist/drafts/store.d.ts.map +1 -1
- package/dist/drafts/store.js +7 -2
- package/dist/drafts/store.js.map +1 -1
- package/dist/initAgents.d.ts.map +1 -1
- package/dist/initAgents.js +69 -21
- package/dist/initAgents.js.map +1 -1
- package/dist/requestConnection.d.ts +5 -3
- package/dist/requestConnection.d.ts.map +1 -1
- package/dist/requestConnection.js +11 -5
- package/dist/requestConnection.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +26 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/connection.tools.d.ts.map +1 -1
- package/dist/tools/connection.tools.js +12 -10
- package/dist/tools/connection.tools.js.map +1 -1
- package/dist/tools/discovery.tools.d.ts.map +1 -1
- package/dist/tools/discovery.tools.js +94 -2
- package/dist/tools/discovery.tools.js.map +1 -1
- package/dist/tools/formulas.tools.d.ts +7 -0
- package/dist/tools/formulas.tools.d.ts.map +1 -0
- package/dist/tools/formulas.tools.js +56 -0
- package/dist/tools/formulas.tools.js.map +1 -0
- package/dist/tools/heal.tools.d.ts +17 -0
- package/dist/tools/heal.tools.d.ts.map +1 -0
- package/dist/tools/heal.tools.js +76 -0
- package/dist/tools/heal.tools.js.map +1 -0
- package/dist/tools/recording.tools.d.ts.map +1 -1
- package/dist/tools/recording.tools.js +34 -12
- package/dist/tools/recording.tools.js.map +1 -1
- package/dist/tools/run.tools.d.ts.map +1 -1
- package/dist/tools/run.tools.js +378 -37
- package/dist/tools/run.tools.js.map +1 -1
- package/dist/tools/storySync.tools.d.ts +66 -0
- package/dist/tools/storySync.tools.d.ts.map +1 -0
- package/dist/tools/storySync.tools.js +213 -0
- package/dist/tools/storySync.tools.js.map +1 -0
- package/dist/tools/testcase.tools.d.ts.map +1 -1
- package/dist/tools/testcase.tools.js +24 -9
- package/dist/tools/testcase.tools.js.map +1 -1
- package/dist/tools/testdata.tools.d.ts +7 -0
- package/dist/tools/testdata.tools.d.ts.map +1 -0
- package/dist/tools/testdata.tools.js +161 -0
- package/dist/tools/testdata.tools.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Simplify3x MCP
|
|
2
2
|
|
|
3
3
|
One **product-neutral MCP** that AI clients (Claude Code, Cursor, Windsurf, VS Code, Codex, …)
|
|
4
4
|
connect to with a single URL + token, and which **routes** the whole test-case lifecycle —
|
|
@@ -12,7 +12,7 @@ The client sees **one tool vocabulary** and **one neutral data model** regardles
|
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
┌─▶ Walnut agent /mcp ─▶ Walnut backend (+ web & mainframe recording)
|
|
15
|
-
AI client ──MCP (url+token)──▶
|
|
15
|
+
AI client ──MCP (url+token)──▶ SIMPLIFY3X MCP ─┤─▶ Walnut backend REST (lifecycle only)
|
|
16
16
|
└─▶ SimplifyQA agent /mcp ─▶ SQA backend
|
|
17
17
|
```
|
|
18
18
|
|
|
@@ -22,19 +22,25 @@ AI client ──MCP (url+token)──▶ COMMON QA MCP ─┤─▶ Walnut backe
|
|
|
22
22
|
(`tc_draft_*`), then promote them to automated in place.
|
|
23
23
|
- **Record automated test cases** — delegate a goal to a technology sub-agent that drives a **real
|
|
24
24
|
browser** (`web`) or a **TN3270 mainframe terminal** (`mainframe`), capturing real
|
|
25
|
-
locators/fields and assertions. _(Requires the
|
|
25
|
+
locators/fields and assertions. _(Requires the Simplifyqa agent — see below. `android` / `db` are
|
|
26
26
|
declared but not built yet.)_
|
|
27
27
|
- **Run & triage** — execute a test case or a suite **local or cloud**, poll status, and report the
|
|
28
28
|
failing step + report link.
|
|
29
29
|
- **Modify** — edit an existing test case's steps (loop / if-else / nested / add / remove / move)
|
|
30
30
|
without re-recording the structure.
|
|
31
|
+
- **Sync a story to its test cases** — compare a user story's acceptance criteria against every
|
|
32
|
+
linked **manual** test case and get a structured drift report with the exact draft ops
|
|
33
|
+
(`add_step` / `update_step` / `remove_step`) to re-align them. Report-only; the caller applies
|
|
34
|
+
the ops via `tc_draft_open` → `tc_draft_update` → `tc_save` on the **same** TC id, so params,
|
|
35
|
+
testdata, run history, and suite membership are preserved. Automation TCs are routed to
|
|
36
|
+
`skipped[]` (v1 scope — automation drift needs recording). (`story_sync_testcases`)
|
|
31
37
|
|
|
32
38
|
## How recording works (and what it needs)
|
|
33
39
|
Recording can't run inside an `npx` gateway — `web` needs a real browser/Electron window and
|
|
34
|
-
`mainframe` needs an HLLAPI terminal attachment. That engine lives in the **
|
|
40
|
+
`mainframe` needs an HLLAPI terminal attachment. That engine lives in the **Simplifyqa agent**, which
|
|
35
41
|
mounts this same core with the extra deps injected. So:
|
|
36
42
|
|
|
37
|
-
- Point **`QA_MCP_URL` at the
|
|
43
|
+
- Point **`QA_MCP_URL` at the Simplifyqa agent's `/mcp`** (default `http://127.0.0.1:4040/mcp`) and the
|
|
38
44
|
gateway **relays** the recording tools to it — you get the full surface.
|
|
39
45
|
- Point it at the **backend REST URL** for a zero-agent gateway: discovery / drafts / save / run,
|
|
40
46
|
**no recording**.
|
|
@@ -53,19 +59,19 @@ Nothing to build or clone — AI clients launch it over stdio with `npx`. Requir
|
|
|
53
59
|
```json
|
|
54
60
|
{
|
|
55
61
|
"mcpServers": {
|
|
56
|
-
"common-qa": {
|
|
62
|
+
"common-qa-mcp": {
|
|
57
63
|
"command": "npx",
|
|
58
64
|
"args": ["-y", "common-qa-mcp"],
|
|
59
65
|
"env": {
|
|
60
|
-
"QA_MCP_URL": "http://127.0.0.1:
|
|
66
|
+
"QA_MCP_URL": "http://127.0.0.1:4040/mcp",
|
|
61
67
|
"QA_MCP_TOKEN": "<token>",
|
|
62
|
-
"QA_MCP_PRODUCT": "walnut"
|
|
68
|
+
"QA_MCP_PRODUCT": "walnut/Simplifyqa"
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
73
|
```
|
|
68
|
-
- `QA_MCP_URL` — the Walnut **agent** (`…:
|
|
74
|
+
- `QA_MCP_URL` — the Walnut/Simplifyqa **agent** (`…:4040/mcp`) for the full surface incl. recording, or the
|
|
69
75
|
**backend REST** URL for lifecycle only.
|
|
70
76
|
- `QA_MCP_TOKEN` — your **raw** auth token (JWT, **no** `Bearer` prefix).
|
|
71
77
|
- `QA_MCP_PRODUCT` — `walnut` (default) or `simplifyqa`.
|
|
@@ -77,8 +83,17 @@ can connect from chat with `qa_connect`.
|
|
|
77
83
|
|
|
78
84
|
Install the QA agent (persona + tool guidance) into your project:
|
|
79
85
|
```bash
|
|
80
|
-
npx common-qa-mcp init-agents --loop=claude
|
|
86
|
+
npx common-qa-mcp init-agents --loop=claude --server-name <server-name> # claude | cursor | windsurf | vscode | codex | devin | all
|
|
81
87
|
```
|
|
88
|
+
The generated agent files scope tool access to this MCP with a wildcard (`mcp__<server>__*` for
|
|
89
|
+
Claude/Devin, `<server>/*` for VS Code) — so **every** QA tool is available and **none** of the
|
|
90
|
+
editor's own tools leak in. (Cursor and Windsurf install as *rules*, Codex as `AGENTS.md` — those
|
|
91
|
+
formats have no tool-allowlist field, so the QA tool list rides along as in-body guidance there.)
|
|
92
|
+
The `<server>` must match the server name in your editor's MCP config
|
|
93
|
+
(each editor keeps that config in its own file), so it defaults to `common-qa-mcp` and can be set
|
|
94
|
+
explicitly with `--server-name <name>`. Name your server `common-qa-mcp` in the config above (or pass
|
|
95
|
+
`--server-name`) so the wildcard resolves.
|
|
96
|
+
|
|
82
97
|
The installed agent asks which **technology** (web / mainframe / android / db) and **manual or
|
|
83
98
|
automated** before recording, and **never saves on its own** — it persists a test case only when you
|
|
84
99
|
explicitly tell it to.
|
|
@@ -88,63 +103,3 @@ Reload your client, then drive it in plain language:
|
|
|
88
103
|
- _"List my projects"_ → _"switch to project X"_
|
|
89
104
|
- _"Record a login test on web"_ → answer the setup questions → review the draft → _"save this test case"_
|
|
90
105
|
- _"Run TC_123 on cloud"_ · _"show me the login stories"_ · _"add a loop around steps 3–5 of TC_42"_
|
|
91
|
-
|
|
92
|
-
## Develop
|
|
93
|
-
```bash
|
|
94
|
-
npm install
|
|
95
|
-
npm run build # tsc -> dist/
|
|
96
|
-
npm start # stdio server from dist/ (what npx runs)
|
|
97
|
-
npm run dev # same, via tsx, no build step
|
|
98
|
-
npm run start:http # HTTP gateway on http://127.0.0.1:4060/mcp (override with PORT=)
|
|
99
|
-
npm run dev:http # HTTP gateway via tsx watch
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Connect over HTTP (config-based, no chat)
|
|
103
|
-
`.mcp.json`:
|
|
104
|
-
```json
|
|
105
|
-
{
|
|
106
|
-
"mcpServers": {
|
|
107
|
-
"common-qa": {
|
|
108
|
-
"type": "http",
|
|
109
|
-
"url": "http://127.0.0.1:4060/mcp",
|
|
110
|
-
"headers": {
|
|
111
|
-
"Authorization": "Bearer <token>",
|
|
112
|
-
"x-qa-product": "walnut",
|
|
113
|
-
"x-qa-url": "http://127.0.0.1:4050/mcp"
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
Switch `x-qa-product` to `simplifyqa` and point `x-qa-url` at the SimplifyQA agent's `/mcp` to route
|
|
120
|
-
there instead. Everything after `Authorization` may also be passed as `?query` params, and falls
|
|
121
|
-
back to the `QA_MCP_*` environment. At runtime, `qa_connect` / `qa_switch_project` override the
|
|
122
|
-
connection without re-entering credentials.
|
|
123
|
-
|
|
124
|
-
## What's inside (for contributors)
|
|
125
|
-
The **standalone gateway** build of the neutral core — the lifecycle surface plus the recording
|
|
126
|
-
**relay**. Files under `src/`:
|
|
127
|
-
|
|
128
|
-
- `adapters/` — the `ProviderAdapter` contract + `walnut/` (REST), `remoteMcp/` (relays to the
|
|
129
|
-
Walnut agent / SimplifyQA over MCP), and the adapter factory.
|
|
130
|
-
- `connection.ts` / `requestConnection.ts` — the runtime connection (URL + token, in-memory,
|
|
131
|
-
validate-before-adopt) and the header/URL-based config connection.
|
|
132
|
-
- `domain/` — the neutral data model + validation.
|
|
133
|
-
- `drafts/` — the edit-before-save draft store.
|
|
134
|
-
- `tools/` — the client-facing tools: `connection.tools` (`qa_connect` / `qa_switch_project` / …),
|
|
135
|
-
`discovery.tools` (`list_projects` / `tc_list` / `tc_get`), `testcase.tools` (`tc_draft_*`),
|
|
136
|
-
`recording.tools` (relayed `web` / `mainframe` + their status polls), `run.tools`, plus
|
|
137
|
-
`markdown` / `schemas`.
|
|
138
|
-
- `server.ts` — assembles the MCP (`buildServer`).
|
|
139
|
-
- `mount.ts` / `httpMain.ts` — the standalone Streamable-HTTP `/mcp` gateway + its entrypoint.
|
|
140
|
-
- `vendor/` — self-contained files vendored from the Walnut agent (`logger`, `actionSignatures`, `bridge`).
|
|
141
|
-
|
|
142
|
-
> The browser/Electron recording **engine** and the live editor themselves stay in the **Walnut
|
|
143
|
-
> agent** (they need a real window). This gateway **relays** those tools whenever `QA_MCP_URL`
|
|
144
|
-
> targets the agent's `/mcp`.
|
|
145
|
-
|
|
146
|
-
## SimplifyQA integration
|
|
147
|
-
The SimplifyQA agent implements its own MCP exposing the provider-operation tools this gateway calls
|
|
148
|
-
(`info`, `list_projects`, `list_testcases`, `get_testcase`, `create_testcase`, `update_testcase`,
|
|
149
|
-
`start_run`, `get_run`, `stop_run`, …) returning the neutral shapes. See the integration guide for
|
|
150
|
-
the full contract.
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import type { ProviderAdapter } from './types.js';
|
|
2
2
|
import type { QaConfig } from '../config.js';
|
|
3
3
|
/**
|
|
4
|
-
* Builds the adapter for the current connection.
|
|
4
|
+
* Builds the adapter for the current connection (design note §3).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Routing (non-breaking, purely additive):
|
|
7
|
+
* - offline → null (draft authoring needs no backend).
|
|
8
|
+
* - simplifyqa WITH a resolvable REST base (explicit `baseUrl` OR a JWT `url` claim on the token)
|
|
9
|
+
* → SimplifyQaAdapter: DIRECT to the SimplifyQA TM backend REST, plus an OPTIONAL agent hop
|
|
10
|
+
* (`config.url` = the local agent /mcp) for the recording surface + writes not yet ported.
|
|
11
|
+
* - simplifyqa WITHOUT any REST base → RemoteMcpAdapter (LEGACY pure-forwarder; existing configs
|
|
12
|
+
* that use only QA_MCP_URL keep working exactly as before).
|
|
13
|
+
* - walnut WITH `baseUrl` (QA_BASE_URL) → WalnutAdapter: DIRECT to the Walnut backend REST, plus an
|
|
14
|
+
* OPTIONAL agent hop (`config.url` = the local agent /mcp) for recording + save-with-editor. This
|
|
15
|
+
* lets a cloud editor with no local agent drive the whole lifecycle except recording.
|
|
16
|
+
* - walnut WITHOUT `baseUrl` (only `config.url` set) → RemoteMcpAdapter: the LEGACY pure-forwarder,
|
|
17
|
+
* so existing configs (QA_MCP_URL = agent, no QA_BASE_URL) keep working exactly as before.
|
|
11
18
|
*
|
|
12
|
-
*
|
|
19
|
+
* `WalnutAdapter` and `SimplifyQaAdapter` implement only their direct-REST subsets of
|
|
20
|
+
* `ProviderAdapter` (writes / testdata / run dispatch / … are ported incrementally), so the cast
|
|
21
|
+
* bridges the gap — unported ops on those adapters delegate to their agent hop when configured, or
|
|
22
|
+
* throw a clear "not yet ported / configure the hop" error otherwise.
|
|
13
23
|
*/
|
|
14
24
|
export declare function createAdapter(config: QaConfig): ProviderAdapter | null;
|
|
15
25
|
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAqB,QAAQ,EAAE,MAAM,cAAc,CAAC;AAKhE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,GAAG,eAAe,GAAG,IAAI,CAgBtE"}
|
package/dist/adapters/factory.js
CHANGED
|
@@ -1,18 +1,72 @@
|
|
|
1
1
|
import { RemoteMcpAdapter } from './remoteMcp/adapter.js';
|
|
2
|
+
import { WalnutAdapter } from './walnut/adapter.js';
|
|
3
|
+
import { SimplifyQaAdapter } from './simplifyqa/adapter.js';
|
|
2
4
|
/**
|
|
3
|
-
* Builds the adapter for the current connection.
|
|
5
|
+
* Builds the adapter for the current connection (design note §3).
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Routing (non-breaking, purely additive):
|
|
8
|
+
* - offline → null (draft authoring needs no backend).
|
|
9
|
+
* - simplifyqa WITH a resolvable REST base (explicit `baseUrl` OR a JWT `url` claim on the token)
|
|
10
|
+
* → SimplifyQaAdapter: DIRECT to the SimplifyQA TM backend REST, plus an OPTIONAL agent hop
|
|
11
|
+
* (`config.url` = the local agent /mcp) for the recording surface + writes not yet ported.
|
|
12
|
+
* - simplifyqa WITHOUT any REST base → RemoteMcpAdapter (LEGACY pure-forwarder; existing configs
|
|
13
|
+
* that use only QA_MCP_URL keep working exactly as before).
|
|
14
|
+
* - walnut WITH `baseUrl` (QA_BASE_URL) → WalnutAdapter: DIRECT to the Walnut backend REST, plus an
|
|
15
|
+
* OPTIONAL agent hop (`config.url` = the local agent /mcp) for recording + save-with-editor. This
|
|
16
|
+
* lets a cloud editor with no local agent drive the whole lifecycle except recording.
|
|
17
|
+
* - walnut WITHOUT `baseUrl` (only `config.url` set) → RemoteMcpAdapter: the LEGACY pure-forwarder,
|
|
18
|
+
* so existing configs (QA_MCP_URL = agent, no QA_BASE_URL) keep working exactly as before.
|
|
10
19
|
*
|
|
11
|
-
*
|
|
20
|
+
* `WalnutAdapter` and `SimplifyQaAdapter` implement only their direct-REST subsets of
|
|
21
|
+
* `ProviderAdapter` (writes / testdata / run dispatch / … are ported incrementally), so the cast
|
|
22
|
+
* bridges the gap — unported ops on those adapters delegate to their agent hop when configured, or
|
|
23
|
+
* throw a clear "not yet ported / configure the hop" error otherwise.
|
|
12
24
|
*/
|
|
13
25
|
export function createAdapter(config) {
|
|
14
26
|
if (config.mode !== 'connected')
|
|
15
27
|
return null;
|
|
28
|
+
if (config.provider === 'simplifyqa') {
|
|
29
|
+
const restBase = resolveSqaBaseUrl(config);
|
|
30
|
+
if (restBase) {
|
|
31
|
+
// Ensure the adapter sees the resolved base (JWT-derived fallback is applied here, not deeper).
|
|
32
|
+
const cfgWithBase = restBase === config.baseUrl ? config : { ...config, baseUrl: restBase };
|
|
33
|
+
return new SimplifyQaAdapter(cfgWithBase);
|
|
34
|
+
}
|
|
35
|
+
return new RemoteMcpAdapter(config);
|
|
36
|
+
}
|
|
37
|
+
// walnut (the default): direct REST when a backend base is set, else the legacy forwarder.
|
|
38
|
+
if (config.baseUrl)
|
|
39
|
+
return new WalnutAdapter(config);
|
|
16
40
|
return new RemoteMcpAdapter(config);
|
|
17
41
|
}
|
|
42
|
+
/** Resolve the REST base URL for SQA: explicit `cfg.baseUrl` wins; else the JWT's `url` claim
|
|
43
|
+
* (SQA tokens embed the TM base). Returns undefined if neither is available — factory falls back
|
|
44
|
+
* to the RemoteMcpAdapter forwarder in that case. */
|
|
45
|
+
function resolveSqaBaseUrl(cfg) {
|
|
46
|
+
const explicit = cfg.baseUrl?.trim();
|
|
47
|
+
if (explicit)
|
|
48
|
+
return explicit;
|
|
49
|
+
return jwtStringClaim(cfg.token, 'url');
|
|
50
|
+
}
|
|
51
|
+
/** Decode a string claim from a JWT payload WITHOUT verifying the signature. Verification is the
|
|
52
|
+
* backend's job; this only extracts the `url` claim SQA embeds. Returns undefined on any parse
|
|
53
|
+
* failure — never throws. Mirrors Jwt.claim in the SQA server, and userIdFromJwt in walnut. */
|
|
54
|
+
function jwtStringClaim(token, name) {
|
|
55
|
+
if (!token)
|
|
56
|
+
return undefined;
|
|
57
|
+
try {
|
|
58
|
+
const t = token.startsWith('Bearer ') ? token.slice(7).trim() : token.trim();
|
|
59
|
+
const seg = t.split('.')[1];
|
|
60
|
+
if (!seg)
|
|
61
|
+
return undefined;
|
|
62
|
+
let b64 = seg.replace(/-/g, '+').replace(/_/g, '/');
|
|
63
|
+
b64 += '='.repeat((4 - (b64.length % 4)) % 4);
|
|
64
|
+
const claims = JSON.parse(Buffer.from(b64, 'base64').toString('utf8'));
|
|
65
|
+
const v = claims[name];
|
|
66
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
18
72
|
//# sourceMappingURL=factory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,aAAa,CAAC,MAAgB;IAC5C,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAE7C,IAAI,MAAM,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACb,gGAAgG;YAChG,MAAM,WAAW,GAAsB,QAAQ,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YAC/G,OAAO,IAAI,iBAAiB,CAAC,WAAW,CAA+B,CAAC;QAC1E,CAAC;QACD,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,2FAA2F;IAC3F,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,IAAI,aAAa,CAAC,MAAM,CAA+B,CAAC;IACnF,OAAO,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;sDAEsD;AACtD,SAAS,iBAAiB,CAAC,GAAsB;IAC/C,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;IACrC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,OAAO,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED;;gGAEgG;AAChG,SAAS,cAAc,CAAC,KAAyB,EAAE,IAAY;IAC7D,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7E,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,IAAI,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACpD,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA4B,CAAC;QAClG,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by every QaHttp method on any non-2xx response. Downstream adapters branch
|
|
3
|
+
* on `status` (e.g. the 409 optimistic-concurrency retry, the 503
|
|
4
|
+
* EXECUTIONS_RESERVE_FIRST guidance) so `status` must be the exact upstream HTTP
|
|
5
|
+
* status code. `body` is a return value on the error, not a log line -- safe to
|
|
6
|
+
* surface to the model/user; the HTTP layer itself never logs bodies or headers.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ApiError extends Error {
|
|
9
|
+
readonly status: number;
|
|
10
|
+
readonly body: string;
|
|
11
|
+
readonly url: string;
|
|
12
|
+
constructor(status: number, body: string, url: string);
|
|
13
|
+
}
|
|
14
|
+
export type MakeClientOptions = {
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
headers: () => Record<string, string>;
|
|
17
|
+
/**
|
|
18
|
+
* Injectable transport. Defaults to the ambient global `fetch` (Node >=20's native
|
|
19
|
+
* Fetch API) -- production code never overrides this. Tests inject a matching
|
|
20
|
+
* implementation (e.g. undici's own `fetch` export, paired with `FormDataImpl`
|
|
21
|
+
* below) instead of mutating `globalThis`, since Node's bundled internal undici
|
|
22
|
+
* and an installed `undici` devDependency are distinct module instances that do
|
|
23
|
+
* not share MockAgent's dispatcher registry.
|
|
24
|
+
*/
|
|
25
|
+
fetchImpl?: typeof fetch;
|
|
26
|
+
/**
|
|
27
|
+
* Paired with `fetchImpl`. Verified empirically: a `FormData` instance built from
|
|
28
|
+
* the *ambient* global `FormData` constructor, handed to a *different* fetch
|
|
29
|
+
* implementation's multipart encoder, fails that encoder's internal `instanceof`
|
|
30
|
+
* check and silently degrades the whole request body to the string
|
|
31
|
+
* "[object FormData]" instead of an actual multipart payload. Whenever
|
|
32
|
+
* `fetchImpl` is overridden, `FormDataImpl` must come from the same
|
|
33
|
+
* implementation family.
|
|
34
|
+
*/
|
|
35
|
+
FormDataImpl?: typeof FormData;
|
|
36
|
+
/** Paired with FormDataImpl for symmetry; defaults to the ambient global `Blob`. */
|
|
37
|
+
BlobImpl?: typeof Blob;
|
|
38
|
+
};
|
|
39
|
+
export type QaHttp = {
|
|
40
|
+
getJson<T = unknown>(path: string): Promise<T>;
|
|
41
|
+
postJson<T = unknown>(path: string, body: unknown): Promise<T>;
|
|
42
|
+
putJson<T = unknown>(path: string, body: unknown): Promise<T>;
|
|
43
|
+
patchJson<T = unknown>(path: string, body: unknown): Promise<T>;
|
|
44
|
+
del(path: string): Promise<void>;
|
|
45
|
+
postMultipart<T = unknown>(path: string, partName: string, json: unknown): Promise<T>;
|
|
46
|
+
putMultipart?<T = unknown>(path: string, partName: string, json: unknown): Promise<T>;
|
|
47
|
+
};
|
|
48
|
+
/** Builds a QaHttp bound to one base URL + one headers-callback (one product connection). */
|
|
49
|
+
export declare function makeClient(opts: MakeClientOptions): QaHttp;
|
|
50
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/adapters/http.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAET,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAOtD;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAGhB,OAAO,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,QAAQ,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,IAAI,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC9D,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAChE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjC,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAKtF,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACvF,CAAC;AAuDF,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAwB1D"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { log } from '../log.js';
|
|
2
|
+
// First N characters of a non-2xx response body kept on the thrown error -- enough
|
|
3
|
+
// for a caller to show useful diagnostic text without risking logging/echoing an
|
|
4
|
+
// unbounded (or sensitive-data-laden) upstream error page.
|
|
5
|
+
const BODY_SNIPPET_LEN = 500;
|
|
6
|
+
// Default per-request timeout. Without one, a stalled upstream (backend or the
|
|
7
|
+
// external DATA_GENERATION_URL proxy behind /tm/customFormula) freezes the whole
|
|
8
|
+
// tool call forever and the MCP client just sits at "in progress". Override with
|
|
9
|
+
// QA_HTTP_TIMEOUT_MS. 30s is generous for slow proxies; individual callers can
|
|
10
|
+
// tighten it later if needed.
|
|
11
|
+
const DEFAULT_TIMEOUT_MS = Number.parseInt(process.env['QA_HTTP_TIMEOUT_MS'] ?? '30000', 10);
|
|
12
|
+
/**
|
|
13
|
+
* Thrown by every QaHttp method on any non-2xx response. Downstream adapters branch
|
|
14
|
+
* on `status` (e.g. the 409 optimistic-concurrency retry, the 503
|
|
15
|
+
* EXECUTIONS_RESERVE_FIRST guidance) so `status` must be the exact upstream HTTP
|
|
16
|
+
* status code. `body` is a return value on the error, not a log line -- safe to
|
|
17
|
+
* surface to the model/user; the HTTP layer itself never logs bodies or headers.
|
|
18
|
+
*/
|
|
19
|
+
export class ApiError extends Error {
|
|
20
|
+
constructor(status, body, url) {
|
|
21
|
+
super(`HTTP ${status} ${url}`);
|
|
22
|
+
this.name = 'ApiError';
|
|
23
|
+
this.status = status;
|
|
24
|
+
this.body = body;
|
|
25
|
+
this.url = url;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function joinUrl(baseUrl, path) {
|
|
29
|
+
const base = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
|
|
30
|
+
const suffix = path.startsWith('/') ? path : `/${path}`;
|
|
31
|
+
return `${base}${suffix}`;
|
|
32
|
+
}
|
|
33
|
+
// Every request funnels through here: resolves the url, merges fresh auth headers
|
|
34
|
+
// with any per-call headers, reads the body once as text, logs method+path+status
|
|
35
|
+
// only (never body/headers -- both carry tokens and test data), and shapes any
|
|
36
|
+
// non-2xx into ApiError. Callers parse the returned text as needed (or ignore it,
|
|
37
|
+
// for `del`).
|
|
38
|
+
async function send(opts, method, path, init = {}) {
|
|
39
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
40
|
+
const url = joinUrl(opts.baseUrl, path);
|
|
41
|
+
// Built incrementally (not `{ method, body: init.body, headers: {...} }`) so the
|
|
42
|
+
// `body` key is omitted entirely when absent, rather than present-with-`undefined`
|
|
43
|
+
// -- required under exactOptionalPropertyTypes, since DOM's RequestInit.body is
|
|
44
|
+
// typed `BodyInit | null` (no `| undefined`) though the property itself is optional.
|
|
45
|
+
const requestInit = { method, headers: { ...opts.headers(), ...init.headers } };
|
|
46
|
+
if (init.body !== undefined)
|
|
47
|
+
requestInit.body = init.body;
|
|
48
|
+
// AbortSignal.timeout throws a DOMException("TimeoutError") after N ms. Wrap fetch so a hung
|
|
49
|
+
// upstream surfaces a readable error instead of leaving the tool call pending forever.
|
|
50
|
+
if (Number.isFinite(DEFAULT_TIMEOUT_MS) && DEFAULT_TIMEOUT_MS > 0) {
|
|
51
|
+
requestInit.signal = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
|
|
52
|
+
}
|
|
53
|
+
let res;
|
|
54
|
+
try {
|
|
55
|
+
res = await doFetch(url, requestInit);
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
if (e instanceof Error && (e.name === 'TimeoutError' || e.name === 'AbortError')) {
|
|
59
|
+
throw new Error(`HTTP ${method} ${path} timed out after ${DEFAULT_TIMEOUT_MS}ms (upstream did not respond).`);
|
|
60
|
+
}
|
|
61
|
+
throw e;
|
|
62
|
+
}
|
|
63
|
+
const text = await res.text();
|
|
64
|
+
log(method, path, res.status);
|
|
65
|
+
if (res.status < 200 || res.status >= 300) {
|
|
66
|
+
throw new ApiError(res.status, text.slice(0, BODY_SNIPPET_LEN), url);
|
|
67
|
+
}
|
|
68
|
+
return text;
|
|
69
|
+
}
|
|
70
|
+
function parseJson(text) {
|
|
71
|
+
return (text.length ? JSON.parse(text) : undefined);
|
|
72
|
+
}
|
|
73
|
+
const JSON_HEADERS = { 'Content-Type': 'application/json' };
|
|
74
|
+
/** Builds a QaHttp bound to one base URL + one headers-callback (one product connection). */
|
|
75
|
+
export function makeClient(opts) {
|
|
76
|
+
return {
|
|
77
|
+
async getJson(path) {
|
|
78
|
+
return parseJson(await send(opts, 'GET', path));
|
|
79
|
+
},
|
|
80
|
+
async postJson(path, body) {
|
|
81
|
+
return parseJson(await send(opts, 'POST', path, { body: JSON.stringify(body), headers: JSON_HEADERS }));
|
|
82
|
+
},
|
|
83
|
+
async putJson(path, body) {
|
|
84
|
+
return parseJson(await send(opts, 'PUT', path, { body: JSON.stringify(body), headers: JSON_HEADERS }));
|
|
85
|
+
},
|
|
86
|
+
async patchJson(path, body) {
|
|
87
|
+
return parseJson(await send(opts, 'PATCH', path, { body: JSON.stringify(body), headers: JSON_HEADERS }));
|
|
88
|
+
},
|
|
89
|
+
async del(path) {
|
|
90
|
+
await send(opts, 'DELETE', path);
|
|
91
|
+
},
|
|
92
|
+
async postMultipart(path, partName, json) {
|
|
93
|
+
return parseJson(await send(opts, 'POST', path, { body: multipartBody(opts, partName, json) }));
|
|
94
|
+
},
|
|
95
|
+
async putMultipart(path, partName, json) {
|
|
96
|
+
return parseJson(await send(opts, 'PUT', path, { body: multipartBody(opts, partName, json) }));
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// Shared multipart body builder — one JSON part, no explicit Content-Type header (fetch computes
|
|
101
|
+
// the boundary from FormData; setting Content-Type manually would break it).
|
|
102
|
+
function multipartBody(opts, partName, json) {
|
|
103
|
+
const FormDataCtor = opts.FormDataImpl ?? FormData;
|
|
104
|
+
const BlobCtor = opts.BlobImpl ?? Blob;
|
|
105
|
+
const form = new FormDataCtor();
|
|
106
|
+
form.append(partName, new BlobCtor([JSON.stringify(json)], { type: 'application/json' }));
|
|
107
|
+
return form;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/adapters/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
|
2
2
|
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import type { ConnectedQaConfig } from '../../config.js';
|
|
4
4
|
import type { ProjectInfo, ProviderAdapter } from '../types.js';
|
|
5
|
-
import type { ActionDef, CloudRunner, DatasetInfo, EntityRef, EnvInfo, JournalOp, JournalView, MemberOp, ObjectQuery, ProjectSummary, QaObject, RunOptions, RunRef, RunStatus, RunTarget, SavedRef, Story, StoryQuery, StorySummary, Suite, SuiteSummary, TcQuery, TcSummary, TestCase } from '../../domain/types.js';
|
|
5
|
+
import type { ActionDef, CloudRunner, DatasetInfo, DefaultIteration, EntityRef, EnvInfo, JournalOp, JournalView, MemberOp, ModuleSummary, ObjectQuery, ProjectSummary, QaObject, ReleaseQuery, ReleaseSummary, RunOptions, RunRef, RunStatus, RunTarget, SaveGeneratedIterations, SaveGeneratedIterationsResult, SavedRef, SprintQuery, SprintSummary, Story, StoryQuery, StorySummary, Suite, SuiteSummary, TcQuery, TcSummary, TestCase } from '../../domain/types.js';
|
|
6
6
|
/**
|
|
7
7
|
* RemoteMcpAdapter -- the generic "forward to a product MCP" driver of the Common QA MCP.
|
|
8
8
|
*
|
|
@@ -59,6 +59,9 @@ export declare class RemoteMcpAdapter implements ProviderAdapter {
|
|
|
59
59
|
getSuite(id: string): Promise<Suite>;
|
|
60
60
|
listStories(q: StoryQuery): Promise<StorySummary[]>;
|
|
61
61
|
getStory(id: string): Promise<Story>;
|
|
62
|
+
listModules(): Promise<ModuleSummary[]>;
|
|
63
|
+
listReleases(q: ReleaseQuery): Promise<ReleaseSummary[]>;
|
|
64
|
+
listSprints(q: SprintQuery): Promise<SprintSummary[]>;
|
|
62
65
|
readJournal(tcId: string): Promise<JournalView>;
|
|
63
66
|
editJournal(tcId: string, ops: JournalOp[]): Promise<JournalView>;
|
|
64
67
|
createSuite(s: Suite): Promise<SavedRef>;
|
|
@@ -86,6 +89,12 @@ export declare class RemoteMcpAdapter implements ProviderAdapter {
|
|
|
86
89
|
}>>;
|
|
87
90
|
listEnvironments(): Promise<EnvInfo[]>;
|
|
88
91
|
listDatasets(tcId?: string): Promise<DatasetInfo[]>;
|
|
92
|
+
getDefaultIteration(q: {
|
|
93
|
+
tcId: string;
|
|
94
|
+
versionId?: string;
|
|
95
|
+
environmentType?: string;
|
|
96
|
+
}): Promise<DefaultIteration>;
|
|
97
|
+
saveGeneratedIterations(payload: SaveGeneratedIterations): Promise<SaveGeneratedIterationsResult>;
|
|
89
98
|
getObject(id: string): Promise<QaObject>;
|
|
90
99
|
productUrlFor(entity: EntityRef): string;
|
|
91
100
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/remoteMcp/adapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,KAAK,EACV,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/remoteMcp/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,19 +28,27 @@ export class RemoteMcpAdapter {
|
|
|
28
28
|
const h = { Authorization: `Bearer ${this.cfg.token}` };
|
|
29
29
|
if (this.cfg.projectId)
|
|
30
30
|
h['x-project-id'] = this.cfg.projectId;
|
|
31
|
+
// Explicit product base URL (from `qa_connect({baseUrl})` or `QA_BASE_URL` env). Forwarded to
|
|
32
|
+
// the product MCP (Walnut or SimplifyQA) so its backend REST calls have a base — lets tokens
|
|
33
|
+
// without a JWT `url` claim still work. The product MCP prefers this header over the claim.
|
|
34
|
+
if (this.cfg.baseUrl)
|
|
35
|
+
h['x-qa-base-url'] = this.cfg.baseUrl;
|
|
31
36
|
return h;
|
|
32
37
|
}
|
|
33
38
|
async client() {
|
|
34
39
|
if (!this.clientPromise) {
|
|
35
40
|
this.clientPromise = (async () => {
|
|
36
|
-
const client = new Client({ name: 'common-qa-mcp', version: '0.
|
|
41
|
+
const client = new Client({ name: 'common-qa-mcp', version: '0.3.0' });
|
|
37
42
|
// The `as Transport` cast bridges exactOptionalPropertyTypes: StreamableHTTPClientTransport
|
|
38
43
|
// implements Transport, but the SDK's own .d.ts (built without EOPT) leaves its optional
|
|
39
44
|
// callbacks (onclose?/onerror?/onmessage?) without `| undefined`, which this project's EOPT
|
|
40
45
|
// rejects on assignment. The class genuinely satisfies the interface at runtime.
|
|
46
|
+
// `cfg.url` (the product /mcp endpoint) is optional on the shared config type now, but the
|
|
47
|
+
// factory only ever builds a RemoteMcpAdapter with it present (SimplifyQA, the legacy walnut
|
|
48
|
+
// forwarder, or WalnutAdapter's recording hop) -- so `?? ''` only satisfies the type.
|
|
41
49
|
const transport = this.transportFactory
|
|
42
50
|
? this.transportFactory()
|
|
43
|
-
: new StreamableHTTPClientTransport(new URL(this.cfg.url), { requestInit: { headers: this.headers() } });
|
|
51
|
+
: new StreamableHTTPClientTransport(new URL(this.cfg.url ?? ''), { requestInit: { headers: this.headers() } });
|
|
44
52
|
await client.connect(transport);
|
|
45
53
|
return client;
|
|
46
54
|
})().catch((e) => {
|
|
@@ -148,6 +156,15 @@ export class RemoteMcpAdapter {
|
|
|
148
156
|
async getStory(id) {
|
|
149
157
|
return this.call('get_story', { id }, 'story');
|
|
150
158
|
}
|
|
159
|
+
async listModules() {
|
|
160
|
+
return this.call('list_modules', {}, 'modules');
|
|
161
|
+
}
|
|
162
|
+
async listReleases(q) {
|
|
163
|
+
return this.call('list_releases', { scope: q.scope }, 'releases');
|
|
164
|
+
}
|
|
165
|
+
async listSprints(q) {
|
|
166
|
+
return this.call('list_sprints', q.releaseId !== undefined ? { releaseId: q.releaseId } : {}, 'sprints');
|
|
167
|
+
}
|
|
151
168
|
async readJournal(tcId) {
|
|
152
169
|
return this.call('read_journal', { id: tcId }, 'view');
|
|
153
170
|
}
|
|
@@ -205,6 +222,17 @@ export class RemoteMcpAdapter {
|
|
|
205
222
|
async listDatasets(tcId) {
|
|
206
223
|
return this.call('list_datasets', tcId !== undefined ? { tcId } : {}, 'datasets');
|
|
207
224
|
}
|
|
225
|
+
async getDefaultIteration(q) {
|
|
226
|
+
const args = { tcId: q.tcId };
|
|
227
|
+
if (q.versionId !== undefined)
|
|
228
|
+
args['versionId'] = q.versionId;
|
|
229
|
+
if (q.environmentType !== undefined)
|
|
230
|
+
args['environmentType'] = q.environmentType;
|
|
231
|
+
return this.call('get_default_iteration', args, 'iteration');
|
|
232
|
+
}
|
|
233
|
+
async saveGeneratedIterations(payload) {
|
|
234
|
+
return this.call('save_generated_iterations', payload, 'result');
|
|
235
|
+
}
|
|
208
236
|
async getObject(id) {
|
|
209
237
|
return this.call('get_object', { id }, 'object');
|
|
210
238
|
}
|
|
@@ -212,7 +240,7 @@ export class RemoteMcpAdapter {
|
|
|
212
240
|
// by create/update); this synchronous fallback is best-effort off the MCP endpoint origin -- it
|
|
213
241
|
// cannot round-trip to the remote, so callers should prefer SavedRef.productUrl when they have it.
|
|
214
242
|
productUrlFor(entity) {
|
|
215
|
-
const base = this.cfg.url.replace(/\/+$/, '').replace(/\/mcp$/i, '');
|
|
243
|
+
const base = (this.cfg.url ?? '').replace(/\/+$/, '').replace(/\/mcp$/i, '');
|
|
216
244
|
return `${base}/${entity.kind}/${entity.id}`;
|
|
217
245
|
}
|
|
218
246
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/remoteMcp/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/remoteMcp/adapter.ts"],"names":[],"mappings":"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"}
|