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.
@@ -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 [Doc docs](../../../docs/files/doc/index.md#parameter-annotations-in-api-descriptions) for details.
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
- All requests POST to [test.mmt.dev/echo](https://test.mmt.dev/echo) and read fields back from the echoed payload.
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
 
@@ -6,7 +6,7 @@ inputs:
6
6
  outputs:
7
7
  echoed_name: body[/<name>(.*?)</name>/]
8
8
  status_code: status
9
- url: https://test.mmt.dev/echo
9
+ url: https://test.mmt.dev/echo/xml
10
10
  method: post
11
11
  format: xml
12
12
  body:
@@ -7,7 +7,7 @@ outputs:
7
7
  echoed_name: body[/<name>(.*?)</name>/]
8
8
  has_expanded_meta: body[/<meta><\/meta>/]
9
9
  status_code: status
10
- url: https://test.mmt.dev/echo
10
+ url: https://test.mmt.dev/echo/xml
11
11
  method: post
12
12
  format: xmle
13
13
  body:
@@ -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.
@@ -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
- - Assert with `expect` on call, or `assert` / `check` steps
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
- ` : "") + ` const __mmt_originalSend = send_;
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 apiSetenvReporter = options.__mmtIsSuiteBundleChildRun === true && typeof options.reporter === "function" ? (event) => {
26872
- if (event && event.scope === "setenv") {
26873
- options.reporter({ ...event, id: event.id || options.id });
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
- apiSetenvReporter,
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
- ` : "") + ` const __mmt_originalSend = send_;
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 apiSetenvReporter = options.__mmtIsSuiteBundleChildRun === true && typeof options.reporter === "function" ? (event) => {
26872
- if (event && event.scope === "setenv") {
26873
- options.reporter({ ...event, id: event.id || options.id });
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
- apiSetenvReporter,
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.1-pre",
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",