@chrischall/mcp-utils 0.20.0 → 0.21.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 +42 -0
- package/dist/response/index.d.ts +1 -0
- package/dist/response/index.d.ts.map +1 -1
- package/dist/response/index.js +1 -0
- package/dist/response/index.js.map +1 -1
- package/dist/response/view.d.ts +123 -0
- package/dist/response/view.d.ts.map +1 -0
- package/dist/response/view.js +150 -0
- package/dist/response/view.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -105,6 +105,48 @@ return textResult(flattenJsonApi(payload)); // collapse JSON:API envelopes
|
|
|
105
105
|
deepMapStringField(payload, 'eventDate', dmyToIso);
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
#### The `view` vocabulary — read tools answer in the cheap shape by default
|
|
109
|
+
|
|
110
|
+
`VIEWS`, `DEFAULT_VIEW`, `View`, `viewParam`, `resolveView`, `viewResult`,
|
|
111
|
+
`minifiedResult`, `projectOrRaw`. See `docs/fleet-conventions.md`
|
|
112
|
+
("Response shape") for the convention these implement.
|
|
113
|
+
|
|
114
|
+
`view: 'compact' | 'full' | 'raw'`, defaulting to **`compact`** — a projection
|
|
115
|
+
that has to be requested is one that usually is not.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { viewParam, resolveView, viewResult, projectOrRaw } from '@chrischall/mcp-utils';
|
|
119
|
+
|
|
120
|
+
const VIEWS_HERE = ['compact', 'full'] as const; // only the rungs you honour
|
|
121
|
+
|
|
122
|
+
server.registerTool('svc_list_things', {
|
|
123
|
+
inputSchema: {
|
|
124
|
+
view: viewParam(VIEWS_HERE, { note: 'compact omits the upstream `meta` echo.' }),
|
|
125
|
+
},
|
|
126
|
+
}, async (args) => {
|
|
127
|
+
const view = resolveView(args.view, VIEWS_HERE);
|
|
128
|
+
const rows = await client.list();
|
|
129
|
+
// Project the ARRAY, so one odd record cannot half-answer, and fall back to
|
|
130
|
+
// the whole payload (warning to stderr) if the upstream shape has drifted.
|
|
131
|
+
const items = view === 'compact'
|
|
132
|
+
? projectOrRaw(rows, (rs) => rs.map(compactThing), { label: 'svc-mcp', context: 'GET /things' })
|
|
133
|
+
: rows;
|
|
134
|
+
return viewResult(view, { count: rows.length, items });
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`viewParam` refuses a rung list without `compact` (a tool with no cheap answer
|
|
139
|
+
has nothing to default to) and refuses a single-rung list (a parameter that
|
|
140
|
+
decides nothing). Register only the rungs you honour: `raw` is meaningless
|
|
141
|
+
where a record is *assembled* from several endpoints rather than passed through
|
|
142
|
+
from one, and a value that silently aliases to another is a lie in the schema.
|
|
143
|
+
`raw` means "no projection" — never "no normalisation".
|
|
144
|
+
|
|
145
|
+
`viewResult` minifies `compact` and `full` and leaves `raw` indented (that rung
|
|
146
|
+
exists to be read by a person); `minifiedResult` is the same rule with no view
|
|
147
|
+
to hand. Formatting whitespace only — whitespace *inside* a value is content
|
|
148
|
+
and is never touched.
|
|
149
|
+
|
|
108
150
|
### `errors` — helpful errors
|
|
109
151
|
|
|
110
152
|
`McpToolError` and its subclasses (`SessionNotAuthenticatedError`,
|
package/dist/response/index.d.ts
CHANGED
|
@@ -48,4 +48,5 @@ export declare function pruneUndefined<T extends Record<string, unknown>>(obj: T
|
|
|
48
48
|
* rather than a 1-element array.
|
|
49
49
|
*/
|
|
50
50
|
export declare function toArray<T>(value: T | T[] | null | undefined): T[];
|
|
51
|
+
export * from './view.js';
|
|
51
52
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/response/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAIzE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAIxD;AAED,sEAAsE;AACtE,eAAO,MAAM,UAAU,mBAAa,CAAC;AAErC,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAE1D;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAI5E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAK3D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAoBxD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,CAAC,CAY5F;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMpF;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,EAAE,CAGjE"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/response/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAIzE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAIxD;AAED,sEAAsE;AACtE,eAAO,MAAM,UAAU,mBAAa,CAAC;AAErC,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAE1D;AAED,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAI5E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAK3D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAoBxD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,CAAC,CAY5F;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMpF;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,EAAE,CAGjE;AACD,cAAc,WAAW,CAAC"}
|
package/dist/response/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/response/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/response/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The fleet's response-shape vocabulary (`docs/fleet-conventions.md`,
|
|
5
|
+
* "Response shape").
|
|
6
|
+
*
|
|
7
|
+
* Every tool that reads an upstream API answers in one of three shapes, and
|
|
8
|
+
* the CHEAP one is the default. That inversion is the whole point: five repos
|
|
9
|
+
* had already grown a projection by the time this was written, and four of
|
|
10
|
+
* them made it opt-in — `compact: false` in the schema, with the tool's own
|
|
11
|
+
* description asking the model to please pass `compact=true`. An efficiency
|
|
12
|
+
* that has to be requested is one that is usually not, and the caller paying
|
|
13
|
+
* for it is the one least able to know it was available.
|
|
14
|
+
*
|
|
15
|
+
* The rungs, in ascending order of size:
|
|
16
|
+
*
|
|
17
|
+
* - **compact** — the projection: the fields a caller acts on, with anything
|
|
18
|
+
* the response already carries elsewhere removed. The default.
|
|
19
|
+
* - **full** — every field this MCP understands, nothing dropped.
|
|
20
|
+
* - **raw** — the upstream payload, unprojected.
|
|
21
|
+
*
|
|
22
|
+
* `raw` means "no projection". It NEVER means "no normalisation": a repo that
|
|
23
|
+
* rewrites values on the way out — timestamps into a single zone, ids into a
|
|
24
|
+
* stable shape — keeps doing so on every rung. Handing back the untouched wire
|
|
25
|
+
* format would reintroduce exactly the inconsistencies that normalisation
|
|
26
|
+
* exists to remove, on the one rung a caller reaches for when something
|
|
27
|
+
* already looks wrong.
|
|
28
|
+
*
|
|
29
|
+
* A tool registers only the rungs it can honour, so a schema never advertises
|
|
30
|
+
* a value that would silently alias to another: `raw` is meaningless where a
|
|
31
|
+
* record is ASSEMBLED from several endpoints rather than passed through from
|
|
32
|
+
* one, and those tools offer `compact` and `full` alone.
|
|
33
|
+
*/
|
|
34
|
+
export declare const VIEWS: readonly ["compact", "full", "raw"];
|
|
35
|
+
/** One of {@link VIEWS}: the shape a read tool answers in. */
|
|
36
|
+
export type View = (typeof VIEWS)[number];
|
|
37
|
+
/** Efficiency is not something a caller should have to ask for. */
|
|
38
|
+
export declare const DEFAULT_VIEW: View;
|
|
39
|
+
/** Per-tool tuning for {@link viewParam}. */
|
|
40
|
+
export interface ViewParamOptions {
|
|
41
|
+
/**
|
|
42
|
+
* What THIS tool's compact rung leaves out, in the tool's own words.
|
|
43
|
+
*
|
|
44
|
+
* Worth writing. The generic blurb says a projection happened; only the tool
|
|
45
|
+
* can say which field a caller who needs it should ask for `full` to get.
|
|
46
|
+
*/
|
|
47
|
+
note?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The `view` parameter, built from the rungs a tool actually honours.
|
|
51
|
+
*
|
|
52
|
+
* `view` rather than `detail`, `mode` or `compact`: `detail` is already an
|
|
53
|
+
* UPSTREAM passthrough in alltrails-mcp (`basic|medium|offline` goes into the
|
|
54
|
+
* URL), `mode` and `format` are taken elsewhere in the fleet, and `compact` as
|
|
55
|
+
* a boolean cannot express three rungs — nor say whether `compact: false`
|
|
56
|
+
* meant "everything you understand" or "everything you received".
|
|
57
|
+
*/
|
|
58
|
+
export declare function viewParam(honoured: readonly View[], opts?: ViewParamOptions): z.ZodOptional<z.ZodEnum<Record<string, string>>>;
|
|
59
|
+
/**
|
|
60
|
+
* The rung to answer in. Absent means `compact`.
|
|
61
|
+
*
|
|
62
|
+
* The schema has already rejected anything this tool does not honour, so this
|
|
63
|
+
* is the second line — and it fails toward the CHEAP answer rather than
|
|
64
|
+
* throwing, because a caller that somehow named an unavailable rung is better
|
|
65
|
+
* served by a small correct response than by an error.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveView(value: string | undefined, honoured: readonly View[]): View;
|
|
68
|
+
/**
|
|
69
|
+
* A tool result with no formatting whitespace.
|
|
70
|
+
*
|
|
71
|
+
* `JSON.stringify(data, null, 2)` — the fleet's most duplicated line — spends
|
|
72
|
+
* roughly a fifth of a large response on indentation that carries no
|
|
73
|
+
* information and that nothing downstream reads: measured at 23% of a
|
|
74
|
+
* 135 KB ofw-mcp message page, or about 8,000 tokens per call.
|
|
75
|
+
*
|
|
76
|
+
* Only FORMATTING whitespace goes. Whitespace inside a value is content — the
|
|
77
|
+
* blank line between paragraphs of a message body, the indentation of a quoted
|
|
78
|
+
* block — and `JSON.stringify` leaves every byte of it alone, because it drops
|
|
79
|
+
* only the indent and the runs after `:` and `,`. Any hand-rolled alternative
|
|
80
|
+
* (a regex over the serialised text, a collapse of `\s+`) corrupts exactly the
|
|
81
|
+
* payloads this is meant to shrink. There are tests on that; do not replace
|
|
82
|
+
* this with something cleverer.
|
|
83
|
+
*
|
|
84
|
+
* Key ORDER is untouched too, which several repos depend on (ofw-mcp emits its
|
|
85
|
+
* paging state before its data array precisely so a truncated read still sees
|
|
86
|
+
* it).
|
|
87
|
+
*/
|
|
88
|
+
export declare function minifiedResult(data: unknown): CallToolResult;
|
|
89
|
+
/**
|
|
90
|
+
* A tool result whose whitespace matches its rung: `compact` and `full` are
|
|
91
|
+
* minified, `raw` stays indented.
|
|
92
|
+
*
|
|
93
|
+
* The asymmetry is deliberate rather than an oversight. `compact` and `full`
|
|
94
|
+
* are consumed by a model, which reads the parse and not the layout. `raw` is
|
|
95
|
+
* the rung a person reaches for when a payload is not what they expected, and
|
|
96
|
+
* indentation is most of what makes an unfamiliar shape legible.
|
|
97
|
+
*/
|
|
98
|
+
export declare function viewResult(view: View, data: unknown): CallToolResult;
|
|
99
|
+
/** Who is projecting what, for the stderr line {@link projectOrRaw} writes on a fallback. */
|
|
100
|
+
export interface ProjectOptions {
|
|
101
|
+
/** The MCP's own name, for the stderr line. */
|
|
102
|
+
label: string;
|
|
103
|
+
/** Which call produced the value — the endpoint, usually. */
|
|
104
|
+
context: string;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Project a value, falling back to the RAW value if the projection fails.
|
|
108
|
+
*
|
|
109
|
+
* This is what makes compact-by-default survivable on a reverse-engineered
|
|
110
|
+
* API, and it is not optional. A projector names fields; upstream changes
|
|
111
|
+
* them; and the two failure modes that follow are an exception (loud, but it
|
|
112
|
+
* takes the whole tool call down) and an empty or half-filled record (silent,
|
|
113
|
+
* and indistinguishable from "there was nothing there") — which is the same
|
|
114
|
+
* false negative every absence-reporting guard in this fleet exists to
|
|
115
|
+
* prevent. So a projector that throws, or that returns nothing, hands back
|
|
116
|
+
* everything instead and says why on stderr.
|
|
117
|
+
*
|
|
118
|
+
* `undefined` counts as a failure. A projection legitimately has nothing to
|
|
119
|
+
* say only about a value that was already absent, and a caller cannot tell
|
|
120
|
+
* that from a projector that lost its footing.
|
|
121
|
+
*/
|
|
122
|
+
export declare function projectOrRaw<T, R>(value: T, project: (value: T) => R, opts: ProjectOptions): T | R;
|
|
123
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/response/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,KAAK,qCAAsC,CAAC;AAEzD,8DAA8D;AAC9D,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1C,mEAAmE;AACnE,eAAO,MAAM,YAAY,EAAE,IAAgB,CAAC;AAQ5C,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,EAAE,IAAI,GAAE,gBAAqB,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAmBlI;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,EAAE,GAAG,IAAI,CAEtF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CAE5D;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,GAAG,cAAc,CAEpE;AAED,6FAA6F;AAC7F,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,cAAc,GAAG,CAAC,GAAG,CAAC,CAYlG"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The fleet's response-shape vocabulary (`docs/fleet-conventions.md`,
|
|
4
|
+
* "Response shape").
|
|
5
|
+
*
|
|
6
|
+
* Every tool that reads an upstream API answers in one of three shapes, and
|
|
7
|
+
* the CHEAP one is the default. That inversion is the whole point: five repos
|
|
8
|
+
* had already grown a projection by the time this was written, and four of
|
|
9
|
+
* them made it opt-in — `compact: false` in the schema, with the tool's own
|
|
10
|
+
* description asking the model to please pass `compact=true`. An efficiency
|
|
11
|
+
* that has to be requested is one that is usually not, and the caller paying
|
|
12
|
+
* for it is the one least able to know it was available.
|
|
13
|
+
*
|
|
14
|
+
* The rungs, in ascending order of size:
|
|
15
|
+
*
|
|
16
|
+
* - **compact** — the projection: the fields a caller acts on, with anything
|
|
17
|
+
* the response already carries elsewhere removed. The default.
|
|
18
|
+
* - **full** — every field this MCP understands, nothing dropped.
|
|
19
|
+
* - **raw** — the upstream payload, unprojected.
|
|
20
|
+
*
|
|
21
|
+
* `raw` means "no projection". It NEVER means "no normalisation": a repo that
|
|
22
|
+
* rewrites values on the way out — timestamps into a single zone, ids into a
|
|
23
|
+
* stable shape — keeps doing so on every rung. Handing back the untouched wire
|
|
24
|
+
* format would reintroduce exactly the inconsistencies that normalisation
|
|
25
|
+
* exists to remove, on the one rung a caller reaches for when something
|
|
26
|
+
* already looks wrong.
|
|
27
|
+
*
|
|
28
|
+
* A tool registers only the rungs it can honour, so a schema never advertises
|
|
29
|
+
* a value that would silently alias to another: `raw` is meaningless where a
|
|
30
|
+
* record is ASSEMBLED from several endpoints rather than passed through from
|
|
31
|
+
* one, and those tools offer `compact` and `full` alone.
|
|
32
|
+
*/
|
|
33
|
+
export const VIEWS = ['compact', 'full', 'raw'];
|
|
34
|
+
/** Efficiency is not something a caller should have to ask for. */
|
|
35
|
+
export const DEFAULT_VIEW = 'compact';
|
|
36
|
+
const BLURB = {
|
|
37
|
+
compact: '"compact" (default) drops fields the response already carries elsewhere',
|
|
38
|
+
full: '"full" returns every field this server understands',
|
|
39
|
+
raw: '"raw" returns the upstream payload unprojected',
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The `view` parameter, built from the rungs a tool actually honours.
|
|
43
|
+
*
|
|
44
|
+
* `view` rather than `detail`, `mode` or `compact`: `detail` is already an
|
|
45
|
+
* UPSTREAM passthrough in alltrails-mcp (`basic|medium|offline` goes into the
|
|
46
|
+
* URL), `mode` and `format` are taken elsewhere in the fleet, and `compact` as
|
|
47
|
+
* a boolean cannot express three rungs — nor say whether `compact: false`
|
|
48
|
+
* meant "everything you understand" or "everything you received".
|
|
49
|
+
*/
|
|
50
|
+
export function viewParam(honoured, opts = {}) {
|
|
51
|
+
if (honoured.length < 2) {
|
|
52
|
+
throw new Error('viewParam needs at least two rungs: a parameter offering one value decides nothing');
|
|
53
|
+
}
|
|
54
|
+
if (!honoured.includes('compact')) {
|
|
55
|
+
// A tool whose rungs are `full` and `raw` has no cheap answer at all,
|
|
56
|
+
// which is the shape this vocabulary exists to remove — not one it should
|
|
57
|
+
// help express.
|
|
58
|
+
throw new Error('viewParam must offer "compact": a tool with no cheap rung has nothing to default to');
|
|
59
|
+
}
|
|
60
|
+
const ordered = VIEWS.filter((v) => honoured.includes(v));
|
|
61
|
+
const sentence = `Response shape: ${ordered.map((v) => BLURB[v]).join('; ')}.`;
|
|
62
|
+
// `.describe()` LAST, after `.optional()`. Applied to the enum it lands on
|
|
63
|
+
// the inner type, and the wrapper an MCP host actually reads its description
|
|
64
|
+
// off comes back blank — a parameter documented to nobody.
|
|
65
|
+
return z
|
|
66
|
+
.enum(Object.fromEntries(ordered.map((v) => [v, v])))
|
|
67
|
+
.optional()
|
|
68
|
+
.describe(opts.note ? `${sentence} ${opts.note}` : sentence);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The rung to answer in. Absent means `compact`.
|
|
72
|
+
*
|
|
73
|
+
* The schema has already rejected anything this tool does not honour, so this
|
|
74
|
+
* is the second line — and it fails toward the CHEAP answer rather than
|
|
75
|
+
* throwing, because a caller that somehow named an unavailable rung is better
|
|
76
|
+
* served by a small correct response than by an error.
|
|
77
|
+
*/
|
|
78
|
+
export function resolveView(value, honoured) {
|
|
79
|
+
return value !== undefined && honoured.includes(value) ? value : DEFAULT_VIEW;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A tool result with no formatting whitespace.
|
|
83
|
+
*
|
|
84
|
+
* `JSON.stringify(data, null, 2)` — the fleet's most duplicated line — spends
|
|
85
|
+
* roughly a fifth of a large response on indentation that carries no
|
|
86
|
+
* information and that nothing downstream reads: measured at 23% of a
|
|
87
|
+
* 135 KB ofw-mcp message page, or about 8,000 tokens per call.
|
|
88
|
+
*
|
|
89
|
+
* Only FORMATTING whitespace goes. Whitespace inside a value is content — the
|
|
90
|
+
* blank line between paragraphs of a message body, the indentation of a quoted
|
|
91
|
+
* block — and `JSON.stringify` leaves every byte of it alone, because it drops
|
|
92
|
+
* only the indent and the runs after `:` and `,`. Any hand-rolled alternative
|
|
93
|
+
* (a regex over the serialised text, a collapse of `\s+`) corrupts exactly the
|
|
94
|
+
* payloads this is meant to shrink. There are tests on that; do not replace
|
|
95
|
+
* this with something cleverer.
|
|
96
|
+
*
|
|
97
|
+
* Key ORDER is untouched too, which several repos depend on (ofw-mcp emits its
|
|
98
|
+
* paging state before its data array precisely so a truncated read still sees
|
|
99
|
+
* it).
|
|
100
|
+
*/
|
|
101
|
+
export function minifiedResult(data) {
|
|
102
|
+
return { content: [{ type: 'text', text: JSON.stringify(data) }] };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A tool result whose whitespace matches its rung: `compact` and `full` are
|
|
106
|
+
* minified, `raw` stays indented.
|
|
107
|
+
*
|
|
108
|
+
* The asymmetry is deliberate rather than an oversight. `compact` and `full`
|
|
109
|
+
* are consumed by a model, which reads the parse and not the layout. `raw` is
|
|
110
|
+
* the rung a person reaches for when a payload is not what they expected, and
|
|
111
|
+
* indentation is most of what makes an unfamiliar shape legible.
|
|
112
|
+
*/
|
|
113
|
+
export function viewResult(view, data) {
|
|
114
|
+
return view === 'raw' ? { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] } : minifiedResult(data);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Project a value, falling back to the RAW value if the projection fails.
|
|
118
|
+
*
|
|
119
|
+
* This is what makes compact-by-default survivable on a reverse-engineered
|
|
120
|
+
* API, and it is not optional. A projector names fields; upstream changes
|
|
121
|
+
* them; and the two failure modes that follow are an exception (loud, but it
|
|
122
|
+
* takes the whole tool call down) and an empty or half-filled record (silent,
|
|
123
|
+
* and indistinguishable from "there was nothing there") — which is the same
|
|
124
|
+
* false negative every absence-reporting guard in this fleet exists to
|
|
125
|
+
* prevent. So a projector that throws, or that returns nothing, hands back
|
|
126
|
+
* everything instead and says why on stderr.
|
|
127
|
+
*
|
|
128
|
+
* `undefined` counts as a failure. A projection legitimately has nothing to
|
|
129
|
+
* say only about a value that was already absent, and a caller cannot tell
|
|
130
|
+
* that from a projector that lost its footing.
|
|
131
|
+
*/
|
|
132
|
+
export function projectOrRaw(value, project, opts) {
|
|
133
|
+
try {
|
|
134
|
+
const projected = project(value);
|
|
135
|
+
if (projected === undefined) {
|
|
136
|
+
warn(opts, 'the projection produced nothing');
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
return projected;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
warn(opts, error instanceof Error ? error.message : String(error));
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function warn(opts, why) {
|
|
147
|
+
console.error(`[${opts.label}] WARNING: could not project ${opts.context} (${why}); returning the unprojected payload. ` +
|
|
148
|
+
'The upstream shape has probably changed — the projection needs updating.');
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/response/view.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/mcp-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Shared scaffolding for the chrischall MCP fleet — server bootstrap, tool-result formatting, helpful errors, hardened env/config, a bearer API-client kit, zod atoms, session registries, a fetchproxy transport adapter, auth resolver skeletons, an in-memory test harness, and opt-in HTML helpers. The generic MCP glue hoisted out of ~19 sibling servers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|