@farming-labs/docs 0.2.77 → 0.2.79
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/{agent-DRKj42ht.d.mts → agent-C3Y011P9.d.mts} +282 -15
- package/dist/{agent-D4hNGatV.mjs → agent-DYPnd8-9.mjs} +2 -2
- package/dist/{agent-SRIJ-oF8.mjs → agent-DejGcJfb.mjs} +4286 -334
- package/dist/{agent-evals-DmFoKy_y.mjs → agent-evals-DQbsw5fY.mjs} +1 -1
- package/dist/{agent-export-CM-p9_YD.mjs → agent-export-DyDl_mmh.mjs} +6 -5
- package/dist/agent-provenance-DEyAr22i.mjs +463 -0
- package/dist/agent-skills-bundle.d.mts +1 -1
- package/dist/{agent-skills-server-CJ4D0G9P.d.mts → agent-skills-server-Daq-FOay.d.mts} +2 -2
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/{agents-BeLDNCnE.mjs → agents-ktSbqsOA.mjs} +4 -4
- package/dist/cli/index.mjs +14 -14
- package/dist/client/react.d.mts +1 -1
- package/dist/{cloud-ask-ai-BCgHPxew.d.mts → cloud-ask-ai-o41WfOTk.d.mts} +1 -1
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/{doctor-DhMVKHjp.mjs → doctor-DPj4Af0T.mjs} +9 -9
- package/dist/{golden-evaluations-VzE6juQl.mjs → golden-evaluations-xjthrnDO.mjs} +7 -2
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +5 -5
- package/dist/{mcp-CZkQJXtA.mjs → mcp-DOisfwWF.mjs} +5 -4
- package/dist/mcp.d.mts +19 -6
- package/dist/mcp.mjs +482 -40
- package/dist/{prompt-references-B6L3AD98.mjs → prompt-references-DbmH5FA9.mjs} +2 -2
- package/dist/retrieval-digest-DIbiu0TW.d.mts +190 -0
- package/dist/{review-nxoV8jIm.mjs → review-X1qVmw9I.mjs} +4 -4
- package/dist/{robots-CiQT8mX2.mjs → robots-DTo_uqa9.mjs} +2 -2
- package/dist/{robots-CgH6Stqn.mjs → robots-DUdUIBpi.mjs} +1 -1
- package/dist/{search-BTUIkhnT.mjs → search-DMOwAmxo.mjs} +4 -4
- package/dist/server.d.mts +7 -7
- package/dist/server.mjs +6 -6
- package/dist/{sitemap-e0_GeCWJ.mjs → sitemap-5Lajt0xS.mjs} +4 -4
- package/dist/{sitemap-server-DHaxyPAd.mjs → sitemap-server-p4wkFm9-.mjs} +1 -1
- package/dist/{standards-discovery-BbslY4id.d.mts → standards-discovery-C2cUIQzW.d.mts} +1 -1
- package/dist/{types-B-5Kzmkn.d.mts → types-o-ULHPK6.d.mts} +127 -4
- package/package.json +6 -2
- package/dist/retrieval-digest-rponR4jM.d.mts +0 -332
- package/dist/search-Da2AKaFJ.mjs +0 -3992
package/dist/mcp.mjs
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { a as emitDocsAnalyticsEvent, i as emitDocsAgentTraceEvent, n as createDocsAgentTraceContext, r as createDocsAgentTraceId } from "./analytics-Bx44lg6d.mjs";
|
|
2
|
-
import { E as DOCS_MARKDOWN_SECTION_INDEX_FORMAT, Kt as normalizeDocsRelated, P as buildDocsMarkdownSectionIndex,
|
|
2
|
+
import { $n as resolveDocsMcpProtectedResourceMetadataLocation, An as normalizeAgentLocale, Dn as agentVersionConstraintMatches, E as DOCS_MARKDOWN_SECTION_INDEX_FORMAT, In as isDocsRetrievalCanonicalUrl, Jn as isDocsMcpProtectedResourceMetadataPath, Jt as resolveDocsContentChangesConfig, Kt as isDocsContentChangeGeneration, Ln as normalizeDocsRelated, Nn as DocsPaginationCursorError, On as agentVersionConstraintsOverlap, P as buildDocsMarkdownSectionIndex, Pn as paginateDocsItems, Qn as normalizeDocsMcpEndpointPath, Rn as renderDocsRelatedMarkdownLines, Tn as resolveDocsAudienceMdxContent, Ut as DocsContentChangesRequestError, Wt as createDocsContentChangeFeed, Xn as isDocsMcpResourcePath, Zn as normalizeDocsMcpAuthorizationServerUrls, dn as performDocsSearch, er as resolveDocsMcpResourceLocation, fn as performDocsSearchWithMetadata, jn as normalizeAgentScopeValues, kn as normalizeAgentFramework, qn as isDocsMcpOAuthScopeToken, tn as buildDocsSearchFacets, un as normalizeDocsSearchFilters, wt as toDocsMarkdownUrl } from "./agent-DejGcJfb.mjs";
|
|
3
3
|
import { S as upsertPageAgentContractMarkdown, _ as hasStructuredPageAgentContract, o as findDocsMarkdownSection, s as parseDocsMarkdownSections, v as normalizePageAgentFrontmatter } from "./markdown-sections-7OoA7ylx.mjs";
|
|
4
4
|
import "./standards-discovery-BKlEnK_H.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { f as emitDocsTelemetryAgentSurfaceEvent, h as emitDocsTelemetryProjectEvent, l as resolvePageSidebarFolderIndexBehavior, m as emitDocsTelemetryMcpToolEvent, s as stripGeneratedAgentProvenance } from "./agent-provenance-DEyAr22i.mjs";
|
|
6
6
|
import matter from "gray-matter";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
12
|
-
import { ErrorCode, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
10
|
+
import { InMemoryServerEventBus, McpServer, ProtocolError, ProtocolErrorCode, ResourceTemplate, createMcpHandler, isInitializeRequest } from "@modelcontextprotocol/server";
|
|
13
11
|
import * as z from "zod/v4";
|
|
14
12
|
|
|
15
13
|
//#region src/mcp.ts
|
|
@@ -21,6 +19,9 @@ const MAX_MCP_CONTEXT_TOKEN_BUDGET = 32e3;
|
|
|
21
19
|
const DOCS_MCP_PROTOCOL_LIST_PAGE_SIZE = 10;
|
|
22
20
|
const DOCS_MCP_TOOL_LIST_PAGE_SIZE = 25;
|
|
23
21
|
const DOCS_MCP_PAGINATION_META_KEY = "dev.farming-labs/pagination";
|
|
22
|
+
const DOCS_MCP_CONTENT_CHANGES_CURRENT_URI = "docs://changes/current";
|
|
23
|
+
const DOCS_MCP_CONTENT_CHANGES_URI_TEMPLATE = "docs://changes/{generation}";
|
|
24
|
+
const DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS = 3e4;
|
|
24
25
|
const UTF8_ENCODER = new TextEncoder();
|
|
25
26
|
const DEFAULT_DOCS_MCP_MAX_BODY_BYTES = 1024 * 1024;
|
|
26
27
|
const DEFAULT_DOCS_MCP_CORS_MAX_AGE_SECONDS = 600;
|
|
@@ -29,6 +30,8 @@ const DEFAULT_DOCS_MCP_CORS_ALLOWED_HEADERS = Object.freeze([
|
|
|
29
30
|
"Authorization",
|
|
30
31
|
"Content-Type",
|
|
31
32
|
"Last-Event-ID",
|
|
33
|
+
"MCP-Method",
|
|
34
|
+
"MCP-Name",
|
|
32
35
|
"MCP-Protocol-Version",
|
|
33
36
|
"MCP-Session-Id"
|
|
34
37
|
]);
|
|
@@ -223,9 +226,44 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
223
226
|
path: "agent",
|
|
224
227
|
name: "agent",
|
|
225
228
|
type: "DocsAgentConfig",
|
|
226
|
-
description: "Agent compaction defaults and offline-by-default usefulness evaluations.",
|
|
229
|
+
description: "Agent synchronization, reusable skills, compaction defaults, and offline-by-default usefulness evaluations.",
|
|
227
230
|
docs: "/docs/getting-started/agent-ready-docs",
|
|
228
231
|
children: [
|
|
232
|
+
{
|
|
233
|
+
path: "agent.contentChanges",
|
|
234
|
+
name: "contentChanges",
|
|
235
|
+
type: "boolean | DocsAgentContentChangesConfig",
|
|
236
|
+
default: true,
|
|
237
|
+
description: "Body-free runtime document synchronization feed. Disable it with false, or configure bounded and durable snapshot history.",
|
|
238
|
+
children: [
|
|
239
|
+
{
|
|
240
|
+
path: "agent.contentChanges.enabled",
|
|
241
|
+
name: "enabled",
|
|
242
|
+
type: "boolean",
|
|
243
|
+
default: true,
|
|
244
|
+
description: "Whether runtime adapters serve response=changes."
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
path: "agent.contentChanges.maxSnapshots",
|
|
248
|
+
name: "maxSnapshots",
|
|
249
|
+
type: "number",
|
|
250
|
+
default: 8,
|
|
251
|
+
description: "Metadata-only snapshots retained in this server process; accepted range is 1 through 64."
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
path: "agent.contentChanges.loadSnapshot",
|
|
255
|
+
name: "loadSnapshot",
|
|
256
|
+
type: "DocsContentChangeSnapshotLoader",
|
|
257
|
+
description: "Optional callback that loads a prior generation from durable storage for exact cross-deployment deltas."
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
path: "agent.contentChanges.saveSnapshot",
|
|
261
|
+
name: "saveSnapshot",
|
|
262
|
+
type: "DocsContentChangeSnapshotSaver",
|
|
263
|
+
description: "Optional callback that persists each current metadata snapshot to durable storage."
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
},
|
|
229
267
|
{
|
|
230
268
|
path: "agent.skills",
|
|
231
269
|
name: "skills",
|
|
@@ -1526,6 +1564,20 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
1526
1564
|
default: true,
|
|
1527
1565
|
description: "Expose the search_docs tool."
|
|
1528
1566
|
},
|
|
1567
|
+
{
|
|
1568
|
+
path: "mcp.tools.searchFacets",
|
|
1569
|
+
name: "searchFacets",
|
|
1570
|
+
type: "boolean",
|
|
1571
|
+
default: true,
|
|
1572
|
+
description: "Expose the list_search_facets tool for body-free framework, version, package, and tag discovery."
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
path: "mcp.tools.listContentChanges",
|
|
1576
|
+
name: "listContentChanges",
|
|
1577
|
+
type: "boolean",
|
|
1578
|
+
default: true,
|
|
1579
|
+
description: "Expose list_content_changes polling and docs://changes resources when agent.contentChanges is enabled."
|
|
1580
|
+
},
|
|
1529
1581
|
{
|
|
1530
1582
|
path: "mcp.tools.readPage",
|
|
1531
1583
|
name: "readPage",
|
|
@@ -1728,6 +1780,22 @@ const searchDocsInputSchema = z.object({
|
|
|
1728
1780
|
package: searchFilterValueSchema.optional(),
|
|
1729
1781
|
tags: searchFilterValueSchema.optional()
|
|
1730
1782
|
});
|
|
1783
|
+
const searchFacetsInputSchema = z.object({
|
|
1784
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1785
|
+
audience: z.enum(["human", "agent"]).optional(),
|
|
1786
|
+
facet: z.enum([
|
|
1787
|
+
"framework",
|
|
1788
|
+
"version",
|
|
1789
|
+
"package",
|
|
1790
|
+
"tags"
|
|
1791
|
+
]).optional(),
|
|
1792
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
1793
|
+
cursor: paginationCursorInputSchema,
|
|
1794
|
+
framework: searchFilterValueSchema.optional(),
|
|
1795
|
+
version: searchFilterValueSchema.optional(),
|
|
1796
|
+
package: searchFilterValueSchema.optional(),
|
|
1797
|
+
tags: searchFilterValueSchema.optional()
|
|
1798
|
+
});
|
|
1731
1799
|
const readPageInputSchema = z.object({
|
|
1732
1800
|
path: z.string().min(1),
|
|
1733
1801
|
locale: z.string().trim().min(1).max(128).optional(),
|
|
@@ -1822,6 +1890,10 @@ const listDocsInputSchema = z.object({
|
|
|
1822
1890
|
cursor: paginationCursorInputSchema
|
|
1823
1891
|
});
|
|
1824
1892
|
const getNavigationInputSchema = z.object({ locale: z.string().trim().min(1).max(128).optional() });
|
|
1893
|
+
const listContentChangesInputSchema = z.object({
|
|
1894
|
+
since: z.string().refine(isDocsContentChangeGeneration, "Expected a SHA-256 index generation").optional(),
|
|
1895
|
+
locale: z.string().trim().min(1).max(128).optional()
|
|
1896
|
+
});
|
|
1825
1897
|
const getConfigSchemaInputSchema = z.object({
|
|
1826
1898
|
option: z.string().trim().min(1).optional(),
|
|
1827
1899
|
query: z.string().trim().min(1).optional()
|
|
@@ -1929,6 +2001,37 @@ const retrievalSourceScopeOutputSchema = z.object({
|
|
|
1929
2001
|
])).max(4).optional()
|
|
1930
2002
|
});
|
|
1931
2003
|
const retrievalSourceDigestOutputSchema = z.string().regex(/^sha256:[a-f\d]{64}$/iu);
|
|
2004
|
+
const contentChangeDocumentOutputSchema = z.object({
|
|
2005
|
+
url: z.string(),
|
|
2006
|
+
canonicalUrl: z.string().max(4096).refine(isDocsRetrievalCanonicalUrl, "Expected a safe HTTP(S) URL or root-relative path"),
|
|
2007
|
+
digest: retrievalSourceDigestOutputSchema,
|
|
2008
|
+
lastModified: z.string().optional()
|
|
2009
|
+
});
|
|
2010
|
+
const contentChangesOutputSchema = z.object({
|
|
2011
|
+
format: z.literal("docs-content-changes.v1"),
|
|
2012
|
+
audience: z.enum(["human", "agent"]),
|
|
2013
|
+
locale: z.string().optional(),
|
|
2014
|
+
since: retrievalSourceDigestOutputSchema.nullable(),
|
|
2015
|
+
indexGeneration: retrievalSourceDigestOutputSchema,
|
|
2016
|
+
mode: z.enum([
|
|
2017
|
+
"snapshot",
|
|
2018
|
+
"delta",
|
|
2019
|
+
"reset"
|
|
2020
|
+
]),
|
|
2021
|
+
resetRequired: z.boolean(),
|
|
2022
|
+
documentCount: z.number().int().nonnegative(),
|
|
2023
|
+
counts: z.object({
|
|
2024
|
+
added: z.number().int().nonnegative(),
|
|
2025
|
+
changed: z.number().int().nonnegative(),
|
|
2026
|
+
deleted: z.number().int().nonnegative()
|
|
2027
|
+
}),
|
|
2028
|
+
added: z.array(contentChangeDocumentOutputSchema),
|
|
2029
|
+
changed: z.array(contentChangeDocumentOutputSchema.extend({
|
|
2030
|
+
previousDigest: retrievalSourceDigestOutputSchema,
|
|
2031
|
+
previousLastModified: z.string().optional()
|
|
2032
|
+
})),
|
|
2033
|
+
deleted: z.array(contentChangeDocumentOutputSchema)
|
|
2034
|
+
});
|
|
1932
2035
|
const retrievalSourceOutputSchema = z.object({
|
|
1933
2036
|
canonicalUrl: z.string().max(4096).refine(isDocsRetrievalCanonicalUrl, "Expected a safe HTTP(S) URL or root-relative path"),
|
|
1934
2037
|
scope: retrievalSourceScopeOutputSchema,
|
|
@@ -1984,6 +2087,30 @@ const searchDocsOutputSchema = z.object({
|
|
|
1984
2087
|
results: z.array(searchResultOutputSchema),
|
|
1985
2088
|
warnings: z.array(searchWarningOutputSchema)
|
|
1986
2089
|
});
|
|
2090
|
+
const searchFacetOutputSchema = z.object({
|
|
2091
|
+
valueCount: z.number().int().nonnegative(),
|
|
2092
|
+
total: z.number().int().nonnegative(),
|
|
2093
|
+
hasMore: z.boolean(),
|
|
2094
|
+
nextCursor: z.string().optional(),
|
|
2095
|
+
truncated: z.boolean(),
|
|
2096
|
+
values: z.array(z.object({
|
|
2097
|
+
value: z.string(),
|
|
2098
|
+
count: z.number().int().nonnegative()
|
|
2099
|
+
}))
|
|
2100
|
+
});
|
|
2101
|
+
const searchFacetsOutputSchema = z.object({
|
|
2102
|
+
format: z.literal("docs-search-facets.v1"),
|
|
2103
|
+
audience: z.enum(["human", "agent"]),
|
|
2104
|
+
filters: searchFiltersOutputSchema,
|
|
2105
|
+
indexGeneration: retrievalSourceDigestOutputSchema,
|
|
2106
|
+
matchedPageCount: z.number().int().nonnegative(),
|
|
2107
|
+
facets: z.object({
|
|
2108
|
+
framework: searchFacetOutputSchema,
|
|
2109
|
+
version: searchFacetOutputSchema,
|
|
2110
|
+
package: searchFacetOutputSchema,
|
|
2111
|
+
tags: searchFacetOutputSchema
|
|
2112
|
+
})
|
|
2113
|
+
});
|
|
1987
2114
|
const codeExampleOutputSchema = z.object({
|
|
1988
2115
|
id: z.string(),
|
|
1989
2116
|
page: z.object({
|
|
@@ -2145,6 +2272,8 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2145
2272
|
listTasks: true,
|
|
2146
2273
|
readTask: true,
|
|
2147
2274
|
searchDocs: true,
|
|
2275
|
+
searchFacets: true,
|
|
2276
|
+
listContentChanges: true,
|
|
2148
2277
|
getNavigation: true,
|
|
2149
2278
|
getCodeExamples: true,
|
|
2150
2279
|
getConfigSchema: true,
|
|
@@ -2166,6 +2295,8 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2166
2295
|
listTasks: config.tools?.listTasks ?? true,
|
|
2167
2296
|
readTask: config.tools?.readTask ?? true,
|
|
2168
2297
|
searchDocs: config.tools?.searchDocs ?? true,
|
|
2298
|
+
searchFacets: config.tools?.searchFacets ?? true,
|
|
2299
|
+
listContentChanges: config.tools?.listContentChanges ?? true,
|
|
2169
2300
|
getNavigation: config.tools?.getNavigation ?? true,
|
|
2170
2301
|
getCodeExamples: config.tools?.getCodeExamples ?? true,
|
|
2171
2302
|
getConfigSchema: config.tools?.getConfigSchema ?? true,
|
|
@@ -2284,6 +2415,54 @@ function nowMs() {
|
|
|
2284
2415
|
function durationMs(startedAt) {
|
|
2285
2416
|
return Math.max(0, Date.now() - startedAt);
|
|
2286
2417
|
}
|
|
2418
|
+
function createDocsMcpContentChangeMonitor(options) {
|
|
2419
|
+
let context;
|
|
2420
|
+
let generation;
|
|
2421
|
+
let timer;
|
|
2422
|
+
let running = false;
|
|
2423
|
+
let closed = false;
|
|
2424
|
+
const schedule = () => {
|
|
2425
|
+
if (closed || timer || running || options.isActive?.() === false) return;
|
|
2426
|
+
timer = setTimeout(async () => {
|
|
2427
|
+
timer = void 0;
|
|
2428
|
+
if (closed || context === void 0 || options.isActive?.() === false) return;
|
|
2429
|
+
running = true;
|
|
2430
|
+
try {
|
|
2431
|
+
const nextGeneration = await options.readGeneration(context);
|
|
2432
|
+
if (generation && nextGeneration !== generation) {
|
|
2433
|
+
generation = nextGeneration;
|
|
2434
|
+
await options.notify();
|
|
2435
|
+
} else generation = nextGeneration;
|
|
2436
|
+
} catch {} finally {
|
|
2437
|
+
running = false;
|
|
2438
|
+
schedule();
|
|
2439
|
+
}
|
|
2440
|
+
}, options.pollIntervalMs);
|
|
2441
|
+
if (options.unrefTimer) timer.unref?.();
|
|
2442
|
+
};
|
|
2443
|
+
return {
|
|
2444
|
+
async start(nextContext) {
|
|
2445
|
+
if (closed) return;
|
|
2446
|
+
context = nextContext;
|
|
2447
|
+
if (timer) {
|
|
2448
|
+
clearTimeout(timer);
|
|
2449
|
+
timer = void 0;
|
|
2450
|
+
}
|
|
2451
|
+
try {
|
|
2452
|
+
generation = await options.readGeneration(nextContext);
|
|
2453
|
+
} catch {
|
|
2454
|
+
generation = void 0;
|
|
2455
|
+
}
|
|
2456
|
+
schedule();
|
|
2457
|
+
},
|
|
2458
|
+
close() {
|
|
2459
|
+
closed = true;
|
|
2460
|
+
context = void 0;
|
|
2461
|
+
if (timer) clearTimeout(timer);
|
|
2462
|
+
timer = void 0;
|
|
2463
|
+
}
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2287
2466
|
function createStructuredTextResult(structuredContent, text) {
|
|
2288
2467
|
return {
|
|
2289
2468
|
content: [{
|
|
@@ -2315,7 +2494,7 @@ function paginateDocsMcpProtocolItems(items, options) {
|
|
|
2315
2494
|
pageSize: DOCS_MCP_PROTOCOL_LIST_PAGE_SIZE
|
|
2316
2495
|
});
|
|
2317
2496
|
} catch (error) {
|
|
2318
|
-
if (error instanceof DocsPaginationCursorError) throw new
|
|
2497
|
+
if (error instanceof DocsPaginationCursorError) throw new ProtocolError(ProtocolErrorCode.InvalidParams, error.message);
|
|
2319
2498
|
throw error;
|
|
2320
2499
|
}
|
|
2321
2500
|
}
|
|
@@ -2346,10 +2525,10 @@ function paginateDocsMcpSdkListResult(result, field, options) {
|
|
|
2346
2525
|
function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
2347
2526
|
const originalSetRequestHandler = server.server.setRequestHandler;
|
|
2348
2527
|
const setRequestHandler = originalSetRequestHandler.bind(server.server);
|
|
2349
|
-
const interceptedSetRequestHandler = ((
|
|
2528
|
+
const interceptedSetRequestHandler = ((method, handler) => {
|
|
2350
2529
|
const sdkHandler = handler;
|
|
2351
|
-
if (
|
|
2352
|
-
setRequestHandler(
|
|
2530
|
+
if (method === "resources/list") {
|
|
2531
|
+
setRequestHandler("resources/list", async (request, extra) => {
|
|
2353
2532
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resources", {
|
|
2354
2533
|
kind: "mcp.protocol/resources-list",
|
|
2355
2534
|
scope,
|
|
@@ -2362,8 +2541,8 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2362
2541
|
});
|
|
2363
2542
|
return;
|
|
2364
2543
|
}
|
|
2365
|
-
if (
|
|
2366
|
-
setRequestHandler(
|
|
2544
|
+
if (method === "resources/templates/list") {
|
|
2545
|
+
setRequestHandler("resources/templates/list", async (request, extra) => {
|
|
2367
2546
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resourceTemplates", {
|
|
2368
2547
|
kind: "mcp.protocol/resource-templates-list",
|
|
2369
2548
|
scope,
|
|
@@ -2376,8 +2555,8 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2376
2555
|
});
|
|
2377
2556
|
return;
|
|
2378
2557
|
}
|
|
2379
|
-
if (
|
|
2380
|
-
setRequestHandler(
|
|
2558
|
+
if (method === "tools/list") {
|
|
2559
|
+
setRequestHandler("tools/list", async (request, extra) => {
|
|
2381
2560
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "tools", {
|
|
2382
2561
|
kind: "mcp.protocol/tools-list",
|
|
2383
2562
|
scope,
|
|
@@ -2387,8 +2566,8 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2387
2566
|
});
|
|
2388
2567
|
return;
|
|
2389
2568
|
}
|
|
2390
|
-
if (
|
|
2391
|
-
setRequestHandler(
|
|
2569
|
+
if (method === "prompts/list") {
|
|
2570
|
+
setRequestHandler("prompts/list", async (request, extra) => {
|
|
2392
2571
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "prompts", {
|
|
2393
2572
|
kind: "mcp.protocol/prompts-list",
|
|
2394
2573
|
scope,
|
|
@@ -2398,7 +2577,7 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2398
2577
|
});
|
|
2399
2578
|
return;
|
|
2400
2579
|
}
|
|
2401
|
-
setRequestHandler(
|
|
2580
|
+
setRequestHandler(method, handler);
|
|
2402
2581
|
});
|
|
2403
2582
|
server.server.setRequestHandler = interceptedSetRequestHandler;
|
|
2404
2583
|
return () => {
|
|
@@ -2415,11 +2594,8 @@ function installDocsMcpSdkRegistrationPagination(server, scope) {
|
|
|
2415
2594
|
}
|
|
2416
2595
|
} });
|
|
2417
2596
|
server.registerTool = wrapRegistration(server.registerTool);
|
|
2418
|
-
server.tool = wrapRegistration(server.tool);
|
|
2419
2597
|
server.registerResource = wrapRegistration(server.registerResource);
|
|
2420
|
-
server.resource = wrapRegistration(server.resource);
|
|
2421
2598
|
server.registerPrompt = wrapRegistration(server.registerPrompt);
|
|
2422
|
-
server.prompt = wrapRegistration(server.prompt);
|
|
2423
2599
|
}
|
|
2424
2600
|
async function createDocsMcpServer(options) {
|
|
2425
2601
|
const resolved = resolveDocsMcpConfig(options.mcp, {
|
|
@@ -2431,11 +2607,13 @@ async function createDocsMcpServer(options) {
|
|
|
2431
2607
|
name: resolved.name,
|
|
2432
2608
|
version: resolved.version
|
|
2433
2609
|
});
|
|
2610
|
+
const contentChangesEnabled = resolveDocsContentChangesConfig(options.contentChanges).enabled && resolved.tools.listContentChanges !== false;
|
|
2434
2611
|
const server = new McpServer({
|
|
2435
2612
|
name: resolved.name,
|
|
2436
2613
|
version: resolved.version
|
|
2437
2614
|
});
|
|
2438
2615
|
installDocsMcpSdkRegistrationPagination(server, protocolScope);
|
|
2616
|
+
if (contentChangesEnabled) server.server.registerCapabilities({ resources: { subscribe: true } });
|
|
2439
2617
|
const registerResource = (name, uri, metadata, callback) => {
|
|
2440
2618
|
return server.registerResource(name, uri, metadata, callback);
|
|
2441
2619
|
};
|
|
@@ -2472,6 +2650,26 @@ async function createDocsMcpServer(options) {
|
|
|
2472
2650
|
const defaultPages = dedupePages(await getSourcePages());
|
|
2473
2651
|
const defaultTree = await getSourceNavigation();
|
|
2474
2652
|
const defaultSkills = await getSourceSkills();
|
|
2653
|
+
const contentChangeFeed = options.contentChangeFeed ?? createDocsContentChangeFeed(options.contentChanges);
|
|
2654
|
+
async function resolveContentChanges(since, locale) {
|
|
2655
|
+
if (!contentChangesEnabled) throw new ProtocolError(ProtocolErrorCode.MethodNotFound, "Content changes are disabled.");
|
|
2656
|
+
if (since && !isDocsContentChangeGeneration(since)) throw new ProtocolError(ProtocolErrorCode.InvalidParams, "Content-change `since` must be a SHA-256 index generation.");
|
|
2657
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2658
|
+
try {
|
|
2659
|
+
return await contentChangeFeed.resolve({
|
|
2660
|
+
pages: toSearchSourcePages(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext))),
|
|
2661
|
+
search: options.search,
|
|
2662
|
+
audience: "agent",
|
|
2663
|
+
locale: resolvedLocale,
|
|
2664
|
+
baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0),
|
|
2665
|
+
...since ? { since } : {},
|
|
2666
|
+
...options.requestContext?.request ? { request: options.requestContext.request.clone() } : {}
|
|
2667
|
+
});
|
|
2668
|
+
} catch (error) {
|
|
2669
|
+
if (error instanceof DocsContentChangesRequestError) throw new ProtocolError(ProtocolErrorCode.InvalidParams, error.message);
|
|
2670
|
+
throw error;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2475
2673
|
registerResource("docs-navigation", "docs://navigation", {
|
|
2476
2674
|
title: "Docs Navigation",
|
|
2477
2675
|
description: "Structured navigation tree for the documentation site.",
|
|
@@ -2481,6 +2679,65 @@ async function createDocsMcpServer(options) {
|
|
|
2481
2679
|
mimeType: "text/plain",
|
|
2482
2680
|
text: renderNavigationTree(defaultTree)
|
|
2483
2681
|
}] }));
|
|
2682
|
+
if (contentChangesEnabled) {
|
|
2683
|
+
const readChanges = async (generation) => {
|
|
2684
|
+
const result = await resolveContentChanges(generation && generation !== "current" ? generation : void 0);
|
|
2685
|
+
return { contents: [{
|
|
2686
|
+
uri: generation && generation !== "current" ? `docs://changes/${generation}` : DOCS_MCP_CONTENT_CHANGES_CURRENT_URI,
|
|
2687
|
+
mimeType: "application/json",
|
|
2688
|
+
text: JSON.stringify(result, null, 2)
|
|
2689
|
+
}] };
|
|
2690
|
+
};
|
|
2691
|
+
registerResource("docs-content-changes-current", DOCS_MCP_CONTENT_CHANGES_CURRENT_URI, {
|
|
2692
|
+
title: "Current docs content changes",
|
|
2693
|
+
description: "Stable subscription target for body-free documentation change notifications.",
|
|
2694
|
+
mimeType: "application/json"
|
|
2695
|
+
}, async () => readChanges());
|
|
2696
|
+
server.registerResource("docs-content-changes-by-generation", new ResourceTemplate(DOCS_MCP_CONTENT_CHANGES_URI_TEMPLATE, { list: async () => {
|
|
2697
|
+
return { resources: [{
|
|
2698
|
+
uri: `docs://changes/${(await resolveContentChanges()).indexGeneration}`,
|
|
2699
|
+
name: "Docs changes from current generation",
|
|
2700
|
+
title: "Docs changes from current generation",
|
|
2701
|
+
description: "Read this URI later to retrieve changes since the listed generation.",
|
|
2702
|
+
mimeType: "application/json"
|
|
2703
|
+
}] };
|
|
2704
|
+
} }), {
|
|
2705
|
+
title: "Docs content changes by generation",
|
|
2706
|
+
description: "Body-free documentation changes from a SHA-256 index generation to the current generation.",
|
|
2707
|
+
mimeType: "application/json"
|
|
2708
|
+
}, async (_uri, variables) => {
|
|
2709
|
+
const generation = variables.generation;
|
|
2710
|
+
if (typeof generation !== "string" || !isDocsContentChangeGeneration(generation)) throw new ProtocolError(ProtocolErrorCode.InvalidParams, "Change resource generation must be a SHA-256 index generation.");
|
|
2711
|
+
return readChanges(generation);
|
|
2712
|
+
});
|
|
2713
|
+
registerTool("list_content_changes", {
|
|
2714
|
+
title: "List docs content changes",
|
|
2715
|
+
description: "Synchronize body-free document metadata. Save indexGeneration and pass it as since on the next poll. A reset response means the named snapshot is no longer available.",
|
|
2716
|
+
inputSchema: listContentChangesInputSchema,
|
|
2717
|
+
outputSchema: contentChangesOutputSchema,
|
|
2718
|
+
annotations: { readOnlyHint: true }
|
|
2719
|
+
}, async ({ since, locale }) => {
|
|
2720
|
+
const startedAt = nowMs();
|
|
2721
|
+
const result = await resolveContentChanges(since, locale);
|
|
2722
|
+
trackMcpTool("list_content_changes", {
|
|
2723
|
+
locale,
|
|
2724
|
+
resultCount: result.counts.added + result.counts.changed + result.counts.deleted
|
|
2725
|
+
});
|
|
2726
|
+
await emitDocsAnalyticsEvent(options.analytics, {
|
|
2727
|
+
type: "mcp_tool",
|
|
2728
|
+
source: "mcp",
|
|
2729
|
+
locale,
|
|
2730
|
+
properties: {
|
|
2731
|
+
tool: "list_content_changes",
|
|
2732
|
+
mode: result.mode,
|
|
2733
|
+
resetRequired: result.resetRequired,
|
|
2734
|
+
resultCount: result.counts.added + result.counts.changed + result.counts.deleted,
|
|
2735
|
+
durationMs: durationMs(startedAt)
|
|
2736
|
+
}
|
|
2737
|
+
});
|
|
2738
|
+
return createStructuredTextResult(result);
|
|
2739
|
+
});
|
|
2740
|
+
}
|
|
2484
2741
|
for (const page of defaultPages) {
|
|
2485
2742
|
const resourceUri = toPageResourceUri(page.url);
|
|
2486
2743
|
registerResource(`page-${slugToKey(page.slug)}`, resourceUri, {
|
|
@@ -3115,6 +3372,112 @@ async function createDocsMcpServer(options) {
|
|
|
3115
3372
|
throw error;
|
|
3116
3373
|
}
|
|
3117
3374
|
});
|
|
3375
|
+
if (resolved.tools.searchFacets) registerTool("list_search_facets", {
|
|
3376
|
+
title: "List documentation search facets",
|
|
3377
|
+
description: "List valid framework, version, package, and tag filters with matching page counts before calling search_docs. Use facet, limit, and cursor to continue a large facet without document bodies.",
|
|
3378
|
+
inputSchema: searchFacetsInputSchema,
|
|
3379
|
+
outputSchema: searchFacetsOutputSchema,
|
|
3380
|
+
annotations: { readOnlyHint: true }
|
|
3381
|
+
}, async ({ locale, audience, facet, limit, cursor, framework, version, package: packageName, tags }) => {
|
|
3382
|
+
const startedAt = nowMs();
|
|
3383
|
+
const resolvedAudience = audience ?? "agent";
|
|
3384
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
3385
|
+
const filters = {
|
|
3386
|
+
framework,
|
|
3387
|
+
version,
|
|
3388
|
+
package: packageName,
|
|
3389
|
+
tags
|
|
3390
|
+
};
|
|
3391
|
+
const trace = createDocsAgentTraceContext("mcp.tool.list_search_facets");
|
|
3392
|
+
const callSpanId = createDocsAgentTraceId("span");
|
|
3393
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3394
|
+
type: "tool.call",
|
|
3395
|
+
source: "mcp",
|
|
3396
|
+
traceId: trace.traceId,
|
|
3397
|
+
spanId: callSpanId,
|
|
3398
|
+
name: "list_search_facets",
|
|
3399
|
+
startedAt: trace.startedAt,
|
|
3400
|
+
status: "started",
|
|
3401
|
+
locale,
|
|
3402
|
+
inputPreview: {
|
|
3403
|
+
locale,
|
|
3404
|
+
audience: resolvedAudience,
|
|
3405
|
+
facet,
|
|
3406
|
+
limit,
|
|
3407
|
+
hasCursor: cursor !== void 0,
|
|
3408
|
+
filterFields: Object.entries(filters).filter(([, value]) => value !== void 0).map(([field]) => field)
|
|
3409
|
+
},
|
|
3410
|
+
metadata: { tool: "list_search_facets" }
|
|
3411
|
+
});
|
|
3412
|
+
try {
|
|
3413
|
+
const facets = await buildDocsSearchFacets({
|
|
3414
|
+
pages: toSearchSourcePages(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext))),
|
|
3415
|
+
search: toolSearchConfig ?? true,
|
|
3416
|
+
audience: resolvedAudience,
|
|
3417
|
+
filters,
|
|
3418
|
+
facet,
|
|
3419
|
+
limit,
|
|
3420
|
+
cursor,
|
|
3421
|
+
locale: resolvedLocale,
|
|
3422
|
+
baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0)
|
|
3423
|
+
});
|
|
3424
|
+
const elapsed = durationMs(startedAt);
|
|
3425
|
+
await emitDocsAnalyticsEvent(options.analytics, {
|
|
3426
|
+
type: "mcp_tool",
|
|
3427
|
+
source: "mcp",
|
|
3428
|
+
locale,
|
|
3429
|
+
properties: {
|
|
3430
|
+
tool: "list_search_facets",
|
|
3431
|
+
audience: resolvedAudience,
|
|
3432
|
+
matchedPageCount: facets.matchedPageCount,
|
|
3433
|
+
frameworkCount: facets.facets.framework.valueCount,
|
|
3434
|
+
versionCount: facets.facets.version.valueCount,
|
|
3435
|
+
packageCount: facets.facets.package.valueCount,
|
|
3436
|
+
tagCount: facets.facets.tags.valueCount,
|
|
3437
|
+
durationMs: elapsed
|
|
3438
|
+
}
|
|
3439
|
+
});
|
|
3440
|
+
trackMcpTool("list_search_facets", {
|
|
3441
|
+
locale,
|
|
3442
|
+
resultCount: facets.matchedPageCount
|
|
3443
|
+
});
|
|
3444
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3445
|
+
type: "tool.result",
|
|
3446
|
+
source: "mcp",
|
|
3447
|
+
traceId: trace.traceId,
|
|
3448
|
+
parentSpanId: callSpanId,
|
|
3449
|
+
name: "list_search_facets",
|
|
3450
|
+
startedAt: trace.startedAt,
|
|
3451
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3452
|
+
durationMs: elapsed,
|
|
3453
|
+
status: "success",
|
|
3454
|
+
locale,
|
|
3455
|
+
outputPreview: {
|
|
3456
|
+
matchedPageCount: facets.matchedPageCount,
|
|
3457
|
+
facetValueCount: Object.values(facets.facets).reduce((total, facet) => total + facet.valueCount, 0)
|
|
3458
|
+
},
|
|
3459
|
+
metadata: { tool: "list_search_facets" }
|
|
3460
|
+
});
|
|
3461
|
+
return createStructuredTextResult(facets);
|
|
3462
|
+
} catch (error) {
|
|
3463
|
+
const elapsed = durationMs(startedAt);
|
|
3464
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3465
|
+
type: "tool.error",
|
|
3466
|
+
source: "mcp",
|
|
3467
|
+
traceId: trace.traceId,
|
|
3468
|
+
parentSpanId: callSpanId,
|
|
3469
|
+
name: "list_search_facets",
|
|
3470
|
+
startedAt: trace.startedAt,
|
|
3471
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3472
|
+
durationMs: elapsed,
|
|
3473
|
+
status: "error",
|
|
3474
|
+
locale,
|
|
3475
|
+
outputPreview: { message: error instanceof Error ? error.message : "Unknown error" },
|
|
3476
|
+
metadata: { tool: "list_search_facets" }
|
|
3477
|
+
});
|
|
3478
|
+
throw error;
|
|
3479
|
+
}
|
|
3480
|
+
});
|
|
3118
3481
|
if (resolved.tools.searchDocs) registerTool("search_docs", {
|
|
3119
3482
|
title: "Search documentation",
|
|
3120
3483
|
description: "Search the docs by keyword with optional framework, version, package, and tag filters. Returns structured ambiguity and metadata warnings.",
|
|
@@ -3861,20 +4224,48 @@ function createDocsMcpHttpHandler(options) {
|
|
|
3861
4224
|
data: { reason: "mcp_disabled" }
|
|
3862
4225
|
}),
|
|
3863
4226
|
DELETE: async () => createJsonErrorResponse(404, disabledMessage),
|
|
3864
|
-
OPTIONS: async () => createJsonErrorResponse(404, disabledMessage)
|
|
4227
|
+
OPTIONS: async () => createJsonErrorResponse(404, disabledMessage),
|
|
4228
|
+
close: async () => {}
|
|
3865
4229
|
};
|
|
3866
|
-
|
|
3867
|
-
|
|
4230
|
+
const contentChangesEnabled = resolveDocsContentChangesConfig(options.contentChanges).enabled && resolved.tools.listContentChanges !== false;
|
|
4231
|
+
const contentChangeFeed = options.contentChangeFeed ?? createDocsContentChangeFeed(options.contentChanges);
|
|
4232
|
+
const eventBus = new InMemoryServerEventBus();
|
|
4233
|
+
const mcpHandler = createMcpHandler(async (context) => {
|
|
4234
|
+
const internalAuth = context.authInfo;
|
|
4235
|
+
return createDocsMcpServer({
|
|
3868
4236
|
...options,
|
|
3869
|
-
|
|
4237
|
+
contentChangeFeed,
|
|
4238
|
+
requestContext: {
|
|
4239
|
+
transport: "http",
|
|
4240
|
+
...context.requestInfo ? { request: context.requestInfo.clone() } : {},
|
|
4241
|
+
...internalAuth?.principal ? { auth: internalAuth.principal } : {}
|
|
4242
|
+
}
|
|
3870
4243
|
});
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
4244
|
+
}, {
|
|
4245
|
+
legacy: "stateless",
|
|
4246
|
+
bus: eventBus
|
|
4247
|
+
});
|
|
4248
|
+
const configuredPollInterval = options.contentChangePollIntervalMs;
|
|
4249
|
+
const contentChangePollIntervalMs = typeof configuredPollInterval === "number" && Number.isFinite(configuredPollInterval) && configuredPollInterval >= 10 ? Math.floor(configuredPollInterval) : DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS;
|
|
4250
|
+
async function readMonitoredGeneration(context) {
|
|
4251
|
+
const locale = options.source.resolveLocale?.(void 0, context);
|
|
4252
|
+
const pages = dedupePages(await options.source.getPages(locale, context));
|
|
4253
|
+
return (await contentChangeFeed.resolve({
|
|
4254
|
+
pages: toSearchSourcePages(pages),
|
|
4255
|
+
search: options.search,
|
|
4256
|
+
audience: "agent",
|
|
4257
|
+
locale,
|
|
4258
|
+
baseUrl: options.source.baseUrl ?? (context.request ? new URL(context.request.url).origin : void 0),
|
|
4259
|
+
...context.request ? { request: context.request.clone() } : {}
|
|
4260
|
+
})).indexGeneration;
|
|
3877
4261
|
}
|
|
4262
|
+
const contentChangeMonitor = createDocsMcpContentChangeMonitor({
|
|
4263
|
+
pollIntervalMs: contentChangePollIntervalMs,
|
|
4264
|
+
readGeneration: readMonitoredGeneration,
|
|
4265
|
+
notify: () => mcpHandler.notify.resourceUpdated(DOCS_MCP_CONTENT_CHANGES_CURRENT_URI),
|
|
4266
|
+
isActive: () => eventBus.listenerCount > 0,
|
|
4267
|
+
unrefTimer: true
|
|
4268
|
+
});
|
|
3878
4269
|
async function handle(request) {
|
|
3879
4270
|
const originalUrl = new URL(request.url);
|
|
3880
4271
|
const method = request.method.toUpperCase();
|
|
@@ -3957,26 +4348,77 @@ function createDocsMcpHttpHandler(options) {
|
|
|
3957
4348
|
code: -32700,
|
|
3958
4349
|
message: "Parse error: Invalid JSON"
|
|
3959
4350
|
}));
|
|
3960
|
-
|
|
4351
|
+
const requestContext = {
|
|
3961
4352
|
transport: "http",
|
|
3962
4353
|
request: request.clone(),
|
|
3963
4354
|
auth
|
|
3964
|
-
}
|
|
4355
|
+
};
|
|
4356
|
+
const isContentChangeSubscription = contentChangesEnabled && method === "POST" && typeof parsedBody === "object" && parsedBody !== null && !Array.isArray(parsedBody) && parsedBody.method === "subscriptions/listen";
|
|
4357
|
+
const authInfo = auth ? {
|
|
4358
|
+
token: "",
|
|
4359
|
+
clientId: auth.id,
|
|
4360
|
+
scopes: auth.scopes ?? [],
|
|
4361
|
+
principal: auth
|
|
4362
|
+
} : void 0;
|
|
4363
|
+
const response = await mcpHandler.fetch(request, {
|
|
4364
|
+
...parsedBody === void 0 ? {} : { parsedBody },
|
|
4365
|
+
...authInfo ? { authInfo } : {}
|
|
4366
|
+
});
|
|
4367
|
+
if (isContentChangeSubscription) await contentChangeMonitor.start(requestContext);
|
|
4368
|
+
return withCors(response);
|
|
3965
4369
|
}
|
|
3966
4370
|
return {
|
|
3967
4371
|
GET: async ({ request }) => handle(request),
|
|
3968
4372
|
POST: async ({ request }) => handle(request),
|
|
3969
4373
|
DELETE: async ({ request }) => handle(request),
|
|
3970
|
-
OPTIONS: async ({ request }) => handle(request)
|
|
4374
|
+
OPTIONS: async ({ request }) => handle(request),
|
|
4375
|
+
close: async () => {
|
|
4376
|
+
contentChangeMonitor.close();
|
|
4377
|
+
await mcpHandler.close();
|
|
4378
|
+
}
|
|
3971
4379
|
};
|
|
3972
4380
|
}
|
|
3973
4381
|
async function runDocsMcpStdio(options) {
|
|
3974
|
-
const
|
|
3975
|
-
|
|
3976
|
-
|
|
4382
|
+
const resolved = resolveDocsMcpConfig(options.mcp, {
|
|
4383
|
+
defaultName: options.defaultName ?? options.source.siteTitle ?? DEFAULT_MCP_NAME,
|
|
4384
|
+
defaultVersion: options.defaultVersion
|
|
4385
|
+
});
|
|
4386
|
+
const contentChangesEnabled = resolveDocsContentChangesConfig(options.contentChanges).enabled && resolved.tools.listContentChanges !== false;
|
|
4387
|
+
const contentChangeFeed = options.contentChangeFeed ?? createDocsContentChangeFeed(options.contentChanges);
|
|
4388
|
+
const configuredPollInterval = options.contentChangePollIntervalMs;
|
|
4389
|
+
const pollIntervalMs = typeof configuredPollInterval === "number" && Number.isFinite(configuredPollInterval) && configuredPollInterval >= 10 ? Math.floor(configuredPollInterval) : DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS;
|
|
4390
|
+
serveStdio(async () => {
|
|
4391
|
+
const requestContext = { transport: "stdio" };
|
|
4392
|
+
const server = await createDocsMcpServer({
|
|
4393
|
+
...options,
|
|
4394
|
+
contentChangeFeed,
|
|
4395
|
+
requestContext
|
|
4396
|
+
});
|
|
4397
|
+
if (!contentChangesEnabled) return server;
|
|
4398
|
+
const readGeneration = async () => {
|
|
4399
|
+
const locale = options.source.resolveLocale?.(void 0, requestContext);
|
|
4400
|
+
const pages = dedupePages(await options.source.getPages(locale, requestContext));
|
|
4401
|
+
return (await contentChangeFeed.resolve({
|
|
4402
|
+
pages: toSearchSourcePages(pages),
|
|
4403
|
+
search: options.search,
|
|
4404
|
+
audience: "agent",
|
|
4405
|
+
locale,
|
|
4406
|
+
baseUrl: options.source.baseUrl
|
|
4407
|
+
})).indexGeneration;
|
|
4408
|
+
};
|
|
4409
|
+
const monitor = createDocsMcpContentChangeMonitor({
|
|
4410
|
+
pollIntervalMs,
|
|
4411
|
+
readGeneration: () => readGeneration(),
|
|
4412
|
+
notify: () => server.server.sendResourceUpdated({ uri: DOCS_MCP_CONTENT_CHANGES_CURRENT_URI })
|
|
4413
|
+
});
|
|
4414
|
+
await monitor.start(requestContext);
|
|
4415
|
+
const closeServer = server.close.bind(server);
|
|
4416
|
+
server.close = async () => {
|
|
4417
|
+
monitor.close();
|
|
4418
|
+
await closeServer();
|
|
4419
|
+
};
|
|
4420
|
+
return server;
|
|
3977
4421
|
});
|
|
3978
|
-
const transport = new StdioServerTransport();
|
|
3979
|
-
await server.connect(transport);
|
|
3980
4422
|
}
|
|
3981
4423
|
async function isDocsMcpOriginAllowed(request, allowedOrigins) {
|
|
3982
4424
|
const origin = request.headers.get("origin");
|
|
@@ -5417,4 +5859,4 @@ function toPageResourceUri(url) {
|
|
|
5417
5859
|
}
|
|
5418
5860
|
|
|
5419
5861
|
//#endregion
|
|
5420
|
-
export { DEFAULT_DOCS_MCP_CORS_ALLOWED_HEADERS, DEFAULT_DOCS_MCP_CORS_EXPOSED_HEADERS, DEFAULT_DOCS_MCP_CORS_MAX_AGE_SECONDS, DEFAULT_DOCS_MCP_MAX_BODY_BYTES, DOCS_CONFIG_SCHEMA_OPTIONS, buildDocsMcpContext, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, getDocsConfigSchema, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio };
|
|
5862
|
+
export { DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS, DEFAULT_DOCS_MCP_CORS_ALLOWED_HEADERS, DEFAULT_DOCS_MCP_CORS_EXPOSED_HEADERS, DEFAULT_DOCS_MCP_CORS_MAX_AGE_SECONDS, DEFAULT_DOCS_MCP_MAX_BODY_BYTES, DOCS_CONFIG_SCHEMA_OPTIONS, DOCS_MCP_CONTENT_CHANGES_CURRENT_URI, DOCS_MCP_CONTENT_CHANGES_URI_TEMPLATE, buildDocsMcpContext, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, getDocsConfigSchema, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio };
|