@stratusagent/plugin-mcp 0.11.3 → 0.11.5

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.
@@ -1,4 +1,4 @@
1
- import type { JsonValue } from '@stratusagent/core';
1
+ import { type JsonValue } from '@stratusagent/core';
2
2
  import { type TaintedWriteLedger } from '@stratusagent/plugins';
3
3
  /**
4
4
  * Turning what an MCP server sends back into what a Stratus tool returns:
@@ -20,22 +20,167 @@ import { type TaintedWriteLedger } from '@stratusagent/plugins';
20
20
  export declare const sanitizeToolSegment: (raw: string) => string | undefined;
21
21
  /** Server keys are operator-chosen and become a name segment; held to the segment shape outright. */
22
22
  export declare const SERVER_NAME_PATTERN: RegExp;
23
+ /**
24
+ * The longest tool description a server gets to put in front of the model.
25
+ * The same bound a skill's description has (`SKILL_DESCRIPTION_MAX_LENGTH`
26
+ * in `@stratusagent/agents`), for the same reason: a description is prose
27
+ * the model reads on every turn, written by a party the operator did not
28
+ * author, and a paragraph is a description while a page is instructions.
29
+ */
30
+ export declare const BRIDGED_DESCRIPTION_MAX_LENGTH = 1024;
31
+ /**
32
+ * A server's tool description as it reaches the registry — and, through
33
+ * it, every provider's tool block on every turn. The text is the server's,
34
+ * re-read on every reconnect, and `tools/list` is the one channel a
35
+ * server has that arrives looking like part of the harness rather than
36
+ * like a result. Two bounds, neither a filter: control characters and the
37
+ * Unicode bidi controls are spelled out the way memory entries are (a
38
+ * right-to-left override in a description is a description that reads
39
+ * differently to a person than to the model — escaped, it reads as what it
40
+ * is; the set is Unicode's `Bidi_Control` property, marks and the Arabic
41
+ * letter mark included, not only the overrides and isolates), and the
42
+ * length is capped with the cut announced. Newlines and tabs stay: a
43
+ * description is allowed to be several lines.
44
+ */
45
+ export declare const bridgedDescription: (raw: string) => string;
46
+ /**
47
+ * The longest input schema a server gets to put in front of the model, in
48
+ * characters of its JSON. A schema is read by the provider as structure,
49
+ * but every string in it lands in the tool block as text, and sixteen
50
+ * thousand characters of parameter list is a page, not a parameter list.
51
+ */
52
+ export declare const BRIDGED_SCHEMA_MAX_LENGTH = 16384;
53
+ /**
54
+ * The most of one `tools/call` result a server gets to put into the
55
+ * transcript, in characters, counting the joined text and the JSON of
56
+ * `structuredContent` separately.
57
+ *
58
+ * Every first-party tool caps what it returns — `fs.read` at 64 KB,
59
+ * `shell.run` and `browser.read` at 100 KB, `web.fetch` at 400 KB — and
60
+ * a bridged result was the one that did not. Binary blocks already land on
61
+ * disk rather than in the result, so this is about text, and text is the
62
+ * part that is *durable*: a tool result is saved into the session and
63
+ * replayed to the provider on every later turn of that conversation, so a
64
+ * server that answers `list_files` with twenty megabytes does not cost one
65
+ * turn, it costs every turn until the session ends — and survives restarts,
66
+ * because the transcript does. The stdio transport bounds a single message
67
+ * at its reader's buffer (10 MB by default) and the HTTP transports bound
68
+ * nothing, so "the transport will stop it" was never a cap.
69
+ *
70
+ * 100 KB matches `shell.run`, which is the closest comparison: somebody
71
+ * else's program, writing as much as it likes. Counted in characters
72
+ * rather than bytes, like the two bounds above and unlike the tool packs':
73
+ * what is scarce here is the model's context, which is measured in tokens,
74
+ * and a token follows a character more closely than it follows a byte.
75
+ */
76
+ export declare const BRIDGED_RESULT_MAX_LENGTH = 100000;
77
+ /**
78
+ * The smallest `maxResultChars` that means anything, and the floor every
79
+ * smaller one is raised to.
80
+ *
81
+ * A cap has to be able to hold an account of what it cut. The four
82
+ * annotations a result can carry — a marker for the text, one for the
83
+ * structured payload, and the two truncation notes — come to a little over
84
+ * four hundred characters with the keys they arrive under, and shortening
85
+ * them is not on the table: an announcement is the whole reason a cap is
86
+ * safe to have, and a cut with nothing saying it happened is the failure
87
+ * this bound exists to prevent.
88
+ *
89
+ * So below this a cap cannot be honoured, only approximated — `1` yielded
90
+ * 73 characters for a truncated text and 104 for a dropped resource link —
91
+ * and approximating it silently is worse than raising it. Raised rather
92
+ * than refused, and raised to the floor rather than back to the default,
93
+ * because an operator who asked for the smallest possible result should
94
+ * get the smallest possible result. The markers name the cap that was
95
+ * actually applied.
96
+ */
97
+ export declare const BRIDGED_RESULT_MIN_LENGTH = 512;
98
+ /**
99
+ * A configured `maxResultChars` as it actually applies: the default when
100
+ * unset, never below the floor. One implementation because it has two
101
+ * consumers — `normalizeCallResult` for a result, and the call path for a
102
+ * `tools/call` that fails before there is a result to normalize. A second
103
+ * copy would leave the floor applying to one and not the other, which is
104
+ * how a cap of 1 came to name itself in a protocol error's marker.
105
+ */
106
+ export declare const boundedResultLimit: (configured: number | undefined) => number;
107
+ /**
108
+ * How deep a schema may nest before the bridge stops walking it. Sixty-four
109
+ * levels is far past any parameter list a person wrote; a schema nested
110
+ * deeper is a stack-overflow attempt dressed as a tool, and a recursive
111
+ * walk that blew the stack during discovery would take the whole server
112
+ * down as unreachable, and again on every reconnect.
113
+ */
114
+ export declare const BRIDGED_SCHEMA_MAX_DEPTH = 64;
115
+ /**
116
+ * The longest name segment a server's tool may bridge under. The segment
117
+ * is the tail of `mcp.<server>.<segment>`, sent as the tool's name in
118
+ * every model request, and a name is the one string a server writes that
119
+ * no description bound touches — a tool called `a` three thousand times
120
+ * over is a page in the tool block by another route. Sixty-four is the
121
+ * longest name the strictest provider accepts whole.
122
+ */
123
+ export declare const BRIDGED_SEGMENT_MAX_LENGTH = 64;
124
+ /**
125
+ * A server's input schema as it reaches the registry — and, through it,
126
+ * the tool block of every turn, the same way the description does. The
127
+ * top-level description is not the only prose in `tools/list`: a
128
+ * `description` or `title` on any property, at any depth, is text the
129
+ * model reads too, and it was copied through unbounded. Each is bounded
130
+ * like the tool's own description. Nothing else in the schema is touched:
131
+ * a property name, an enum value, a const or a pattern is what the model
132
+ * sends back in a call, and the bridge forwards arguments to the server
133
+ * as the model wrote them — a value spelled out here would arrive at the
134
+ * server as a different value, and the schema would be a lie in the
135
+ * direction that breaks calls. An annotation key *inside* a literal (an
136
+ * `enum` member with a `description` field) is data too, and is left
137
+ * alone — while a *parameter* named `enum` or `default` is a schema like
138
+ * any other, because the keys of `properties` and `$defs` are names, not
139
+ * keywords. `undefined` when the bounded schema is still longer than
140
+ * {@link BRIDGED_SCHEMA_MAX_LENGTH} characters, or nests deeper than
141
+ * {@link BRIDGED_SCHEMA_MAX_DEPTH}: that tool is not bridged, and the
142
+ * caller names it.
143
+ */
144
+ export declare const bridgedSchema: (schema: Record<string, unknown>) => Record<string, unknown> | undefined;
23
145
  /** The registered name a server's tool bridges to: `mcp.<server>.<segment>`. */
