mmt-mcp 1.45.1-pre → 1.45.3
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/dist/examples/intermediate/16_bruno_files/README.md +1 -1
- package/dist/examples/intermediate/20_document_parameters/README.md +2 -1
- package/dist/examples/intermediate/28_http_body_formats/README.md +1 -1
- package/dist/examples/intermediate/28_http_body_formats/post_xml.mmt +1 -1
- package/dist/examples/intermediate/28_http_body_formats/post_xmle.mmt +1 -1
- package/dist/examples/professional/11_token_resolution/README.md +1 -1
- package/dist/examples/professional/11_token_resolution/api/current_xml_body.mmt +15 -15
- package/dist/examples/professional/11_token_resolution/api/env_xml_body.mmt +17 -17
- package/dist/examples/professional/11_token_resolution/api/input_xml_body.mmt +25 -25
- package/dist/examples/professional/11_token_resolution/api/random_xml_body.mmt +14 -14
- package/dist/guides/generate-api.md +1 -0
- package/dist/guides/generate-test-skill.md +2 -0
- package/dist/guides/generate-test.md +5 -2
- package/dist/guides/min/test.md +1 -1
- package/dist/server.cjs +60 -5
- package/dist/server.js +60 -5
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ Use {{btn:list-tree}} in the header to pick **All** (one test) or a single reque
|
|
|
11
11
|
- `get_profile.bru`: a simple Bruno GET request with variables, headers, bearer auth, query params, and assertions.
|
|
12
12
|
- `create_user_json.bru`: a POST request with a JSON body and bearer auth.
|
|
13
13
|
- `update_profile_form.bru`: a PUT request with a form-urlencoded body.
|
|
14
|
-
- `xml_echo.bru`: a POST request with an XML text body.
|
|
14
|
+
- `xml_echo.bru`: a POST request with an XML text body to `test.mmt.dev/echo/xml`.
|
|
15
15
|
- `import_bruno_in_test.mmt`: a Multimeter test that imports a `.bru` file and calls it like any other test import.
|
|
16
16
|
|
|
17
17
|
## Importing Bruno Files From MMT
|
|
@@ -21,5 +21,6 @@ An intermediate `type: doc` example that documents input parameters with options
|
|
|
21
21
|
- **Ranges** use syntax like `<<i:page>> [1-5] Page number`.
|
|
22
22
|
- **Output annotations** use `<<o:name>> Description`.
|
|
23
23
|
- **`html.triable: true`** enables interactive Try buttons in rendered docs.
|
|
24
|
+
- Open the API file’s **Inputs** tab to pick values with the ⋯ menu on constrained fields.
|
|
24
25
|
|
|
25
|
-
See [
|
|
26
|
+
See [Input and output documentation](../../../docs/files/input-output-docs.md) for details.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Intermediate example covering every HTTP request `format:` — `json`, `xml`, `xmle`, `text`, `urlencoded`, `binary`, and `multipart`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Most requests POST to [test.mmt.dev/echo](https://test.mmt.dev/echo). XML formats (`post_xml.mmt`, `post_xmle.mmt`) use [test.mmt.dev/echo/xml](https://test.mmt.dev/echo/xml) so the response is `application/xml`.
|
|
6
6
|
|
|
7
7
|
## Files
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Token resolution
|
|
2
2
|
|
|
3
|
-
Professional samples of `e:`, `i:`, `r:`, and `c:` against [test.mmt.dev/echo](https://test.mmt.dev/echo).
|
|
3
|
+
Professional samples of `e:`, `i:`, `r:`, and `c:` against [test.mmt.dev/echo](https://test.mmt.dev/echo). XML body samples use [test.mmt.dev/echo/xml](https://test.mmt.dev/echo/xml) and read fields from the XML echo (`body.echo.body.body…`).
|
|
4
4
|
|
|
5
5
|
A whole field in a **JSON** body keeps the value's type. **XML**, **urlencoded**, **headers**, and **query** always send text. A quoted token such as `"e:account_age"` is the literal text. `omit` removes the field. `"omit"` sends the word omit. A missing `e:`, `i:`, `r:`, or `c:` token is sent as its own text, for example `e:region` or `i:nickname`.
|
|
6
6
|
|
|
@@ -2,22 +2,22 @@ type: api
|
|
|
2
2
|
title: Current tokens in an XML body
|
|
3
3
|
description: "XML element text is always a string, including c:epoch."
|
|
4
4
|
outputs:
|
|
5
|
-
day_name: body.body.day_name
|
|
6
|
-
epoch_seconds: body.body.epoch_seconds
|
|
7
|
-
city: body.body.city
|
|
8
|
-
missing_token: body.body.missing_token
|
|
9
|
-
literal_token: body.body.literal_token
|
|
10
|
-
literal_omit: body.body.literal_omit
|
|
11
|
-
angle_whole: body.body.angle_whole
|
|
12
|
-
quoted_angle: body.body.quoted_angle
|
|
13
|
-
angle_prefix: body.body.angle_prefix
|
|
14
|
-
angle_suffix: body.body.angle_suffix
|
|
15
|
-
angle_both: body.body.angle_both
|
|
16
|
-
quoted_curly: body.body.quoted_curly
|
|
17
|
-
curly_whole: body.body.curly_whole
|
|
18
|
-
text_slice: body.body.text_slice
|
|
5
|
+
day_name: body.echo.body.body.day_name
|
|
6
|
+
epoch_seconds: body.echo.body.body.epoch_seconds
|
|
7
|
+
city: body.echo.body.body.city
|
|
8
|
+
missing_token: body.echo.body.body.missing_token
|
|
9
|
+
literal_token: body.echo.body.body.literal_token
|
|
10
|
+
literal_omit: body.echo.body.body.literal_omit
|
|
11
|
+
angle_whole: body.echo.body.body.angle_whole
|
|
12
|
+
quoted_angle: body.echo.body.body.quoted_angle
|
|
13
|
+
angle_prefix: body.echo.body.body.angle_prefix
|
|
14
|
+
angle_suffix: body.echo.body.body.angle_suffix
|
|
15
|
+
angle_both: body.echo.body.body.angle_both
|
|
16
|
+
quoted_curly: body.echo.body.body.quoted_curly
|
|
17
|
+
curly_whole: body.echo.body.body.curly_whole
|
|
18
|
+
text_slice: body.echo.body.body.text_slice
|
|
19
19
|
status_code: status
|
|
20
|
-
url: https://test.mmt.dev/echo
|
|
20
|
+
url: https://test.mmt.dev/echo/xml
|
|
21
21
|
method: post
|
|
22
22
|
format: xml
|
|
23
23
|
body:
|
|
@@ -2,24 +2,24 @@ type: api
|
|
|
2
2
|
title: Env tokens in an XML body
|
|
3
3
|
description: "XML element text is always a string, including numbers and booleans from e:."
|
|
4
4
|
outputs:
|
|
5
|
-
account_age: body.body.account_age
|
|
6
|
-
feature_enabled: body.body.feature_enabled
|
|
7
|
-
plan_code: body.body.plan_code
|
|
8
|
-
plan_label: body.body.plan_label
|
|
9
|
-
service_url: body.body.service_url
|
|
10
|
-
missing_region: body.body.missing_region
|
|
11
|
-
literal_token: body.body.literal_token
|
|
12
|
-
literal_omit: body.body.literal_omit
|
|
13
|
-
angle_whole: body.body.angle_whole
|
|
14
|
-
quoted_angle: body.body.quoted_angle
|
|
15
|
-
angle_prefix: body.body.angle_prefix
|
|
16
|
-
angle_suffix: body.body.angle_suffix
|
|
17
|
-
angle_both: body.body.angle_both
|
|
18
|
-
quoted_curly: body.body.quoted_curly
|
|
19
|
-
curly_whole: body.body.curly_whole
|
|
20
|
-
text_slice: body.body.text_slice
|
|
5
|
+
account_age: body.echo.body.body.account_age
|
|
6
|
+
feature_enabled: body.echo.body.body.feature_enabled
|
|
7
|
+
plan_code: body.echo.body.body.plan_code
|
|
8
|
+
plan_label: body.echo.body.body.plan_label
|
|
9
|
+
service_url: body.echo.body.body.service_url
|
|
10
|
+
missing_region: body.echo.body.body.missing_region
|
|
11
|
+
literal_token: body.echo.body.body.literal_token
|
|
12
|
+
literal_omit: body.echo.body.body.literal_omit
|
|
13
|
+
angle_whole: body.echo.body.body.angle_whole
|
|
14
|
+
quoted_angle: body.echo.body.body.quoted_angle
|
|
15
|
+
angle_prefix: body.echo.body.body.angle_prefix
|
|
16
|
+
angle_suffix: body.echo.body.body.angle_suffix
|
|
17
|
+
angle_both: body.echo.body.body.angle_both
|
|
18
|
+
quoted_curly: body.echo.body.body.quoted_curly
|
|
19
|
+
curly_whole: body.echo.body.body.curly_whole
|
|
20
|
+
text_slice: body.echo.body.body.text_slice
|
|
21
21
|
status_code: status
|
|
22
|
-
url: https://test.mmt.dev/echo
|
|
22
|
+
url: https://test.mmt.dev/echo/xml
|
|
23
23
|
method: post
|
|
24
24
|
format: xml
|
|
25
25
|
body:
|
|
@@ -9,32 +9,32 @@ inputs:
|
|
|
9
9
|
version: "1.0"
|
|
10
10
|
price: 9.5
|
|
11
11
|
outputs:
|
|
12
|
-
username: body.body.username
|
|
13
|
-
age: body.body.age
|
|
14
|
-
active: body.body.active
|
|
15
|
-
city: body.body.city
|
|
16
|
-
missing_nickname: body.body.missing_nickname
|
|
17
|
-
literal_token: body.body.literal_token
|
|
18
|
-
literal_omit: body.body.literal_omit
|
|
19
|
-
angle_whole: body.body.angle_whole
|
|
20
|
-
quoted_angle: body.body.quoted_angle
|
|
21
|
-
angle_prefix: body.body.angle_prefix
|
|
22
|
-
angle_suffix: body.body.angle_suffix
|
|
23
|
-
angle_both: body.body.angle_both
|
|
24
|
-
quoted_curly: body.body.quoted_curly
|
|
25
|
-
curly_whole: body.body.curly_whole
|
|
26
|
-
text_slice: body.body.text_slice
|
|
27
|
-
missing_embed: body.body.missing_embed
|
|
28
|
-
attr_number: body.body.item.number
|
|
29
|
-
attr_bool: body.body.item.flag
|
|
30
|
-
attr_text: body.body.item.version
|
|
31
|
-
attr_angle: body.body.item.angle
|
|
32
|
-
attr_embedded: body.body.item.embedded
|
|
33
|
-
attr_literal: body.body.item.literal
|
|
34
|
-
attr_decimal: body.body.item.decimal
|
|
35
|
-
price_text: body.body.price
|
|
12
|
+
username: body.echo.body.body.username
|
|
13
|
+
age: body.echo.body.body.age
|
|
14
|
+
active: body.echo.body.body.active
|
|
15
|
+
city: body.echo.body.body.city
|
|
16
|
+
missing_nickname: body.echo.body.body.missing_nickname
|
|
17
|
+
literal_token: body.echo.body.body.literal_token
|
|
18
|
+
literal_omit: body.echo.body.body.literal_omit
|
|
19
|
+
angle_whole: body.echo.body.body.angle_whole
|
|
20
|
+
quoted_angle: body.echo.body.body.quoted_angle
|
|
21
|
+
angle_prefix: body.echo.body.body.angle_prefix
|
|
22
|
+
angle_suffix: body.echo.body.body.angle_suffix
|
|
23
|
+
angle_both: body.echo.body.body.angle_both
|
|
24
|
+
quoted_curly: body.echo.body.body.quoted_curly
|
|
25
|
+
curly_whole: body.echo.body.body.curly_whole
|
|
26
|
+
text_slice: body.echo.body.body.text_slice
|
|
27
|
+
missing_embed: body.echo.body.body.missing_embed
|
|
28
|
+
attr_number: body.echo.body.body.item.number
|
|
29
|
+
attr_bool: body.echo.body.body.item.flag
|
|
30
|
+
attr_text: body.echo.body.body.item.version
|
|
31
|
+
attr_angle: body.echo.body.body.item.angle
|
|
32
|
+
attr_embedded: body.echo.body.body.item.embedded
|
|
33
|
+
attr_literal: body.echo.body.body.item.literal
|
|
34
|
+
attr_decimal: body.echo.body.body.item.decimal
|
|
35
|
+
price_text: body.echo.body.body.price
|
|
36
36
|
status_code: status
|
|
37
|
-
url: https://test.mmt.dev/echo
|
|
37
|
+
url: https://test.mmt.dev/echo/xml
|
|
38
38
|
method: post
|
|
39
39
|
format: xml
|
|
40
40
|
body:
|
|
@@ -2,21 +2,21 @@ type: api
|
|
|
2
2
|
title: Random tokens in an XML body
|
|
3
3
|
description: "XML element text is always a string, including r:int and r:bool."
|
|
4
4
|
outputs:
|
|
5
|
-
request_id: body.body.request_id
|
|
6
|
-
lucky_number: body.body.lucky_number
|
|
7
|
-
active: body.body.active
|
|
8
|
-
missing_token: body.body.missing_token
|
|
9
|
-
literal_token: body.body.literal_token
|
|
10
|
-
literal_omit: body.body.literal_omit
|
|
11
|
-
angle_whole: body.body.angle_whole
|
|
12
|
-
quoted_angle: body.body.quoted_angle
|
|
13
|
-
angle_prefix: body.body.angle_prefix
|
|
14
|
-
angle_suffix: body.body.angle_suffix
|
|
15
|
-
angle_both: body.body.angle_both
|
|
16
|
-
quoted_curly: body.body.quoted_curly
|
|
17
|
-
curly_whole: body.body.curly_whole
|
|
5
|
+
request_id: body.echo.body.body.request_id
|
|
6
|
+
lucky_number: body.echo.body.body.lucky_number
|
|
7
|
+
active: body.echo.body.body.active
|
|
8
|
+
missing_token: body.echo.body.body.missing_token
|
|
9
|
+
literal_token: body.echo.body.body.literal_token
|
|
10
|
+
literal_omit: body.echo.body.body.literal_omit
|
|
11
|
+
angle_whole: body.echo.body.body.angle_whole
|
|
12
|
+
quoted_angle: body.echo.body.body.quoted_angle
|
|
13
|
+
angle_prefix: body.echo.body.body.angle_prefix
|
|
14
|
+
angle_suffix: body.echo.body.body.angle_suffix
|
|
15
|
+
angle_both: body.echo.body.body.angle_both
|
|
16
|
+
quoted_curly: body.echo.body.body.quoted_curly
|
|
17
|
+
curly_whole: body.echo.body.body.curly_whole
|
|
18
18
|
status_code: status
|
|
19
|
-
url: https://test.mmt.dev/echo
|
|
19
|
+
url: https://test.mmt.dev/echo/xml
|
|
20
20
|
method: post
|
|
21
21
|
format: xml
|
|
22
22
|
body:
|
|
@@ -65,6 +65,7 @@ Notes for the AI:
|
|
|
65
65
|
## When to use which fields
|
|
66
66
|
|
|
67
67
|
- Use **`title`** and **`description`** whenever the user describes intent or business meaning (`"login endpoint"`, `"create user"`, etc.).
|
|
68
|
+
- When documenting parameters, prefer `<<i:name>>` / `<<o:name>>` in `description`, with `[a, b]` or `[1-5]` for allowed values / ranges on inputs (⋯ picker + Doc tables).
|
|
68
69
|
- Use **`tags`** when the user mentions categories like "smoke", "load", "auth", "payments".
|
|
69
70
|
- Use **`inputs`** when the user expects to change parameters between runs (username, pagination, filters, ids, etc.).
|
|
70
71
|
- Use **`outputs`** + **`setenv`** when the user wants to **capture response data** for later steps (e.g. tokens, IDs).
|
|
@@ -53,6 +53,8 @@ steps:
|
|
|
53
53
|
status: 200
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
Prefer **inline `expect` / `require` on the `call`** for assertions about that step’s outputs. Use separate `check` / `assert` steps only for cross-step conditions.
|
|
57
|
+
|
|
56
58
|
## When to use this skill
|
|
57
59
|
|
|
58
60
|
- “Generate a test for this API.”
|
|
@@ -142,7 +142,9 @@ Beyond the basic `call`, `id`, and `inputs`, a call step also supports:
|
|
|
142
142
|
report?: all | fails | none # controls pass/fail reporting level
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
`expect` is a shorthand for common assertions — each key is a dotted path into the response, and the value is compared with `==` by default. You can prefix with an operator (e.g. `>= 1`, `!= null`).
|
|
145
|
+
`expect` is a shorthand for common assertions — each key is a dotted path into the response, and the value is compared with `==` by default. You can prefix with an operator (e.g. `>= 1`, `!= null`). Use `require` instead of `expect` when a failed comparison must **stop** the test (same map shape).
|
|
146
|
+
|
|
147
|
+
**Prefer inline `expect` / `require` on the `call` or `http` step** when the comparison is only about that step’s outputs (status, body fields, headers, …). Do **not** add a separate `- check:` / `- assert:` step for those. Reserve standalone `check` / `assert` for multi-step or cross-step conditions (comparing two step ids, values set earlier, loop state, etc.).
|
|
146
148
|
|
|
147
149
|
`debug` uses the same syntax as `expect` but never fails the test — it always logs results with a debug icon for troubleshooting. Debug entries are excluded from exported reports.
|
|
148
150
|
|
|
@@ -328,5 +330,6 @@ steps:
|
|
|
328
330
|
- Prefer small, readable tests focused on a single behavior.
|
|
329
331
|
- Prefer `steps` for simple linear flows; only use `stages` when explicit parallelism is needed.
|
|
330
332
|
- Always include `title` and `tags` (even if tags is a small list like `[smoke]`).
|
|
333
|
+
- Prefer **inline `expect` / `require` on `call` / `http`** over a following `check` / `assert` when validating only that step’s result.
|
|
331
334
|
- Avoid adding `js` steps unless the user needs custom logic that can’t be expressed with other constructs. YAML comments (`#`) are fine — Format Document preserves them. Prefer `title` / `description` for structured documentation.
|
|
332
|
-
When unsure, generate a **minimal valid test** that clearly calls the described APIs and asserts the most important property (typically HTTP status or a key field in the response).
|
|
335
|
+
When unsure, generate a **minimal valid test** that clearly calls the described APIs and asserts the most important property (typically HTTP status or a key field in the response) via inline `expect` on the call.
|
package/dist/guides/min/test.md
CHANGED
|
@@ -27,7 +27,7 @@ steps:
|
|
|
27
27
|
- Use `steps` **or** `stages`, not both
|
|
28
28
|
- Every `call` needs unique `id`
|
|
29
29
|
- Import aliases before calling them
|
|
30
|
-
-
|
|
30
|
+
- Prefer `expect` / `require` **on the call** when validating that step only; use `assert` / `check` steps for cross-step conditions
|
|
31
31
|
- No YAML comments (`#`)
|
|
32
32
|
- Tokens: `e:`, `i:`, `r:`, `c:` (snake_case)
|
|
33
33
|
|
package/dist/server.cjs
CHANGED
|
@@ -26658,7 +26658,18 @@ ${helperFactorySource}
|
|
|
26658
26658
|
const __mmt_exampleLabel = ${exampleLiteral};
|
|
26659
26659
|
` + helperDestructure + "\n" + (opts.apiFunctionSource ? `${indentMultiline(opts.apiFunctionSource, " ")}
|
|
26660
26660
|
|
|
26661
|
-
` : "") +
|
|
26661
|
+
` : "") + // Direct API runs only (this wrapper). Report wire request/response for
|
|
26662
|
+
// History; imported call: from tests does not use this wrap.
|
|
26663
|
+
` const __mmt_reportNetwork = (scope, request, response) => {
|
|
26664
|
+
if (typeof __reporter !== 'function') { return; }
|
|
26665
|
+
try {
|
|
26666
|
+
const payload = { scope: scope, request: request || {} };
|
|
26667
|
+
if (response !== undefined) { payload.response = response; }
|
|
26668
|
+
__reporter(payload);
|
|
26669
|
+
} catch (_e) {}
|
|
26670
|
+
};
|
|
26671
|
+
const __mmt_originalSend = send_;
|
|
26672
|
+
const __mmt_originalSendGrpc = typeof sendGrpc_ === 'function' ? sendGrpc_ : null;
|
|
26662
26673
|
send_ = async function(req) {
|
|
26663
26674
|
await checkAbort_();
|
|
26664
26675
|
const __req = req || {};
|
|
@@ -26689,6 +26700,7 @@ ${helperFactorySource}
|
|
|
26689
26700
|
body: __mmt_formatBodyValue(__req.body)
|
|
26690
26701
|
};
|
|
26691
26702
|
console.debug(__mmt_formatSection('Request:', __reqLog));
|
|
26703
|
+
__mmt_reportNetwork('network-request', __req);
|
|
26692
26704
|
try {
|
|
26693
26705
|
const __res = await __mmt_originalSend(req);
|
|
26694
26706
|
// Stop before Response logging when the user cancelled mid-request.
|
|
@@ -26710,6 +26722,9 @@ ${helperFactorySource}
|
|
|
26710
26722
|
if (__warning) {
|
|
26711
26723
|
console.warn(__warning);
|
|
26712
26724
|
}
|
|
26725
|
+
__mmt_reportNetwork(
|
|
26726
|
+
(typeof __status === 'number' && __status < 0) ? 'network-error' : 'network-response',
|
|
26727
|
+
__req, __res);
|
|
26713
26728
|
// Return network failures to the API function so outputs (and the
|
|
26714
26729
|
// tester Response panel) still receive the response; the wrapper
|
|
26715
26730
|
// marks the run failed after outputs are built.
|
|
@@ -26738,6 +26753,8 @@ ${helperFactorySource}
|
|
|
26738
26753
|
};
|
|
26739
26754
|
console.log(__mmt_formatSection('Response:', __resLog));
|
|
26740
26755
|
console.warn(__warning);
|
|
26756
|
+
__mmt_reportNetwork(
|
|
26757
|
+
__res.status < 0 ? 'network-error' : 'network-response', __req, __res);
|
|
26741
26758
|
return __res;
|
|
26742
26759
|
}
|
|
26743
26760
|
const __errorLog = {
|
|
@@ -26752,9 +26769,41 @@ ${helperFactorySource}
|
|
|
26752
26769
|
}
|
|
26753
26770
|
}
|
|
26754
26771
|
console.error(__mmt_formatSection('Response:', __errorLog));
|
|
26772
|
+
__mmt_reportNetwork('network-error', __req, {
|
|
26773
|
+
status: err && typeof err.status === 'number' ? err.status : -1,
|
|
26774
|
+
statusText: err && err.message ? String(err.message) : String(err),
|
|
26775
|
+
body: err && err.body,
|
|
26776
|
+
headers: err && err.headers || {},
|
|
26777
|
+
duration: err && typeof err.duration === 'number' ? err.duration : -1
|
|
26778
|
+
});
|
|
26755
26779
|
throw err;
|
|
26756
26780
|
}
|
|
26757
26781
|
};
|
|
26782
|
+
if (__mmt_originalSendGrpc) {
|
|
26783
|
+
sendGrpc_ = async function(req) {
|
|
26784
|
+
await checkAbort_();
|
|
26785
|
+
const __req = req || {};
|
|
26786
|
+
__mmt_reportNetwork('network-request', __req);
|
|
26787
|
+
try {
|
|
26788
|
+
const __res = await __mmt_originalSendGrpc(req);
|
|
26789
|
+
await checkAbort_();
|
|
26790
|
+
__mmt_reportNetwork('network-response', __req, __res);
|
|
26791
|
+
return __res;
|
|
26792
|
+
} catch (err) {
|
|
26793
|
+
if (err && (err.kind === 'test-abort' || (typeof isTestAbortError === 'function' && isTestAbortError(err)))) {
|
|
26794
|
+
throw err;
|
|
26795
|
+
}
|
|
26796
|
+
__mmt_reportNetwork('network-error', __req, {
|
|
26797
|
+
status: err && typeof err.status === 'number' ? err.status : -1,
|
|
26798
|
+
statusText: err && err.message ? String(err.message) : String(err),
|
|
26799
|
+
body: err && err.body,
|
|
26800
|
+
headers: err && err.headers || {},
|
|
26801
|
+
duration: err && typeof err.duration === 'number' ? err.duration : -1
|
|
26802
|
+
});
|
|
26803
|
+
throw err;
|
|
26804
|
+
}
|
|
26805
|
+
};
|
|
26806
|
+
}
|
|
26758
26807
|
|
|
26759
26808
|
try {
|
|
26760
26809
|
if (__mmt_exampleLabel) {
|
|
@@ -26816,6 +26865,7 @@ ${helperFactorySource}
|
|
|
26816
26865
|
return result;
|
|
26817
26866
|
} finally {
|
|
26818
26867
|
send_ = __mmt_originalSend;
|
|
26868
|
+
if (__mmt_originalSendGrpc) { sendGrpc_ = __mmt_originalSendGrpc; }
|
|
26819
26869
|
}
|
|
26820
26870
|
})();`;
|
|
26821
26871
|
}
|
|
@@ -26868,10 +26918,15 @@ async function executeApi(prepared, options, preLogs) {
|
|
|
26868
26918
|
exampleOutputs,
|
|
26869
26919
|
checkTitle: fileDisplayName
|
|
26870
26920
|
});
|
|
26871
|
-
const
|
|
26872
|
-
|
|
26873
|
-
|
|
26921
|
+
const apiReporter = typeof options.reporter === "function" ? (event) => {
|
|
26922
|
+
const isSuiteChild = options.__mmtIsSuiteBundleChildRun === true;
|
|
26923
|
+
if (isSuiteChild && event && event.scope !== "setenv") {
|
|
26924
|
+
return;
|
|
26874
26925
|
}
|
|
26926
|
+
options.reporter({
|
|
26927
|
+
...event,
|
|
26928
|
+
id: event.id || options.id
|
|
26929
|
+
});
|
|
26875
26930
|
} : void 0;
|
|
26876
26931
|
const result = await runGeneratedJs(
|
|
26877
26932
|
"run-api",
|
|
@@ -26882,7 +26937,7 @@ async function executeApi(prepared, options, preLogs) {
|
|
|
26882
26937
|
void 0,
|
|
26883
26938
|
options.id,
|
|
26884
26939
|
fileLoader,
|
|
26885
|
-
|
|
26940
|
+
apiReporter,
|
|
26886
26941
|
options.abortSignal,
|
|
26887
26942
|
void 0,
|
|
26888
26943
|
prepared.filePath ? prepared.filePath.split(/[/\\]/).slice(0, -1).join("/") : void 0,
|
package/dist/server.js
CHANGED
|
@@ -26658,7 +26658,18 @@ ${helperFactorySource}
|
|
|
26658
26658
|
const __mmt_exampleLabel = ${exampleLiteral};
|
|
26659
26659
|
` + helperDestructure + "\n" + (opts.apiFunctionSource ? `${indentMultiline(opts.apiFunctionSource, " ")}
|
|
26660
26660
|
|
|
26661
|
-
` : "") +
|
|
26661
|
+
` : "") + // Direct API runs only (this wrapper). Report wire request/response for
|
|
26662
|
+
// History; imported call: from tests does not use this wrap.
|
|
26663
|
+
` const __mmt_reportNetwork = (scope, request, response) => {
|
|
26664
|
+
if (typeof __reporter !== 'function') { return; }
|
|
26665
|
+
try {
|
|
26666
|
+
const payload = { scope: scope, request: request || {} };
|
|
26667
|
+
if (response !== undefined) { payload.response = response; }
|
|
26668
|
+
__reporter(payload);
|
|
26669
|
+
} catch (_e) {}
|
|
26670
|
+
};
|
|
26671
|
+
const __mmt_originalSend = send_;
|
|
26672
|
+
const __mmt_originalSendGrpc = typeof sendGrpc_ === 'function' ? sendGrpc_ : null;
|
|
26662
26673
|
send_ = async function(req) {
|
|
26663
26674
|
await checkAbort_();
|
|
26664
26675
|
const __req = req || {};
|
|
@@ -26689,6 +26700,7 @@ ${helperFactorySource}
|
|
|
26689
26700
|
body: __mmt_formatBodyValue(__req.body)
|
|
26690
26701
|
};
|
|
26691
26702
|
console.debug(__mmt_formatSection('Request:', __reqLog));
|
|
26703
|
+
__mmt_reportNetwork('network-request', __req);
|
|
26692
26704
|
try {
|
|
26693
26705
|
const __res = await __mmt_originalSend(req);
|
|
26694
26706
|
// Stop before Response logging when the user cancelled mid-request.
|
|
@@ -26710,6 +26722,9 @@ ${helperFactorySource}
|
|
|
26710
26722
|
if (__warning) {
|
|
26711
26723
|
console.warn(__warning);
|
|
26712
26724
|
}
|
|
26725
|
+
__mmt_reportNetwork(
|
|
26726
|
+
(typeof __status === 'number' && __status < 0) ? 'network-error' : 'network-response',
|
|
26727
|
+
__req, __res);
|
|
26713
26728
|
// Return network failures to the API function so outputs (and the
|
|
26714
26729
|
// tester Response panel) still receive the response; the wrapper
|
|
26715
26730
|
// marks the run failed after outputs are built.
|
|
@@ -26738,6 +26753,8 @@ ${helperFactorySource}
|
|
|
26738
26753
|
};
|
|
26739
26754
|
console.log(__mmt_formatSection('Response:', __resLog));
|
|
26740
26755
|
console.warn(__warning);
|
|
26756
|
+
__mmt_reportNetwork(
|
|
26757
|
+
__res.status < 0 ? 'network-error' : 'network-response', __req, __res);
|
|
26741
26758
|
return __res;
|
|
26742
26759
|
}
|
|
26743
26760
|
const __errorLog = {
|
|
@@ -26752,9 +26769,41 @@ ${helperFactorySource}
|
|
|
26752
26769
|
}
|
|
26753
26770
|
}
|
|
26754
26771
|
console.error(__mmt_formatSection('Response:', __errorLog));
|
|
26772
|
+
__mmt_reportNetwork('network-error', __req, {
|
|
26773
|
+
status: err && typeof err.status === 'number' ? err.status : -1,
|
|
26774
|
+
statusText: err && err.message ? String(err.message) : String(err),
|
|
26775
|
+
body: err && err.body,
|
|
26776
|
+
headers: err && err.headers || {},
|
|
26777
|
+
duration: err && typeof err.duration === 'number' ? err.duration : -1
|
|
26778
|
+
});
|
|
26755
26779
|
throw err;
|
|
26756
26780
|
}
|
|
26757
26781
|
};
|
|
26782
|
+
if (__mmt_originalSendGrpc) {
|
|
26783
|
+
sendGrpc_ = async function(req) {
|
|
26784
|
+
await checkAbort_();
|
|
26785
|
+
const __req = req || {};
|
|
26786
|
+
__mmt_reportNetwork('network-request', __req);
|
|
26787
|
+
try {
|
|
26788
|
+
const __res = await __mmt_originalSendGrpc(req);
|
|
26789
|
+
await checkAbort_();
|
|
26790
|
+
__mmt_reportNetwork('network-response', __req, __res);
|
|
26791
|
+
return __res;
|
|
26792
|
+
} catch (err) {
|
|
26793
|
+
if (err && (err.kind === 'test-abort' || (typeof isTestAbortError === 'function' && isTestAbortError(err)))) {
|
|
26794
|
+
throw err;
|
|
26795
|
+
}
|
|
26796
|
+
__mmt_reportNetwork('network-error', __req, {
|
|
26797
|
+
status: err && typeof err.status === 'number' ? err.status : -1,
|
|
26798
|
+
statusText: err && err.message ? String(err.message) : String(err),
|
|
26799
|
+
body: err && err.body,
|
|
26800
|
+
headers: err && err.headers || {},
|
|
26801
|
+
duration: err && typeof err.duration === 'number' ? err.duration : -1
|
|
26802
|
+
});
|
|
26803
|
+
throw err;
|
|
26804
|
+
}
|
|
26805
|
+
};
|
|
26806
|
+
}
|
|
26758
26807
|
|
|
26759
26808
|
try {
|
|
26760
26809
|
if (__mmt_exampleLabel) {
|
|
@@ -26816,6 +26865,7 @@ ${helperFactorySource}
|
|
|
26816
26865
|
return result;
|
|
26817
26866
|
} finally {
|
|
26818
26867
|
send_ = __mmt_originalSend;
|
|
26868
|
+
if (__mmt_originalSendGrpc) { sendGrpc_ = __mmt_originalSendGrpc; }
|
|
26819
26869
|
}
|
|
26820
26870
|
})();`;
|
|
26821
26871
|
}
|
|
@@ -26868,10 +26918,15 @@ async function executeApi(prepared, options, preLogs) {
|
|
|
26868
26918
|
exampleOutputs,
|
|
26869
26919
|
checkTitle: fileDisplayName
|
|
26870
26920
|
});
|
|
26871
|
-
const
|
|
26872
|
-
|
|
26873
|
-
|
|
26921
|
+
const apiReporter = typeof options.reporter === "function" ? (event) => {
|
|
26922
|
+
const isSuiteChild = options.__mmtIsSuiteBundleChildRun === true;
|
|
26923
|
+
if (isSuiteChild && event && event.scope !== "setenv") {
|
|
26924
|
+
return;
|
|
26874
26925
|
}
|
|
26926
|
+
options.reporter({
|
|
26927
|
+
...event,
|
|
26928
|
+
id: event.id || options.id
|
|
26929
|
+
});
|
|
26875
26930
|
} : void 0;
|
|
26876
26931
|
const result = await runGeneratedJs(
|
|
26877
26932
|
"run-api",
|
|
@@ -26882,7 +26937,7 @@ async function executeApi(prepared, options, preLogs) {
|
|
|
26882
26937
|
void 0,
|
|
26883
26938
|
options.id,
|
|
26884
26939
|
fileLoader,
|
|
26885
|
-
|
|
26940
|
+
apiReporter,
|
|
26886
26941
|
options.abortSignal,
|
|
26887
26942
|
void 0,
|
|
26888
26943
|
prepared.filePath ? prepared.filePath.split(/[/\\]/).slice(0, -1).join("/") : void 0,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mmt-mcp",
|
|
3
|
-
"version": "1.45.
|
|
3
|
+
"version": "1.45.3",
|
|
4
4
|
"description": "Multimeter MCP server for Cursor, Copilot, and Claude. Scaffold, validate, format, and run YAML .mmt API tests. Do not invent .mmt syntax.",
|
|
5
5
|
"mcpName": "io.github.mshobeyri/multimeter",
|
|
6
6
|
"type": "module",
|