@agent-teams/docs-protocol-mcp 0.0.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/dist/tools.js ADDED
@@ -0,0 +1,601 @@
1
+ import { recordOrIssue, standardJsonSchema, unknownKeys } from "./schema.js";
2
+ import { DOCS_PROTOCOL_MCP_PROJECTION_VERSION } from "./version.js";
3
+ const MAX_RESULT_BYTES = 262_144;
4
+ const DEFAULT_MAX_RESULTS = 25;
5
+ const MAX_RESULTS = 100;
6
+ const DEFAULT_CONTEXT_MAX_BYTES = 32_768;
7
+ const DEFAULT_CONTEXT_MAX_DOCUMENTS = 10;
8
+ const MAX_CONTEXT_BYTES = 131_072;
9
+ const MAX_CONTEXT_DOCUMENTS = 50;
10
+ const MAX_INFO_AUTHORITY_PATHS = 16;
11
+ const MAX_INFO_CATALOG_COLLECTIONS = 16;
12
+ const MAX_INFO_CATALOG_PATHS = 16;
13
+ const MAX_INFO_OWNERS = 32;
14
+ const MAX_INFO_TYPES = 24;
15
+ const MAX_INFO_TYPE_FIELDS = 8;
16
+ const MAX_INFO_VALIDATORS = 32;
17
+ const MAX_FIND_RELATIONS = 8;
18
+ const MAX_FIND_PROJECTION_BYTES = 196_608;
19
+ const OPAQUE_ID_PATTERN = /^[A-Za-z0-9@][A-Za-z0-9@._/-]*$/u;
20
+ const OPAQUE_ID_SCHEMA_PATTERN = "^[A-Za-z0-9@][A-Za-z0-9@._/-]*$";
21
+ const LOWER_ID_PATTERN = /^[a-z0-9][a-z0-9._/-]*$/u;
22
+ const LOWER_ID_SCHEMA_PATTERN = "^[a-z0-9][a-z0-9._/-]*$";
23
+ const TEXT_SCHEMA_PATTERN = "^[^\\u0000-\\u001F\\u007F-\\u009F\\uD800-\\uDFFF]+$";
24
+ const OPAQUE_QUERY_FIELDS = new Set(["blockedBy", "id", "owner", "related"]);
25
+ const LOWER_QUERY_FIELDS = new Set(["status", "type"]);
26
+ const FIND_FIELDS = Object.freeze(["blockedBy", "fuzzy", "id", "maxResults", "owner", "related", "status", "text", "type"]);
27
+ const FIND_FIELD_SET = new Set(FIND_FIELDS);
28
+ const QUERY_FIELDS = Object.freeze(["blockedBy", "id", "owner", "related", "status", "text", "type"]);
29
+ const CONTEXT_FIELDS = Object.freeze(["blockedBy", "fuzzy", "id", "maxBytes", "maxDocuments", "owner", "related", "status", "text", "type"]);
30
+ const CONTEXT_FIELD_SET = new Set(CONTEXT_FIELDS);
31
+ const QUERY_REQUIREMENT_JSON = Object.freeze(QUERY_FIELDS.map((field) => Object.freeze({ required: Object.freeze([field]) })));
32
+ const FUZZY_REQUIRES_TEXT_JSON = Object.freeze({
33
+ if: Object.freeze({
34
+ properties: Object.freeze({ fuzzy: Object.freeze({ const: true }) }),
35
+ required: Object.freeze(["fuzzy"])
36
+ }),
37
+ // oxlint-disable-next-line unicorn/no-thenable -- `then` is the JSON Schema conditional keyword.
38
+ then: Object.freeze({ required: Object.freeze(["text"]) })
39
+ });
40
+ function validatedQueryFields(record, issues) {
41
+ const output = {};
42
+ let queryFields = 0;
43
+ for (const field of QUERY_FIELDS) {
44
+ const candidate = record[field];
45
+ if (candidate === undefined) {
46
+ continue;
47
+ }
48
+ const candidateString = typeof candidate === "string" ? candidate : undefined;
49
+ const valid = field === "text"
50
+ ? candidateString !== undefined && candidateString.length >= 1 && candidateString.length <= 512 && !hasControlCharacter(candidateString)
51
+ : OPAQUE_QUERY_FIELDS.has(field)
52
+ ? candidateString !== undefined && candidateString.length <= 214 && OPAQUE_ID_PATTERN.test(candidateString)
53
+ : LOWER_QUERY_FIELDS.has(field) && candidateString !== undefined && candidateString.length <= 160 && LOWER_ID_PATTERN.test(candidateString);
54
+ if (!valid) {
55
+ issues.push(Object.freeze({ message: "Query field has an invalid value or exceeds its canonical limit.", path: Object.freeze([field]) }));
56
+ continue;
57
+ }
58
+ output[field] = candidateString;
59
+ queryFields += 1;
60
+ }
61
+ return Object.freeze({ output, queryFields });
62
+ }
63
+ function hasControlCharacter(value) {
64
+ for (const character of value) {
65
+ const code = character.codePointAt(0);
66
+ if (code <= 0x1f || (code >= 0x7f && code <= 0x9f) || (code >= 0xd800 && code <= 0xdfff)) {
67
+ return true;
68
+ }
69
+ }
70
+ return false;
71
+ }
72
+ function countedOutputSchema(items, maximum) {
73
+ return Object.freeze({
74
+ type: "object",
75
+ additionalProperties: false,
76
+ required: Object.freeze(["originalCount", "returnedCount", "truncated", "items"]),
77
+ properties: Object.freeze({
78
+ originalCount: Object.freeze({ type: "integer", minimum: 0 }),
79
+ returnedCount: Object.freeze({ type: "integer", minimum: 0, maximum }),
80
+ truncated: Object.freeze({ type: "boolean" }),
81
+ items: Object.freeze({ type: "array", maxItems: maximum, items })
82
+ })
83
+ });
84
+ }
85
+ const STRING_OUTPUT_SCHEMA = Object.freeze({ type: "string" });
86
+ const COUNTED_STRINGS_8_OUTPUT_SCHEMA = countedOutputSchema(STRING_OUTPUT_SCHEMA, 8);
87
+ const COUNTED_STRINGS_16_OUTPUT_SCHEMA = countedOutputSchema(STRING_OUTPUT_SCHEMA, 16);
88
+ const COUNTED_STRINGS_32_OUTPUT_SCHEMA = countedOutputSchema(STRING_OUTPUT_SCHEMA, 32);
89
+ const DIAGNOSTICS_OUTPUT_SCHEMA = Object.freeze({
90
+ type: "object",
91
+ additionalProperties: false,
92
+ required: Object.freeze(["originalCount", "returnedCount", "truncated", "items"]),
93
+ properties: Object.freeze({
94
+ originalCount: Object.freeze({ type: "integer", minimum: 0 }),
95
+ returnedCount: Object.freeze({ type: "integer", minimum: 0, maximum: 8 }),
96
+ truncated: Object.freeze({ type: "boolean" }),
97
+ items: Object.freeze({
98
+ type: "array",
99
+ maxItems: 8,
100
+ items: Object.freeze({
101
+ type: "object",
102
+ additionalProperties: false,
103
+ properties: Object.freeze(Object.fromEntries(["ruleId", "severity", "phase", "subject", "message"]
104
+ .map((field) => [field, Object.freeze({ type: "string" })])))
105
+ })
106
+ })
107
+ })
108
+ });
109
+ function projectionOutputJsonSchema(command, result) {
110
+ return Object.freeze({
111
+ type: "object",
112
+ additionalProperties: false,
113
+ required: Object.freeze(["schemaVersion", "source", "diagnostics", "result"]),
114
+ properties: Object.freeze({
115
+ schemaVersion: Object.freeze({ const: DOCS_PROTOCOL_MCP_PROJECTION_VERSION }),
116
+ source: Object.freeze({
117
+ type: "object",
118
+ additionalProperties: false,
119
+ required: Object.freeze(["protocol", "command", "outcome", "exitCode"]),
120
+ properties: Object.freeze({
121
+ protocol: Object.freeze({
122
+ type: "object",
123
+ additionalProperties: false,
124
+ properties: Object.freeze({ id: Object.freeze({ type: "string" }), version: Object.freeze({ type: "integer" }) })
125
+ }),
126
+ command: Object.freeze({ const: command }),
127
+ outcome: Object.freeze({ type: "string" }),
128
+ exitCode: Object.freeze({ type: "integer" })
129
+ })
130
+ }),
131
+ diagnostics: DIAGNOSTICS_OUTPUT_SCHEMA,
132
+ result
133
+ })
134
+ });
135
+ }
136
+ const INFO_RESULT_OUTPUT_SCHEMA = Object.freeze({
137
+ type: "object",
138
+ additionalProperties: false,
139
+ required: Object.freeze(["kind", "protocol", "foundationProfile", "agentWorkflow", "catalog", "authorityPaths", "ownerIds", "types", "semanticValidatorIds"]),
140
+ properties: Object.freeze({
141
+ kind: Object.freeze({ const: "info" }),
142
+ projectId: Object.freeze({ type: "string" }),
143
+ protocol: Object.freeze({ type: "object", additionalProperties: false, properties: Object.freeze({ id: Object.freeze({ type: "string" }), version: Object.freeze({ type: "integer" }) }) }),
144
+ foundationProfile: Object.freeze({ type: "object", additionalProperties: false, properties: Object.freeze({ schemaVersion: Object.freeze({ type: "integer" }), path: Object.freeze({ type: "string" }), metadataSidecarPolicy: Object.freeze({ type: "string" }) }) }),
145
+ agentWorkflow: Object.freeze({ type: "object", additionalProperties: false, properties: Object.freeze({ skillPath: Object.freeze({ type: "string" }), adoption: Object.freeze({ type: "string" }) }) }),
146
+ catalog: Object.freeze({
147
+ type: "object", additionalProperties: false, required: Object.freeze(["collections", "excludedPrefixes"]), properties: Object.freeze({
148
+ collections: countedOutputSchema(Object.freeze({ type: "object", additionalProperties: false, required: Object.freeze(["roots"]), properties: Object.freeze({ kind: Object.freeze({ type: "string" }), root: Object.freeze({ type: "string" }), roots: COUNTED_STRINGS_16_OUTPUT_SCHEMA }) }), MAX_INFO_CATALOG_COLLECTIONS),
149
+ excludedPrefixes: COUNTED_STRINGS_16_OUTPUT_SCHEMA
150
+ })
151
+ }),
152
+ semanticDigest: Object.freeze({ type: "string" }),
153
+ metadataSchemaPath: Object.freeze({ type: "string" }),
154
+ authorityPaths: COUNTED_STRINGS_16_OUTPUT_SCHEMA,
155
+ ownerIds: COUNTED_STRINGS_32_OUTPUT_SCHEMA,
156
+ types: countedOutputSchema(Object.freeze({ type: "object", additionalProperties: false, required: Object.freeze(["allowedOwnerIds", "requiredMetadata"]), properties: Object.freeze({ type: Object.freeze({ type: "string" }), initialStatus: Object.freeze({ type: "string" }), allowedOwnerIds: COUNTED_STRINGS_8_OUTPUT_SCHEMA, requiredMetadata: COUNTED_STRINGS_8_OUTPUT_SCHEMA }) }), MAX_INFO_TYPES),
157
+ semanticValidatorIds: COUNTED_STRINGS_32_OUTPUT_SCHEMA
158
+ })
159
+ });
160
+ const FIND_RESULT_OUTPUT_SCHEMA = Object.freeze({
161
+ type: "object", additionalProperties: false, required: Object.freeze(["kind", "originalCount", "returnedCount", "truncated", "documents"]), properties: Object.freeze({
162
+ kind: Object.freeze({ const: "find" }), originalCount: Object.freeze({ type: "integer", minimum: 0 }), returnedCount: Object.freeze({ type: "integer", minimum: 0 }), truncated: Object.freeze({ type: "boolean" }),
163
+ documents: Object.freeze({ type: "array", maxItems: MAX_RESULTS, items: Object.freeze({ type: "object", additionalProperties: false, required: Object.freeze(["related", "blockedBy"]), properties: Object.freeze({
164
+ ...Object.fromEntries(["id", "type", "status", "owner", "title", "summary", "repositoryPath", "source"].map((field) => [field, Object.freeze({ type: "string" })])),
165
+ related: COUNTED_STRINGS_8_OUTPUT_SCHEMA, blockedBy: COUNTED_STRINGS_8_OUTPUT_SCHEMA
166
+ }) }) })
167
+ })
168
+ });
169
+ const CONTEXT_RESULT_OUTPUT_SCHEMA = Object.freeze({
170
+ type: "object", additionalProperties: false, required: Object.freeze(["kind", "format", "selection", "limits"]), properties: Object.freeze({
171
+ kind: Object.freeze({ const: "context" }), format: Object.freeze({ const: "llms.txt" }), projectId: Object.freeze({ type: "string" }), catalogSemanticDigest: Object.freeze({ type: "string" }),
172
+ selection: Object.freeze({ type: "object", additionalProperties: false, required: Object.freeze(["ranking", "query"]), properties: Object.freeze({ ranking: Object.freeze({ enum: Object.freeze(["binary-default", "fuzzy-advisory"]) }), query: Object.freeze({ type: "object", additionalProperties: false, properties: Object.freeze(Object.fromEntries(QUERY_FIELDS.map((field) => [field, Object.freeze({ type: "string" })]))) }) }) }),
173
+ limits: Object.freeze({ type: "object", additionalProperties: false, properties: Object.freeze({ maxBytes: Object.freeze({ type: "integer" }), maxDocuments: Object.freeze({ type: "integer" }) }) }),
174
+ includedDocuments: Object.freeze({ type: "integer" }), omittedDocuments: Object.freeze({ type: "integer" }), truncated: Object.freeze({ type: "boolean" }), content: Object.freeze({ type: "string" })
175
+ })
176
+ });
177
+ export const DOCS_INFO_OUTPUT_SCHEMA_V1 = projectionOutputJsonSchema("docs.info", INFO_RESULT_OUTPUT_SCHEMA);
178
+ export const DOCS_FIND_OUTPUT_SCHEMA_V1 = projectionOutputJsonSchema("docs.find", FIND_RESULT_OUTPUT_SCHEMA);
179
+ export const DOCS_CONTEXT_OUTPUT_SCHEMA_V1 = projectionOutputJsonSchema("docs.context", CONTEXT_RESULT_OUTPUT_SCHEMA);
180
+ export const DOCS_ERROR_OUTPUT_SCHEMA_V1 = Object.freeze({
181
+ type: "object", additionalProperties: false, required: Object.freeze(["error"]), properties: Object.freeze({ error: Object.freeze({ type: "object", additionalProperties: false, required: Object.freeze(["code", "message"]), properties: Object.freeze({ code: Object.freeze({ enum: Object.freeze(["CANCELLED", "DOCS_READ_FAILED", "RESULT_TOO_LARGE"]) }), message: Object.freeze({ type: "string" }) }) }) })
182
+ });
183
+ function projectionSchema(jsonSchema, command) {
184
+ return standardJsonSchema(jsonSchema, (value) => {
185
+ const projection = objectRecord(value);
186
+ const source = objectRecord(projection.source);
187
+ return projection.schemaVersion === DOCS_PROTOCOL_MCP_PROJECTION_VERSION && source.command === command && Array.isArray(objectRecord(projection.diagnostics).items) && typeof projection.result === "object" && projection.result !== null
188
+ ? Object.freeze({ value: projection })
189
+ : Object.freeze({ issues: Object.freeze([{ message: "Invalid MCP projection output." }]) });
190
+ });
191
+ }
192
+ const INFO_OUTPUT_SCHEMA = projectionSchema(DOCS_INFO_OUTPUT_SCHEMA_V1, "docs.info");
193
+ const FIND_OUTPUT_SCHEMA = projectionSchema(DOCS_FIND_OUTPUT_SCHEMA_V1, "docs.find");
194
+ const CONTEXT_OUTPUT_SCHEMA = projectionSchema(DOCS_CONTEXT_OUTPUT_SCHEMA_V1, "docs.context");
195
+ const READ_ONLY_ANNOTATIONS = Object.freeze({
196
+ readOnlyHint: true,
197
+ destructiveHint: false,
198
+ idempotentHint: true,
199
+ openWorldHint: false
200
+ });
201
+ const EMPTY_SCHEMA = standardJsonSchema(Object.freeze({ type: "object", additionalProperties: false, maxProperties: 0 }), (value) => {
202
+ const parsed = recordOrIssue(value);
203
+ if ("issues" in parsed) {
204
+ return parsed;
205
+ }
206
+ const issues = unknownKeys(parsed.record, new Set());
207
+ return issues.length === 0
208
+ ? Object.freeze({ value: Object.freeze({}) })
209
+ : Object.freeze({ issues });
210
+ });
211
+ const FIND_SCHEMA_JSON = Object.freeze({
212
+ type: "object",
213
+ additionalProperties: false,
214
+ minProperties: 1,
215
+ anyOf: QUERY_REQUIREMENT_JSON,
216
+ allOf: Object.freeze([FUZZY_REQUIRES_TEXT_JSON]),
217
+ properties: Object.freeze({
218
+ text: Object.freeze({ type: "string", minLength: 1, maxLength: 512, pattern: TEXT_SCHEMA_PATTERN }),
219
+ id: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
220
+ type: Object.freeze({ type: "string", minLength: 1, maxLength: 160, pattern: LOWER_ID_SCHEMA_PATTERN }),
221
+ status: Object.freeze({ type: "string", minLength: 1, maxLength: 160, pattern: LOWER_ID_SCHEMA_PATTERN }),
222
+ owner: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
223
+ related: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
224
+ blockedBy: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
225
+ fuzzy: Object.freeze({ type: "boolean" }),
226
+ maxResults: Object.freeze({ type: "integer", minimum: 1, maximum: MAX_RESULTS })
227
+ })
228
+ });
229
+ const FIND_SCHEMA = standardJsonSchema(FIND_SCHEMA_JSON, (value) => {
230
+ const parsed = recordOrIssue(value);
231
+ if ("issues" in parsed) {
232
+ return parsed;
233
+ }
234
+ const issues = [...unknownKeys(parsed.record, FIND_FIELD_SET)];
235
+ const { output, queryFields } = validatedQueryFields(parsed.record, issues);
236
+ const maxResults = parsed.record.maxResults;
237
+ if (maxResults !== undefined) {
238
+ if (!Number.isInteger(maxResults) || typeof maxResults !== "number" || maxResults < 1 || maxResults > MAX_RESULTS) {
239
+ issues.push(Object.freeze({ message: `Expected an integer from 1 to ${MAX_RESULTS}.`, path: Object.freeze(["maxResults"]) }));
240
+ }
241
+ else {
242
+ output.maxResults = maxResults;
243
+ }
244
+ }
245
+ const fuzzy = parsed.record.fuzzy;
246
+ if (fuzzy !== undefined) {
247
+ if (typeof fuzzy !== "boolean") {
248
+ issues.push(Object.freeze({ message: "Expected a boolean.", path: Object.freeze(["fuzzy"]) }));
249
+ }
250
+ else {
251
+ output.fuzzy = fuzzy;
252
+ }
253
+ }
254
+ if (fuzzy === true && typeof output.text !== "string") {
255
+ issues.push(Object.freeze({ message: "Fuzzy ranking requires text.", path: Object.freeze(["fuzzy"]) }));
256
+ }
257
+ if (queryFields === 0) {
258
+ issues.push(Object.freeze({ message: "At least one documentation query field is required." }));
259
+ }
260
+ return issues.length === 0
261
+ ? Object.freeze({ value: Object.freeze(output) })
262
+ : Object.freeze({ issues: Object.freeze(issues) });
263
+ });
264
+ const CONTEXT_SCHEMA_JSON = Object.freeze({
265
+ type: "object",
266
+ additionalProperties: false,
267
+ allOf: Object.freeze([FUZZY_REQUIRES_TEXT_JSON]),
268
+ properties: Object.freeze({
269
+ text: Object.freeze({ type: "string", minLength: 1, maxLength: 512, pattern: TEXT_SCHEMA_PATTERN }),
270
+ id: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
271
+ type: Object.freeze({ type: "string", minLength: 1, maxLength: 160, pattern: LOWER_ID_SCHEMA_PATTERN }),
272
+ status: Object.freeze({ type: "string", minLength: 1, maxLength: 160, pattern: LOWER_ID_SCHEMA_PATTERN }),
273
+ owner: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
274
+ related: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
275
+ blockedBy: Object.freeze({ type: "string", minLength: 1, maxLength: 214, pattern: OPAQUE_ID_SCHEMA_PATTERN }),
276
+ fuzzy: Object.freeze({ type: "boolean" }),
277
+ maxDocuments: Object.freeze({ type: "integer", minimum: 1, maximum: MAX_CONTEXT_DOCUMENTS }),
278
+ maxBytes: Object.freeze({ type: "integer", minimum: 1_024, maximum: MAX_CONTEXT_BYTES })
279
+ })
280
+ });
281
+ const CONTEXT_SCHEMA = standardJsonSchema(CONTEXT_SCHEMA_JSON, (value) => {
282
+ const parsed = recordOrIssue(value);
283
+ if ("issues" in parsed) {
284
+ return parsed;
285
+ }
286
+ const issues = [...unknownKeys(parsed.record, CONTEXT_FIELD_SET)];
287
+ const { output } = validatedQueryFields(parsed.record, issues);
288
+ for (const [field, minimum, maximum] of [
289
+ ["maxDocuments", 1, MAX_CONTEXT_DOCUMENTS],
290
+ ["maxBytes", 1_024, MAX_CONTEXT_BYTES]
291
+ ]) {
292
+ const candidate = parsed.record[field];
293
+ if (candidate === undefined) {
294
+ continue;
295
+ }
296
+ if (typeof candidate !== "number" || !Number.isInteger(candidate) || candidate < minimum || candidate > maximum) {
297
+ issues.push(Object.freeze({ message: `Expected an integer from ${minimum} to ${maximum}.`, path: Object.freeze([field]) }));
298
+ }
299
+ else {
300
+ output[field] = candidate;
301
+ }
302
+ }
303
+ const fuzzy = parsed.record.fuzzy;
304
+ if (fuzzy !== undefined && typeof fuzzy !== "boolean") {
305
+ issues.push(Object.freeze({ message: "Expected a boolean.", path: Object.freeze(["fuzzy"]) }));
306
+ }
307
+ else if (fuzzy === true && typeof output.text !== "string") {
308
+ issues.push(Object.freeze({ message: "Fuzzy ranking requires text.", path: Object.freeze(["fuzzy"]) }));
309
+ }
310
+ else if (fuzzy !== undefined) {
311
+ output.fuzzy = fuzzy;
312
+ }
313
+ return issues.length === 0
314
+ ? Object.freeze({ value: Object.freeze(output) })
315
+ : Object.freeze({ issues: Object.freeze(issues) });
316
+ });
317
+ function errorResult(code, message) {
318
+ return {
319
+ isError: true,
320
+ content: [{ type: "text", text: JSON.stringify(Object.freeze({ error: Object.freeze({ code, message }) })) }]
321
+ };
322
+ }
323
+ function successResult(value) {
324
+ const text = JSON.stringify(value);
325
+ if (Buffer.byteLength(text, "utf8") > MAX_RESULT_BYTES) {
326
+ return errorResult("RESULT_TOO_LARGE", "The documentation result exceeds the MCP response limit; narrow the query.");
327
+ }
328
+ return {
329
+ content: [{ type: "text", text }],
330
+ structuredContent: value
331
+ };
332
+ }
333
+ function sanitizedFailure(error, signal) {
334
+ if (signal.aborted || (error instanceof Error && error.name === "AbortError")) {
335
+ return errorResult("CANCELLED", "The documentation read was cancelled.");
336
+ }
337
+ return errorResult("DOCS_READ_FAILED", "The documentation read failed.");
338
+ }
339
+ function queryFrom(arguments_) {
340
+ const query = {};
341
+ for (const field of QUERY_FIELDS) {
342
+ const value = arguments_[field];
343
+ if (value !== undefined) {
344
+ query[field] = value;
345
+ }
346
+ }
347
+ return Object.freeze({
348
+ ...query,
349
+ ...(arguments_.fuzzy === true ? { ranking: "fuzzy-advisory" } : {})
350
+ });
351
+ }
352
+ function projectExecution(execution, result) {
353
+ const protocol = objectRecord(execution.envelope.protocol);
354
+ return Object.freeze({
355
+ schemaVersion: DOCS_PROTOCOL_MCP_PROJECTION_VERSION,
356
+ source: Object.freeze({
357
+ protocol: Object.freeze({
358
+ ...(stringValue(protocol.id) === undefined ? {} : { id: protocol.id }),
359
+ ...(typeof protocol.version !== "number" ? {} : { version: protocol.version })
360
+ }),
361
+ command: execution.envelope.command,
362
+ outcome: execution.envelope.outcome,
363
+ exitCode: execution.exitCode
364
+ }),
365
+ diagnostics: projectDiagnostics(execution.envelope.diagnostics),
366
+ result
367
+ });
368
+ }
369
+ function objectRecord(value) {
370
+ return typeof value === "object" && value !== null && !Array.isArray(value)
371
+ ? value
372
+ : Object.freeze({});
373
+ }
374
+ function stringValue(value) {
375
+ return typeof value === "string" ? value : undefined;
376
+ }
377
+ function stringList(value) {
378
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : Object.freeze([]);
379
+ }
380
+ function boundedStrings(value, maximum) {
381
+ const original = stringList(value);
382
+ const items = Object.freeze(original.slice(0, maximum));
383
+ return Object.freeze({
384
+ originalCount: original.length,
385
+ returnedCount: items.length,
386
+ truncated: items.length < original.length,
387
+ items
388
+ });
389
+ }
390
+ function projectDiagnostics(value) {
391
+ const items = Object.freeze(value.slice(0, 8).map((entry) => {
392
+ const record = objectRecord(entry);
393
+ return Object.freeze({
394
+ ...(stringValue(record.ruleId) === undefined ? {} : { ruleId: record.ruleId }),
395
+ ...(stringValue(record.severity) === undefined ? {} : { severity: record.severity }),
396
+ ...(stringValue(record.phase) === undefined ? {} : { phase: record.phase }),
397
+ ...(stringValue(record.subject) === undefined ? {} : { subject: record.subject }),
398
+ ...(stringValue(record.message) === undefined ? {} : { message: record.message })
399
+ });
400
+ }));
401
+ return Object.freeze({
402
+ originalCount: value.length,
403
+ returnedCount: items.length,
404
+ truncated: items.length < value.length,
405
+ items
406
+ });
407
+ }
408
+ function projectCatalog(value) {
409
+ const catalog = objectRecord(value);
410
+ const originalCollections = Array.isArray(catalog.collections) ? catalog.collections : [];
411
+ const collections = Object.freeze(originalCollections.slice(0, MAX_INFO_CATALOG_COLLECTIONS).map((entry) => {
412
+ const collection = objectRecord(entry);
413
+ return Object.freeze({
414
+ ...(stringValue(collection.kind) === undefined ? {} : { kind: collection.kind }),
415
+ ...(stringValue(collection.root) === undefined ? {} : { root: collection.root }),
416
+ roots: boundedStrings(collection.roots, MAX_INFO_CATALOG_PATHS)
417
+ });
418
+ }));
419
+ return Object.freeze({
420
+ collections: Object.freeze({
421
+ originalCount: originalCollections.length,
422
+ returnedCount: collections.length,
423
+ truncated: collections.length < originalCollections.length,
424
+ items: collections
425
+ }),
426
+ excludedPrefixes: boundedStrings(catalog.excludedPrefixes, MAX_INFO_CATALOG_PATHS)
427
+ });
428
+ }
429
+ function projectInfo(execution) {
430
+ const result = objectRecord(execution.envelope.result);
431
+ const profile = objectRecord(result.foundationProfile);
432
+ const workflow = objectRecord(result.agentWorkflow);
433
+ const protocol = objectRecord(result.protocol);
434
+ const originalTypes = Array.isArray(result.types) ? result.types : [];
435
+ const types = Object.freeze(originalTypes.slice(0, MAX_INFO_TYPES).map((value) => {
436
+ const type = objectRecord(value);
437
+ return Object.freeze({
438
+ ...(stringValue(type.type) === undefined ? {} : { type: type.type }),
439
+ ...(stringValue(type.initialStatus) === undefined ? {} : { initialStatus: type.initialStatus }),
440
+ allowedOwnerIds: boundedStrings(type.allowedOwnerIds, MAX_INFO_TYPE_FIELDS),
441
+ requiredMetadata: boundedStrings(type.requiredMetadata, MAX_INFO_TYPE_FIELDS)
442
+ });
443
+ }));
444
+ return projectExecution(execution, Object.freeze({
445
+ kind: "info",
446
+ ...(stringValue(result.projectId) === undefined ? {} : { projectId: result.projectId }),
447
+ protocol: Object.freeze({
448
+ ...(stringValue(protocol.id) === undefined ? {} : { id: protocol.id }),
449
+ ...(typeof protocol.version !== "number" ? {} : { version: protocol.version })
450
+ }),
451
+ foundationProfile: Object.freeze({
452
+ ...(typeof profile.schemaVersion !== "number" ? {} : { schemaVersion: profile.schemaVersion }),
453
+ ...(stringValue(profile.path) === undefined ? {} : { path: profile.path }),
454
+ ...(stringValue(profile.metadataSidecarPolicy) === undefined ? {} : { metadataSidecarPolicy: profile.metadataSidecarPolicy })
455
+ }),
456
+ agentWorkflow: Object.freeze({
457
+ ...(stringValue(workflow.skillPath) === undefined ? {} : { skillPath: workflow.skillPath }),
458
+ ...(stringValue(workflow.adoption) === undefined ? {} : { adoption: workflow.adoption })
459
+ }),
460
+ catalog: projectCatalog(result.catalog),
461
+ ...(stringValue(result.semanticDigest) === undefined ? {} : { semanticDigest: result.semanticDigest }),
462
+ ...(stringValue(result.metadataSchemaPath) === undefined ? {} : { metadataSchemaPath: result.metadataSchemaPath }),
463
+ authorityPaths: boundedStrings(result.authorityPaths, MAX_INFO_AUTHORITY_PATHS),
464
+ ownerIds: boundedStrings(result.ownerIds, MAX_INFO_OWNERS),
465
+ types: Object.freeze({
466
+ originalCount: originalTypes.length,
467
+ returnedCount: types.length,
468
+ truncated: types.length < originalTypes.length,
469
+ items: types
470
+ }),
471
+ semanticValidatorIds: boundedStrings(result.semanticValidatorIds, MAX_INFO_VALIDATORS)
472
+ }));
473
+ }
474
+ function projectFindDocument(value) {
475
+ const document = objectRecord(value);
476
+ return Object.freeze({
477
+ ...Object.fromEntries(["id", "type", "status", "owner", "title", "summary", "repositoryPath", "source"]
478
+ .flatMap((field) => stringValue(document[field]) === undefined ? [] : [[field, document[field]]])),
479
+ related: boundedStrings(document.related, MAX_FIND_RELATIONS),
480
+ blockedBy: boundedStrings(document.blockedBy, MAX_FIND_RELATIONS)
481
+ });
482
+ }
483
+ function projectContext(execution) {
484
+ const result = objectRecord(execution.envelope.result);
485
+ const limits = objectRecord(result.limits);
486
+ const selection = objectRecord(result.selection);
487
+ const selectionQuery = objectRecord(selection.query);
488
+ return projectExecution(execution, Object.freeze({
489
+ kind: "context",
490
+ format: "llms.txt",
491
+ ...(stringValue(result.projectId) === undefined ? {} : { projectId: result.projectId }),
492
+ ...(stringValue(result.catalogSemanticDigest) === undefined ? {} : { catalogSemanticDigest: result.catalogSemanticDigest }),
493
+ selection: Object.freeze({
494
+ ranking: selection.ranking === "fuzzy-advisory" ? "fuzzy-advisory" : "binary-default",
495
+ query: Object.freeze(Object.fromEntries(QUERY_FIELDS.flatMap((field) => stringValue(selectionQuery[field]) === undefined ? [] : [[field, selectionQuery[field]]])))
496
+ }),
497
+ limits: Object.freeze({
498
+ ...(typeof limits.maxBytes !== "number" ? {} : { maxBytes: limits.maxBytes }),
499
+ ...(typeof limits.maxDocuments !== "number" ? {} : { maxDocuments: limits.maxDocuments })
500
+ }),
501
+ ...(typeof result.includedDocuments !== "number" ? {} : { includedDocuments: result.includedDocuments }),
502
+ ...(typeof result.omittedDocuments !== "number" ? {} : { omittedDocuments: result.omittedDocuments }),
503
+ ...(typeof result.truncated !== "boolean" ? {} : { truncated: result.truncated }),
504
+ ...(stringValue(result.content) === undefined ? {} : { content: result.content })
505
+ }));
506
+ }
507
+ function boundedFindProjection(execution, maxResults) {
508
+ const result = execution.envelope.result;
509
+ if (typeof result !== "object" || result === null || !("documents" in result) || !Array.isArray(result.documents)) {
510
+ return projectExecution(execution, result);
511
+ }
512
+ const originalCount = result.documents.length;
513
+ const documents = [];
514
+ for (const value of result.documents.slice(0, maxResults)) {
515
+ const document = projectFindDocument(value);
516
+ const candidate = projectExecution(execution, Object.freeze({
517
+ kind: "find",
518
+ originalCount,
519
+ returnedCount: documents.length + 1,
520
+ truncated: documents.length + 1 < originalCount,
521
+ documents: Object.freeze([...documents, document])
522
+ }));
523
+ if (Buffer.byteLength(JSON.stringify(candidate), "utf8") > MAX_FIND_PROJECTION_BYTES) {
524
+ break;
525
+ }
526
+ documents.push(document);
527
+ }
528
+ return projectExecution(execution, Object.freeze({
529
+ kind: "find",
530
+ originalCount,
531
+ returnedCount: documents.length,
532
+ truncated: documents.length < originalCount,
533
+ documents: Object.freeze(documents)
534
+ }));
535
+ }
536
+ export function createDocsTools(reader, binding) {
537
+ const fixedBinding = Object.freeze({ ...binding });
538
+ const tools = Object.freeze([
539
+ Object.freeze({
540
+ name: "docs_info",
541
+ description: "Read the fixed consumer's documentation protocol, authority, catalog, owners, and document types.",
542
+ inputSchema: EMPTY_SCHEMA,
543
+ outputSchema: INFO_OUTPUT_SCHEMA,
544
+ annotations: READ_ONLY_ANNOTATIONS,
545
+ async run(_arguments, signal) {
546
+ try {
547
+ signal.throwIfAborted();
548
+ const execution = await reader.info({ ...fixedBinding, signal });
549
+ return successResult(projectInfo(execution));
550
+ }
551
+ catch (error) {
552
+ return sanitizedFailure(error, signal);
553
+ }
554
+ }
555
+ }),
556
+ Object.freeze({
557
+ name: "docs_find",
558
+ description: "Search the fixed consumer's documentation catalog with bounded, read-only filters.",
559
+ inputSchema: FIND_SCHEMA,
560
+ outputSchema: FIND_OUTPUT_SCHEMA,
561
+ annotations: READ_ONLY_ANNOTATIONS,
562
+ async run(arguments_, signal) {
563
+ try {
564
+ signal.throwIfAborted();
565
+ const execution = await reader.find({ ...fixedBinding, query: queryFrom(arguments_), signal });
566
+ return successResult(boundedFindProjection(execution, arguments_.maxResults ?? DEFAULT_MAX_RESULTS));
567
+ }
568
+ catch (error) {
569
+ return sanitizedFailure(error, signal);
570
+ }
571
+ }
572
+ }),
573
+ Object.freeze({
574
+ name: "docs_context",
575
+ description: "Build bounded llms.txt context from the fixed consumer's documentation with optional filters and advisory fuzzy ranking.",
576
+ inputSchema: CONTEXT_SCHEMA,
577
+ outputSchema: CONTEXT_OUTPUT_SCHEMA,
578
+ annotations: READ_ONLY_ANNOTATIONS,
579
+ async run(arguments_, signal) {
580
+ try {
581
+ signal.throwIfAborted();
582
+ const execution = await reader.context({
583
+ ...fixedBinding,
584
+ query: queryFrom(arguments_),
585
+ limits: Object.freeze({
586
+ maxBytes: arguments_.maxBytes ?? DEFAULT_CONTEXT_MAX_BYTES,
587
+ maxDocuments: arguments_.maxDocuments ?? DEFAULT_CONTEXT_MAX_DOCUMENTS
588
+ }),
589
+ signal
590
+ });
591
+ return successResult(projectContext(execution));
592
+ }
593
+ catch (error) {
594
+ return sanitizedFailure(error, signal);
595
+ }
596
+ }
597
+ })
598
+ ]);
599
+ return tools;
600
+ }
601
+ //# sourceMappingURL=tools.js.map