24
146
  export declare const bridgedToolName: (server: string, segment: string) => string;
147
+ /**
148
+ * Server-written text, bounded for the transcript — the same treatment a
149
+ * result's text gets, exported because a `tools/call` can fail in ways that
150
+ * never produce a result at all: a JSON-RPC error, or a transport failure
151
+ * carrying an HTTP body. Those reach the agent as a thrown message, which
152
+ * `DefaultExecutor` copies into `ToolResult.error` and the session persists
153
+ * and replays exactly like output.
154
+ *
155
+ * Bounded to the cap *minus the envelope it is replayed in*, for the same
156
+ * reason a result's fields are: it does not travel as a bare string but as
157
+ * a JSON string value under a key, and a message cut to exactly the cap
158
+ * arrives a dozen characters over it. The marker still names the cap the
159
+ * operator set rather than the number left after that deduction.
160
+ */
161
+ export declare const THROWN_MESSAGE_ENVELOPE: number;
162
+ export declare const boundServerText: (raw: string, limit: number, what: string) => string;
25
163
  export interface NormalizeOptions {
26
164
  /** The bridged server's config key — part of where a binary block lands. */
27
165
  server: string;
28
166
  /** The server-side tool name — part of the written file's name. */
29
167
  tool: string;
30
168
  /**
31
- * The workspace root the host supplied. Binary content lands under
32
- * `<workspaceRoot>/<agentId>/mcp/<server>/` — per agent, same as
33
- * screenshots, so two agents never read each other's files.
169
+ * Where this agent's workspace is, asked for rather than passed in — not
170
+ * a root to join an id onto. Binary content lands under
171
+ * `<workspace>/mcp/<server>/`, so two agents never read each other's
172
+ * files, the same shape screenshots take.
173
+ *
174
+ * A function because asking is no longer free: the host's seam *creates*
175
+ * the directory and settles its permissions, and it can fail. A
176
+ * text-only result must not be reported as an error because a workspace
177
+ * it never wanted could not be made — the remote call has already
178
+ * happened, and whoever retries it does the side effect twice.
34
179
  */
35
- workspaceRoot?: string;
180
+ workspace?: () => string;
36
181
  agentId: string;
37
182
  /**
38
- * The filesystem provenance ledger for `workspaceRoot`. A binary block
183
+ * The filesystem provenance ledger for `workspace`. A binary block
39
184
  * is a server's bytes written to disk without going through `fs.write`,
40
185
  * so the write records itself here at `external` before the bytes land —
41
186
  * a later `fs.read` of the file then carries the label the tool result
@@ -43,6 +188,12 @@ export interface NormalizeOptions {
43
188
  * the loader-less host case gets.
44
189
  */
45
190
  ledger?: TaintedWriteLedger;
191
+ /**
192
+ * The operator's cap on this result, in characters. Defaults to
193
+ * {@link BRIDGED_RESULT_MAX_LENGTH}; a server cannot raise it, because
194
+ * the cap exists to bound what the server sends.
195
+ */
196
+ maxResultChars?: number;
46
197
  /** Clock seam for deterministic file names in tests. */
47
198
  now?: () => number;
48
199
  }
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEtF;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAI1D,CAAC;AAEF,qGAAqG;AACrG,eAAO,MAAM,mBAAmB,QAA0B,CAAC;AAE3D,gFAAgF;AAChF,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAAoC,CAAC;AAkCvG,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,OAAO,EACf,SAAS,gBAAgB,KACxB,OAAO,CAAC,SAAS,CAqInB,CAAC"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAIA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9F,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEtF;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAI1D,CAAC;AAEF,qGAAqG;AACrG,eAAO,MAAM,mBAAmB,QAA0B,CAAC;AAE3D;;;;;;GAMG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC;AAUnD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,MAWhD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,yBAAyB,SAAU,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,YAAY,MAAM,GAAG,SAAS,KAAG,MACU,CAAC;AAqR/E;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAU3C;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAoD7C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAazF,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAG,MAAoC,CAAC;AA8JvG;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,uBAAuB,QAAwB,CAAC;AAE7D,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,EAAE,OAAO,MAAM,EAAE,MAAM,MAAM,KAAG,MACC,CAAC;AAE7E,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,MAAM,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,OAAO,EACf,SAAS,gBAAgB,KACxB,OAAO,CAAC,SAAS,CA6BnB,CAAC"}