@farming-labs/docs 0.2.75 → 0.2.78
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-BHqaZx-X.mjs → agent-Ba94vwM2.mjs} +4308 -340
- package/dist/{agent-cAPjC2jb.d.mts → agent-CHgWJcK_.d.mts} +60 -2
- package/dist/{agent-DxTa3PLB.mjs → agent-CM-hzhfh.mjs} +2 -2
- package/dist/{agent-evals-21LZ_uEl.mjs → agent-evals-C8dkgJMN.mjs} +1 -1
- package/dist/{agent-export-3VheegEK.mjs → agent-export-DdF-IVfg.mjs} +8 -7
- package/dist/agent-provenance-D8UBpnMc.mjs +463 -0
- package/dist/agent-skills-bundle.d.mts +1 -1
- package/dist/{agent-skills-server-noFn1l_p.mjs → agent-skills-server-B2EXn2QD.mjs} +1 -1
- package/dist/{agent-skills-server-Cix64aGB.d.mts → agent-skills-server-zvs0Yknt.d.mts} +2 -2
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/agent-skills-vite.mjs +2 -2
- package/dist/{agents-ByTdP0Hl.mjs → agents-v0Em2KZo.mjs} +7 -16
- package/dist/cli/index.mjs +15 -15
- package/dist/client/react.d.mts +1 -1
- package/dist/{cloud-ask-ai-Bt0rzFbe.d.mts → cloud-ask-ai-BwsdF7AQ.d.mts} +1 -1
- package/dist/{dev-Cc1cFFj-.mjs → dev-kjaxOOla.mjs} +8 -2
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/{doctor-C34VVF85.mjs → doctor-BbrN0rdC.mjs} +56 -24
- package/dist/{golden-evaluations-D_oDJwGv.mjs → golden-evaluations-Bk9t-HNq.mjs} +12 -3
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +6 -6
- package/dist/{mcp-Bnqfu8P5.mjs → mcp-DT-WNsA-.mjs} +6 -6
- package/dist/mcp.d.mts +28 -6
- package/dist/mcp.mjs +557 -62
- package/dist/{prompt-references-CfyYOa_W.mjs → prompt-references-CoDorsvS.mjs} +3 -3
- package/dist/{retrieval-digest-CFOcSKTo.d.mts → retrieval-digest-CO3wqeMk.d.mts} +105 -6
- package/dist/{review-Dw6oCQX3.mjs → review-DrCaaT7G.mjs} +5 -5
- package/dist/{robots-DaYBoy_A.mjs → robots-C_v2HK43.mjs} +2 -2
- package/dist/{robots-KWLujSLI.mjs → robots-izJbM9cv.mjs} +3 -3
- package/dist/{search-DBdmbUkc.mjs → search-YiZMZDfb.mjs} +6 -6
- package/dist/server.d.mts +9 -7
- package/dist/server.mjs +7 -7
- package/dist/{sitemap-CrzG5Wpf.mjs → sitemap-NO8UMO6Y.mjs} +6 -6
- package/dist/{sitemap-server-B9LZQ1FE.mjs → sitemap-server-Dgxs9V6S.mjs} +12 -3
- package/dist/{standards-discovery-BwL5ffGx.mjs → standards-discovery-BKlEnK_H.mjs} +32 -4
- package/dist/{standards-discovery-DBI1PD7m.d.mts → standards-discovery-BWyNgZSs.d.mts} +34 -7
- package/dist/{types-BDRwrExu.d.mts → types-CpLnwHak.d.mts} +190 -2
- package/package.json +1 -1
- package/dist/search-BmC8wVr0.mjs +0 -3490
package/dist/mcp.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
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,
|
|
2
|
+
import { $n as resolveDocsMcpResourceLocation, An as normalizeAgentScopeValues, Dn as agentVersionConstraintsOverlap, E as DOCS_MARKDOWN_SECTION_INDEX_FORMAT, En as agentVersionConstraintMatches, Fn as isDocsRetrievalCanonicalUrl, In as normalizeDocsRelated, Kn as isDocsMcpOAuthScopeToken, Ln as renderDocsRelatedMarkdownLines, Mn as DocsPaginationCursorError, Nn as paginateDocsItems, On as normalizeAgentFramework, P as buildDocsMarkdownSectionIndex, Qn as resolveDocsMcpProtectedResourceMetadataLocation, Xn as normalizeDocsMcpAuthorizationServerUrls, Yn as isDocsMcpResourcePath, Zn as normalizeDocsMcpEndpointPath, dn as performDocsSearchWithMetadata, en as buildDocsSearchFacets, kn as normalizeAgentLocale, ln as normalizeDocsSearchFilters, qn as isDocsMcpProtectedResourceMetadataPath, un as performDocsSearch, wn as resolveDocsAudienceMdxContent, wt as toDocsMarkdownUrl } from "./agent-Ba94vwM2.mjs";
|
|
3
3
|
import { S as upsertPageAgentContractMarkdown, _ as hasStructuredPageAgentContract, o as findDocsMarkdownSection, s as parseDocsMarkdownSections, v as normalizePageAgentFrontmatter } from "./markdown-sections-7OoA7ylx.mjs";
|
|
4
|
-
import "./standards-discovery-
|
|
5
|
-
import {
|
|
4
|
+
import "./standards-discovery-BKlEnK_H.mjs";
|
|
5
|
+
import { f as emitDocsTelemetryAgentSurfaceEvent, h as emitDocsTelemetryProjectEvent, l as resolvePageSidebarFolderIndexBehavior, m as emitDocsTelemetryMcpToolEvent, s as stripGeneratedAgentProvenance } from "./agent-provenance-D8UBpnMc.mjs";
|
|
6
6
|
import matter from "gray-matter";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
10
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
11
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
12
|
-
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
import { ErrorCode, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
13
13
|
import * as z from "zod/v4";
|
|
14
14
|
|
|
15
15
|
//#region src/mcp.ts
|
|
@@ -18,6 +18,9 @@ const DEFAULT_MCP_NAME = "@farming-labs/docs";
|
|
|
18
18
|
const DEFAULT_MCP_CONTEXT_TOKEN_BUDGET = 4e3;
|
|
19
19
|
const MIN_MCP_CONTEXT_TOKEN_BUDGET = 256;
|
|
20
20
|
const MAX_MCP_CONTEXT_TOKEN_BUDGET = 32e3;
|
|
21
|
+
const DOCS_MCP_PROTOCOL_LIST_PAGE_SIZE = 10;
|
|
22
|
+
const DOCS_MCP_TOOL_LIST_PAGE_SIZE = 25;
|
|
23
|
+
const DOCS_MCP_PAGINATION_META_KEY = "dev.farming-labs/pagination";
|
|
21
24
|
const UTF8_ENCODER = new TextEncoder();
|
|
22
25
|
const DEFAULT_DOCS_MCP_MAX_BODY_BYTES = 1024 * 1024;
|
|
23
26
|
const DEFAULT_DOCS_MCP_CORS_MAX_AGE_SECONDS = 600;
|
|
@@ -220,9 +223,44 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
220
223
|
path: "agent",
|
|
221
224
|
name: "agent",
|
|
222
225
|
type: "DocsAgentConfig",
|
|
223
|
-
description: "Agent compaction defaults and offline-by-default usefulness evaluations.",
|
|
226
|
+
description: "Agent synchronization, reusable skills, compaction defaults, and offline-by-default usefulness evaluations.",
|
|
224
227
|
docs: "/docs/getting-started/agent-ready-docs",
|
|
225
228
|
children: [
|
|
229
|
+
{
|
|
230
|
+
path: "agent.contentChanges",
|
|
231
|
+
name: "contentChanges",
|
|
232
|
+
type: "boolean | DocsAgentContentChangesConfig",
|
|
233
|
+
default: true,
|
|
234
|
+
description: "Body-free runtime document synchronization feed. Disable it with false, or configure bounded and durable snapshot history.",
|
|
235
|
+
children: [
|
|
236
|
+
{
|
|
237
|
+
path: "agent.contentChanges.enabled",
|
|
238
|
+
name: "enabled",
|
|
239
|
+
type: "boolean",
|
|
240
|
+
default: true,
|
|
241
|
+
description: "Whether runtime adapters serve response=changes."
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
path: "agent.contentChanges.maxSnapshots",
|
|
245
|
+
name: "maxSnapshots",
|
|
246
|
+
type: "number",
|
|
247
|
+
default: 8,
|
|
248
|
+
description: "Metadata-only snapshots retained in this server process; accepted range is 1 through 64."
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
path: "agent.contentChanges.loadSnapshot",
|
|
252
|
+
name: "loadSnapshot",
|
|
253
|
+
type: "DocsContentChangeSnapshotLoader",
|
|
254
|
+
description: "Optional callback that loads a prior generation from durable storage for exact cross-deployment deltas."
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
path: "agent.contentChanges.saveSnapshot",
|
|
258
|
+
name: "saveSnapshot",
|
|
259
|
+
type: "DocsContentChangeSnapshotSaver",
|
|
260
|
+
description: "Optional callback that persists each current metadata snapshot to durable storage."
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
},
|
|
226
264
|
{
|
|
227
265
|
path: "agent.skills",
|
|
228
266
|
name: "skills",
|
|
@@ -1523,6 +1561,13 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
1523
1561
|
default: true,
|
|
1524
1562
|
description: "Expose the search_docs tool."
|
|
1525
1563
|
},
|
|
1564
|
+
{
|
|
1565
|
+
path: "mcp.tools.searchFacets",
|
|
1566
|
+
name: "searchFacets",
|
|
1567
|
+
type: "boolean",
|
|
1568
|
+
default: true,
|
|
1569
|
+
description: "Expose the list_search_facets tool for body-free framework, version, package, and tag discovery."
|
|
1570
|
+
},
|
|
1526
1571
|
{
|
|
1527
1572
|
path: "mcp.tools.readPage",
|
|
1528
1573
|
name: "readPage",
|
|
@@ -1562,17 +1607,26 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
1562
1607
|
default: false,
|
|
1563
1608
|
description: "Generated API reference pages from framework route conventions or a hosted OpenAPI document.",
|
|
1564
1609
|
docs: "/docs/customization/api-reference",
|
|
1565
|
-
children: [
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1610
|
+
children: [
|
|
1611
|
+
{
|
|
1612
|
+
path: "apiReference.specUrl",
|
|
1613
|
+
name: "specUrl",
|
|
1614
|
+
type: "string",
|
|
1615
|
+
description: "Remote OpenAPI JSON URL when the backend owns the schema."
|
|
1616
|
+
},
|
|
1617
|
+
{
|
|
1618
|
+
path: "apiReference.path",
|
|
1619
|
+
name: "path",
|
|
1620
|
+
type: "string",
|
|
1621
|
+
description: "Docs route where the API reference is rendered."
|
|
1622
|
+
},
|
|
1623
|
+
{
|
|
1624
|
+
path: "apiReference.catalogTargets",
|
|
1625
|
+
name: "catalogTargets",
|
|
1626
|
+
type: "string[]",
|
|
1627
|
+
description: "Product API base URLs that the OpenAPI document describes in the RFC 9727 catalog."
|
|
1628
|
+
}
|
|
1629
|
+
]
|
|
1576
1630
|
},
|
|
1577
1631
|
{
|
|
1578
1632
|
path: "codeBlocks",
|
|
@@ -1704,9 +1758,11 @@ export default defineDocs({
|
|
|
1704
1758
|
}
|
|
1705
1759
|
]);
|
|
1706
1760
|
const searchFilterValueSchema = z.union([z.string().trim().min(1).max(128), z.array(z.string().trim().min(1).max(128)).min(1).max(16)]);
|
|
1761
|
+
const paginationCursorInputSchema = z.string().min(1).max(4096).describe("Opaque nextCursor from the preceding response page.").optional();
|
|
1707
1762
|
const searchDocsInputSchema = z.object({
|
|
1708
1763
|
query: z.string().trim().min(1),
|
|
1709
1764
|
limit: z.number().int().min(1).max(25).optional(),
|
|
1765
|
+
cursor: paginationCursorInputSchema,
|
|
1710
1766
|
locale: z.string().trim().min(1).max(128).optional(),
|
|
1711
1767
|
audience: z.enum(["human", "agent"]).optional(),
|
|
1712
1768
|
framework: searchFilterValueSchema.optional(),
|
|
@@ -1714,6 +1770,22 @@ const searchDocsInputSchema = z.object({
|
|
|
1714
1770
|
package: searchFilterValueSchema.optional(),
|
|
1715
1771
|
tags: searchFilterValueSchema.optional()
|
|
1716
1772
|
});
|
|
1773
|
+
const searchFacetsInputSchema = z.object({
|
|
1774
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1775
|
+
audience: z.enum(["human", "agent"]).optional(),
|
|
1776
|
+
facet: z.enum([
|
|
1777
|
+
"framework",
|
|
1778
|
+
"version",
|
|
1779
|
+
"package",
|
|
1780
|
+
"tags"
|
|
1781
|
+
]).optional(),
|
|
1782
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
1783
|
+
cursor: paginationCursorInputSchema,
|
|
1784
|
+
framework: searchFilterValueSchema.optional(),
|
|
1785
|
+
version: searchFilterValueSchema.optional(),
|
|
1786
|
+
package: searchFilterValueSchema.optional(),
|
|
1787
|
+
tags: searchFilterValueSchema.optional()
|
|
1788
|
+
});
|
|
1717
1789
|
const readPageInputSchema = z.object({
|
|
1718
1790
|
path: z.string().min(1),
|
|
1719
1791
|
locale: z.string().trim().min(1).max(128).optional(),
|
|
@@ -1724,14 +1796,16 @@ const listPageSectionsInputSchema = z.object({
|
|
|
1724
1796
|
path: z.string().min(1),
|
|
1725
1797
|
locale: z.string().trim().min(1).max(128).optional(),
|
|
1726
1798
|
tokenBudget: z.number().int().min(1).max(1e6).optional(),
|
|
1727
|
-
byteBudget: z.number().int().min(1).max(1e6).optional()
|
|
1799
|
+
byteBudget: z.number().int().min(1).max(1e6).optional(),
|
|
1800
|
+
cursor: paginationCursorInputSchema
|
|
1728
1801
|
});
|
|
1729
1802
|
const listTasksInputSchema = z.object({
|
|
1730
1803
|
query: z.string().trim().min(1).optional(),
|
|
1731
1804
|
framework: z.string().trim().min(1).optional(),
|
|
1732
1805
|
version: z.string().trim().min(1).optional(),
|
|
1733
1806
|
package: z.string().trim().min(1).optional(),
|
|
1734
|
-
locale: z.string().trim().min(1).max(128).optional()
|
|
1807
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1808
|
+
cursor: paginationCursorInputSchema
|
|
1735
1809
|
});
|
|
1736
1810
|
const readTaskInputSchema = readPageInputSchema;
|
|
1737
1811
|
const pageAgentAppliesToOutputSchema = z.object({
|
|
@@ -1775,8 +1849,14 @@ const taskSummaryOutputSchema = z.object({
|
|
|
1775
1849
|
outcome: z.string().optional(),
|
|
1776
1850
|
appliesTo: pageAgentAppliesToOutputSchema.optional()
|
|
1777
1851
|
});
|
|
1852
|
+
const paginationOutputShape = {
|
|
1853
|
+
resultCount: z.number().int().nonnegative().describe("Items returned in this response page."),
|
|
1854
|
+
total: z.number().int().nonnegative().describe("Items in the complete filtered result set."),
|
|
1855
|
+
hasMore: z.boolean().describe("Whether another response page is available."),
|
|
1856
|
+
nextCursor: z.string().describe("Opaque cursor to pass as cursor on the next request.").optional()
|
|
1857
|
+
};
|
|
1778
1858
|
const listTasksOutputSchema = z.object({
|
|
1779
|
-
|
|
1859
|
+
...paginationOutputShape,
|
|
1780
1860
|
tasks: z.array(taskSummaryOutputSchema)
|
|
1781
1861
|
});
|
|
1782
1862
|
const readTaskOutputSchema = z.object({
|
|
@@ -1790,10 +1870,14 @@ const readTaskOutputSchema = z.object({
|
|
|
1790
1870
|
}),
|
|
1791
1871
|
contract: pageAgentContractOutputSchema
|
|
1792
1872
|
});
|
|
1793
|
-
const listPagesInputSchema = z.object({
|
|
1873
|
+
const listPagesInputSchema = z.object({
|
|
1874
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1875
|
+
cursor: paginationCursorInputSchema
|
|
1876
|
+
});
|
|
1794
1877
|
const listDocsInputSchema = z.object({
|
|
1795
1878
|
section: z.string().trim().min(1).optional(),
|
|
1796
|
-
locale: z.string().trim().min(1).max(128).optional()
|
|
1879
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1880
|
+
cursor: paginationCursorInputSchema
|
|
1797
1881
|
});
|
|
1798
1882
|
const getNavigationInputSchema = z.object({ locale: z.string().trim().min(1).max(128).optional() });
|
|
1799
1883
|
const getConfigSchemaInputSchema = z.object({
|
|
@@ -1846,10 +1930,13 @@ const docsSectionOutputSchema = z.lazy(() => z.object({
|
|
|
1846
1930
|
pages: z.array(pageSummaryOutputSchema),
|
|
1847
1931
|
sections: z.array(docsSectionOutputSchema)
|
|
1848
1932
|
}));
|
|
1849
|
-
const listPagesOutputSchema = z.object({
|
|
1933
|
+
const listPagesOutputSchema = z.object({
|
|
1934
|
+
...paginationOutputShape,
|
|
1935
|
+
pages: z.array(pageSummaryOutputSchema)
|
|
1936
|
+
});
|
|
1850
1937
|
const listDocsOutputSchema = z.object({
|
|
1938
|
+
...paginationOutputShape,
|
|
1851
1939
|
section: z.string().optional(),
|
|
1852
|
-
resultCount: z.number().int().nonnegative(),
|
|
1853
1940
|
sectionCount: z.number().int().nonnegative(),
|
|
1854
1941
|
pages: z.array(pageSummaryOutputSchema),
|
|
1855
1942
|
rootPages: z.array(pageSummaryOutputSchema),
|
|
@@ -1951,10 +2038,34 @@ const searchDocsOutputSchema = z.object({
|
|
|
1951
2038
|
audience: z.enum(["human", "agent"]),
|
|
1952
2039
|
filters: searchFiltersOutputSchema,
|
|
1953
2040
|
indexGeneration: retrievalSourceDigestOutputSchema,
|
|
1954
|
-
|
|
2041
|
+
...paginationOutputShape,
|
|
1955
2042
|
results: z.array(searchResultOutputSchema),
|
|
1956
2043
|
warnings: z.array(searchWarningOutputSchema)
|
|
1957
2044
|
});
|
|
2045
|
+
const searchFacetOutputSchema = z.object({
|
|
2046
|
+
valueCount: z.number().int().nonnegative(),
|
|
2047
|
+
total: z.number().int().nonnegative(),
|
|
2048
|
+
hasMore: z.boolean(),
|
|
2049
|
+
nextCursor: z.string().optional(),
|
|
2050
|
+
truncated: z.boolean(),
|
|
2051
|
+
values: z.array(z.object({
|
|
2052
|
+
value: z.string(),
|
|
2053
|
+
count: z.number().int().nonnegative()
|
|
2054
|
+
}))
|
|
2055
|
+
});
|
|
2056
|
+
const searchFacetsOutputSchema = z.object({
|
|
2057
|
+
format: z.literal("docs-search-facets.v1"),
|
|
2058
|
+
audience: z.enum(["human", "agent"]),
|
|
2059
|
+
filters: searchFiltersOutputSchema,
|
|
2060
|
+
indexGeneration: retrievalSourceDigestOutputSchema,
|
|
2061
|
+
matchedPageCount: z.number().int().nonnegative(),
|
|
2062
|
+
facets: z.object({
|
|
2063
|
+
framework: searchFacetOutputSchema,
|
|
2064
|
+
version: searchFacetOutputSchema,
|
|
2065
|
+
package: searchFacetOutputSchema,
|
|
2066
|
+
tags: searchFacetOutputSchema
|
|
2067
|
+
})
|
|
2068
|
+
});
|
|
1958
2069
|
const codeExampleOutputSchema = z.object({
|
|
1959
2070
|
id: z.string(),
|
|
1960
2071
|
page: z.object({
|
|
@@ -2046,6 +2157,7 @@ const pageSectionIndexOutputSchema = z.object({
|
|
|
2046
2157
|
sectionIndexUrl: z.string(),
|
|
2047
2158
|
lineNumbering: z.literal("body"),
|
|
2048
2159
|
sectionCount: z.number().int().nonnegative(),
|
|
2160
|
+
...paginationOutputShape,
|
|
2049
2161
|
estimatedTokens: z.number().int().nonnegative(),
|
|
2050
2162
|
utf8Bytes: z.number().int().nonnegative(),
|
|
2051
2163
|
fetchBudget: z.object({
|
|
@@ -2115,6 +2227,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2115
2227
|
listTasks: true,
|
|
2116
2228
|
readTask: true,
|
|
2117
2229
|
searchDocs: true,
|
|
2230
|
+
searchFacets: true,
|
|
2118
2231
|
getNavigation: true,
|
|
2119
2232
|
getCodeExamples: true,
|
|
2120
2233
|
getConfigSchema: true,
|
|
@@ -2136,6 +2249,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2136
2249
|
listTasks: config.tools?.listTasks ?? true,
|
|
2137
2250
|
readTask: config.tools?.readTask ?? true,
|
|
2138
2251
|
searchDocs: config.tools?.searchDocs ?? true,
|
|
2252
|
+
searchFacets: config.tools?.searchFacets ?? true,
|
|
2139
2253
|
getNavigation: config.tools?.getNavigation ?? true,
|
|
2140
2254
|
getCodeExamples: config.tools?.getCodeExamples ?? true,
|
|
2141
2255
|
getConfigSchema: config.tools?.getConfigSchema ?? true,
|
|
@@ -2263,16 +2377,155 @@ function createStructuredTextResult(structuredContent, text) {
|
|
|
2263
2377
|
structuredContent
|
|
2264
2378
|
};
|
|
2265
2379
|
}
|
|
2380
|
+
function stableDocsMcpPaginationScope(values) {
|
|
2381
|
+
return JSON.stringify(values);
|
|
2382
|
+
}
|
|
2383
|
+
function docsMcpPaginationSnapshot(values) {
|
|
2384
|
+
return JSON.stringify(values);
|
|
2385
|
+
}
|
|
2386
|
+
function paginateDocsMcpItems(items, options) {
|
|
2387
|
+
return paginateDocsItems(items, {
|
|
2388
|
+
kind: options.kind,
|
|
2389
|
+
scope: options.scope,
|
|
2390
|
+
snapshot: docsMcpPaginationSnapshot(items),
|
|
2391
|
+
cursor: options.cursor,
|
|
2392
|
+
pageSize: options.pageSize ?? DOCS_MCP_TOOL_LIST_PAGE_SIZE
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
function paginateDocsMcpProtocolItems(items, options) {
|
|
2396
|
+
try {
|
|
2397
|
+
return paginateDocsMcpItems(items, {
|
|
2398
|
+
...options,
|
|
2399
|
+
pageSize: DOCS_MCP_PROTOCOL_LIST_PAGE_SIZE
|
|
2400
|
+
});
|
|
2401
|
+
} catch (error) {
|
|
2402
|
+
if (error instanceof DocsPaginationCursorError) throw new McpError(ErrorCode.InvalidParams, error.message);
|
|
2403
|
+
throw error;
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
function toDocsMcpProtocolPaginationMeta(result) {
|
|
2407
|
+
return { [DOCS_MCP_PAGINATION_META_KEY]: {
|
|
2408
|
+
hasMore: result.hasMore,
|
|
2409
|
+
total: result.total
|
|
2410
|
+
} };
|
|
2411
|
+
}
|
|
2412
|
+
function paginateDocsMcpSdkListResult(result, field, options) {
|
|
2413
|
+
const page = paginateDocsMcpProtocolItems([...result[field]].sort(options.compare), options);
|
|
2414
|
+
return {
|
|
2415
|
+
...result,
|
|
2416
|
+
[field]: page.items,
|
|
2417
|
+
nextCursor: page.nextCursor,
|
|
2418
|
+
_meta: {
|
|
2419
|
+
...result._meta,
|
|
2420
|
+
...toDocsMcpProtocolPaginationMeta(page)
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
/**
|
|
2425
|
+
* The MCP SDK owns the live registries and descriptor serialization. Intercepting the
|
|
2426
|
+
* handlers it installs lets pagination operate on that live output without copying private
|
|
2427
|
+
* registry state or drifting from SDK behavior when callers register, update, or disable
|
|
2428
|
+
* tools/resources after this factory returns.
|
|
2429
|
+
*/
|
|
2430
|
+
function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
2431
|
+
const originalSetRequestHandler = server.server.setRequestHandler;
|
|
2432
|
+
const setRequestHandler = originalSetRequestHandler.bind(server.server);
|
|
2433
|
+
const interceptedSetRequestHandler = ((requestSchema, handler) => {
|
|
2434
|
+
const sdkHandler = handler;
|
|
2435
|
+
if (Object.is(requestSchema, ListResourcesRequestSchema)) {
|
|
2436
|
+
setRequestHandler(ListResourcesRequestSchema, async (request, extra) => {
|
|
2437
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resources", {
|
|
2438
|
+
kind: "mcp.protocol/resources-list",
|
|
2439
|
+
scope,
|
|
2440
|
+
cursor: request.params?.cursor,
|
|
2441
|
+
compare: (left, right) => {
|
|
2442
|
+
const uriOrder = left.uri.localeCompare(right.uri);
|
|
2443
|
+
return uriOrder !== 0 ? uriOrder : left.name.localeCompare(right.name);
|
|
2444
|
+
}
|
|
2445
|
+
});
|
|
2446
|
+
});
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
2449
|
+
if (Object.is(requestSchema, ListResourceTemplatesRequestSchema)) {
|
|
2450
|
+
setRequestHandler(ListResourceTemplatesRequestSchema, async (request, extra) => {
|
|
2451
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resourceTemplates", {
|
|
2452
|
+
kind: "mcp.protocol/resource-templates-list",
|
|
2453
|
+
scope,
|
|
2454
|
+
cursor: request.params?.cursor,
|
|
2455
|
+
compare: (left, right) => {
|
|
2456
|
+
const uriOrder = left.uriTemplate.localeCompare(right.uriTemplate);
|
|
2457
|
+
return uriOrder !== 0 ? uriOrder : left.name.localeCompare(right.name);
|
|
2458
|
+
}
|
|
2459
|
+
});
|
|
2460
|
+
});
|
|
2461
|
+
return;
|
|
2462
|
+
}
|
|
2463
|
+
if (Object.is(requestSchema, ListToolsRequestSchema)) {
|
|
2464
|
+
setRequestHandler(ListToolsRequestSchema, async (request, extra) => {
|
|
2465
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "tools", {
|
|
2466
|
+
kind: "mcp.protocol/tools-list",
|
|
2467
|
+
scope,
|
|
2468
|
+
cursor: request.params?.cursor,
|
|
2469
|
+
compare: (left, right) => left.name.localeCompare(right.name)
|
|
2470
|
+
});
|
|
2471
|
+
});
|
|
2472
|
+
return;
|
|
2473
|
+
}
|
|
2474
|
+
if (Object.is(requestSchema, ListPromptsRequestSchema)) {
|
|
2475
|
+
setRequestHandler(ListPromptsRequestSchema, async (request, extra) => {
|
|
2476
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "prompts", {
|
|
2477
|
+
kind: "mcp.protocol/prompts-list",
|
|
2478
|
+
scope,
|
|
2479
|
+
cursor: request.params?.cursor,
|
|
2480
|
+
compare: (left, right) => left.name.localeCompare(right.name)
|
|
2481
|
+
});
|
|
2482
|
+
});
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
setRequestHandler(requestSchema, handler);
|
|
2486
|
+
});
|
|
2487
|
+
server.server.setRequestHandler = interceptedSetRequestHandler;
|
|
2488
|
+
return () => {
|
|
2489
|
+
if (server.server.setRequestHandler === interceptedSetRequestHandler) server.server.setRequestHandler = originalSetRequestHandler;
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
2492
|
+
function installDocsMcpSdkRegistrationPagination(server, scope) {
|
|
2493
|
+
const wrapRegistration = (registration) => new Proxy(registration, { apply(target, thisArg, argArray) {
|
|
2494
|
+
const restore = installDocsMcpSdkListPaginationInterceptor(server, scope);
|
|
2495
|
+
try {
|
|
2496
|
+
return Reflect.apply(target, thisArg, argArray);
|
|
2497
|
+
} finally {
|
|
2498
|
+
restore();
|
|
2499
|
+
}
|
|
2500
|
+
} });
|
|
2501
|
+
server.registerTool = wrapRegistration(server.registerTool);
|
|
2502
|
+
server.tool = wrapRegistration(server.tool);
|
|
2503
|
+
server.registerResource = wrapRegistration(server.registerResource);
|
|
2504
|
+
server.resource = wrapRegistration(server.resource);
|
|
2505
|
+
server.registerPrompt = wrapRegistration(server.registerPrompt);
|
|
2506
|
+
server.prompt = wrapRegistration(server.prompt);
|
|
2507
|
+
}
|
|
2266
2508
|
async function createDocsMcpServer(options) {
|
|
2267
2509
|
const resolved = resolveDocsMcpConfig(options.mcp, {
|
|
2268
2510
|
defaultName: options.defaultName ?? options.source.siteTitle ?? DEFAULT_MCP_NAME,
|
|
2269
2511
|
defaultVersion: options.defaultVersion
|
|
2270
2512
|
});
|
|
2271
2513
|
const toolSearchConfig = resolveMcpToolSearchConfig(options.search, resolved.route);
|
|
2514
|
+
const protocolScope = stableDocsMcpPaginationScope({
|
|
2515
|
+
name: resolved.name,
|
|
2516
|
+
version: resolved.version
|
|
2517
|
+
});
|
|
2272
2518
|
const server = new McpServer({
|
|
2273
2519
|
name: resolved.name,
|
|
2274
2520
|
version: resolved.version
|
|
2275
2521
|
});
|
|
2522
|
+
installDocsMcpSdkRegistrationPagination(server, protocolScope);
|
|
2523
|
+
const registerResource = (name, uri, metadata, callback) => {
|
|
2524
|
+
return server.registerResource(name, uri, metadata, callback);
|
|
2525
|
+
};
|
|
2526
|
+
const registerTool = (name, config, callback) => {
|
|
2527
|
+
return server.registerTool(name, config, callback);
|
|
2528
|
+
};
|
|
2276
2529
|
const telemetryConfig = {
|
|
2277
2530
|
telemetry: options.telemetry,
|
|
2278
2531
|
mcp: options.mcp,
|
|
@@ -2303,7 +2556,7 @@ async function createDocsMcpServer(options) {
|
|
|
2303
2556
|
const defaultPages = dedupePages(await getSourcePages());
|
|
2304
2557
|
const defaultTree = await getSourceNavigation();
|
|
2305
2558
|
const defaultSkills = await getSourceSkills();
|
|
2306
|
-
|
|
2559
|
+
registerResource("docs-navigation", "docs://navigation", {
|
|
2307
2560
|
title: "Docs Navigation",
|
|
2308
2561
|
description: "Structured navigation tree for the documentation site.",
|
|
2309
2562
|
mimeType: "text/plain"
|
|
@@ -2314,7 +2567,7 @@ async function createDocsMcpServer(options) {
|
|
|
2314
2567
|
}] }));
|
|
2315
2568
|
for (const page of defaultPages) {
|
|
2316
2569
|
const resourceUri = toPageResourceUri(page.url);
|
|
2317
|
-
|
|
2570
|
+
registerResource(`page-${slugToKey(page.slug)}`, resourceUri, {
|
|
2318
2571
|
title: page.title,
|
|
2319
2572
|
description: page.description,
|
|
2320
2573
|
mimeType: "text/markdown"
|
|
@@ -2327,7 +2580,7 @@ async function createDocsMcpServer(options) {
|
|
|
2327
2580
|
for (const skill of defaultSkills) for (const file of skill.files) {
|
|
2328
2581
|
const encodedPath = file.path.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
2329
2582
|
const resourceUri = `docs://skills/${encodeURIComponent(skill.name)}/${encodedPath}`;
|
|
2330
|
-
|
|
2583
|
+
registerResource(`skill-${encodeURIComponent(skill.name)}-${Buffer.from(file.path).toString("base64url")}`, resourceUri, {
|
|
2331
2584
|
title: `${skill.name}: ${file.path}`,
|
|
2332
2585
|
description: `${skill.description} (${file.digest})`,
|
|
2333
2586
|
mimeType: file.mediaType
|
|
@@ -2341,14 +2594,15 @@ async function createDocsMcpServer(options) {
|
|
|
2341
2594
|
blob: Buffer.from(file.content).toString("base64")
|
|
2342
2595
|
}] }));
|
|
2343
2596
|
}
|
|
2344
|
-
if (resolved.tools.listPages)
|
|
2597
|
+
if (resolved.tools.listPages) registerTool("list_pages", {
|
|
2345
2598
|
title: "List docs pages",
|
|
2346
2599
|
description: "List the known documentation pages with titles, slugs, and URLs.",
|
|
2347
2600
|
inputSchema: listPagesInputSchema,
|
|
2348
2601
|
outputSchema: listPagesOutputSchema,
|
|
2349
2602
|
annotations: { readOnlyHint: true }
|
|
2350
|
-
}, async ({ locale }) => {
|
|
2603
|
+
}, async ({ locale, cursor }) => {
|
|
2351
2604
|
const startedAt = nowMs();
|
|
2605
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2352
2606
|
const trace = createDocsAgentTraceContext("mcp.tool.list_pages");
|
|
2353
2607
|
const callSpanId = createDocsAgentTraceId("span");
|
|
2354
2608
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2360,11 +2614,25 @@ async function createDocsMcpServer(options) {
|
|
|
2360
2614
|
startedAt: trace.startedAt,
|
|
2361
2615
|
status: "started",
|
|
2362
2616
|
locale,
|
|
2363
|
-
inputPreview: {
|
|
2617
|
+
inputPreview: {
|
|
2618
|
+
locale,
|
|
2619
|
+
hasCursor: cursor !== void 0
|
|
2620
|
+
},
|
|
2364
2621
|
metadata: { tool: "list_pages" }
|
|
2365
2622
|
});
|
|
2366
2623
|
try {
|
|
2367
|
-
const
|
|
2624
|
+
const page = paginateDocsMcpItems(toPageSummaries(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext))).sort(compareDocsMcpPageSummaries), {
|
|
2625
|
+
kind: "mcp.tool/list_pages",
|
|
2626
|
+
scope: stableDocsMcpPaginationScope({ locale: resolvedLocale ?? null }),
|
|
2627
|
+
cursor
|
|
2628
|
+
});
|
|
2629
|
+
const result = {
|
|
2630
|
+
resultCount: page.resultCount,
|
|
2631
|
+
total: page.total,
|
|
2632
|
+
hasMore: page.hasMore,
|
|
2633
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
2634
|
+
pages: page.items
|
|
2635
|
+
};
|
|
2368
2636
|
const elapsed = durationMs(startedAt);
|
|
2369
2637
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
2370
2638
|
type: "mcp_tool",
|
|
@@ -2372,13 +2640,15 @@ async function createDocsMcpServer(options) {
|
|
|
2372
2640
|
locale,
|
|
2373
2641
|
properties: {
|
|
2374
2642
|
tool: "list_pages",
|
|
2375
|
-
resultCount:
|
|
2643
|
+
resultCount: page.resultCount,
|
|
2644
|
+
total: page.total,
|
|
2645
|
+
hasMore: page.hasMore,
|
|
2376
2646
|
durationMs: elapsed
|
|
2377
2647
|
}
|
|
2378
2648
|
});
|
|
2379
2649
|
trackMcpTool("list_pages", {
|
|
2380
2650
|
locale,
|
|
2381
|
-
resultCount:
|
|
2651
|
+
resultCount: page.resultCount
|
|
2382
2652
|
});
|
|
2383
2653
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
2384
2654
|
type: "tool.result",
|
|
@@ -2391,10 +2661,14 @@ async function createDocsMcpServer(options) {
|
|
|
2391
2661
|
durationMs: elapsed,
|
|
2392
2662
|
status: "success",
|
|
2393
2663
|
locale,
|
|
2394
|
-
outputPreview: {
|
|
2664
|
+
outputPreview: {
|
|
2665
|
+
resultCount: page.resultCount,
|
|
2666
|
+
total: page.total,
|
|
2667
|
+
hasMore: page.hasMore
|
|
2668
|
+
},
|
|
2395
2669
|
metadata: { tool: "list_pages" }
|
|
2396
2670
|
});
|
|
2397
|
-
return createStructuredTextResult(
|
|
2671
|
+
return createStructuredTextResult(result);
|
|
2398
2672
|
} catch (error) {
|
|
2399
2673
|
const elapsed = durationMs(startedAt);
|
|
2400
2674
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2414,14 +2688,15 @@ async function createDocsMcpServer(options) {
|
|
|
2414
2688
|
throw error;
|
|
2415
2689
|
}
|
|
2416
2690
|
});
|
|
2417
|
-
if (resolved.tools.listDocs)
|
|
2691
|
+
if (resolved.tools.listDocs) registerTool("list_docs", {
|
|
2418
2692
|
title: "List docs by section",
|
|
2419
2693
|
description: "List documentation pages grouped by section, optionally narrowed to one section.",
|
|
2420
2694
|
inputSchema: listDocsInputSchema,
|
|
2421
2695
|
outputSchema: listDocsOutputSchema,
|
|
2422
2696
|
annotations: { readOnlyHint: true }
|
|
2423
|
-
}, async ({ section, locale }) => {
|
|
2697
|
+
}, async ({ section, locale, cursor }) => {
|
|
2424
2698
|
const startedAt = nowMs();
|
|
2699
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2425
2700
|
const trace = createDocsAgentTraceContext("mcp.tool.list_docs");
|
|
2426
2701
|
const callSpanId = createDocsAgentTraceId("span");
|
|
2427
2702
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2435,14 +2710,21 @@ async function createDocsMcpServer(options) {
|
|
|
2435
2710
|
locale,
|
|
2436
2711
|
inputPreview: {
|
|
2437
2712
|
section,
|
|
2438
|
-
locale
|
|
2713
|
+
locale,
|
|
2714
|
+
hasCursor: cursor !== void 0
|
|
2439
2715
|
},
|
|
2440
2716
|
metadata: { tool: "list_docs" }
|
|
2441
2717
|
});
|
|
2442
2718
|
try {
|
|
2443
|
-
const docs = listDocsBySection(dedupePages(await
|
|
2719
|
+
const docs = paginateDocsMcpDocsList(listDocsBySection(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext)), {
|
|
2444
2720
|
section,
|
|
2445
2721
|
entry: options.source.entry
|
|
2722
|
+
}), {
|
|
2723
|
+
cursor,
|
|
2724
|
+
scope: stableDocsMcpPaginationScope({
|
|
2725
|
+
locale: resolvedLocale ?? null,
|
|
2726
|
+
section: normalizeDocsListMatchValue(section ?? "")
|
|
2727
|
+
})
|
|
2446
2728
|
});
|
|
2447
2729
|
const elapsed = durationMs(startedAt);
|
|
2448
2730
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
@@ -2453,6 +2735,8 @@ async function createDocsMcpServer(options) {
|
|
|
2453
2735
|
tool: "list_docs",
|
|
2454
2736
|
section,
|
|
2455
2737
|
resultCount: docs.resultCount,
|
|
2738
|
+
total: docs.total,
|
|
2739
|
+
hasMore: docs.hasMore,
|
|
2456
2740
|
sectionCount: docs.sectionCount,
|
|
2457
2741
|
durationMs: elapsed
|
|
2458
2742
|
}
|
|
@@ -2474,6 +2758,8 @@ async function createDocsMcpServer(options) {
|
|
|
2474
2758
|
locale,
|
|
2475
2759
|
outputPreview: {
|
|
2476
2760
|
resultCount: docs.resultCount,
|
|
2761
|
+
total: docs.total,
|
|
2762
|
+
hasMore: docs.hasMore,
|
|
2477
2763
|
sectionCount: docs.sectionCount
|
|
2478
2764
|
},
|
|
2479
2765
|
metadata: { tool: "list_docs" }
|
|
@@ -2498,14 +2784,15 @@ async function createDocsMcpServer(options) {
|
|
|
2498
2784
|
throw error;
|
|
2499
2785
|
}
|
|
2500
2786
|
});
|
|
2501
|
-
if (resolved.tools.listTasks)
|
|
2787
|
+
if (resolved.tools.listTasks) registerTool("list_tasks", {
|
|
2502
2788
|
title: "List documented tasks",
|
|
2503
2789
|
description: "List pages with actionable agent contracts, optionally filtered by text or applicability.",
|
|
2504
2790
|
inputSchema: listTasksInputSchema,
|
|
2505
2791
|
outputSchema: listTasksOutputSchema,
|
|
2506
2792
|
annotations: { readOnlyHint: true }
|
|
2507
|
-
}, async ({ query, framework, version, package: packageName, locale }) => {
|
|
2793
|
+
}, async ({ query, framework, version, package: packageName, locale, cursor }) => {
|
|
2508
2794
|
const startedAt = nowMs();
|
|
2795
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2509
2796
|
const trace = createDocsAgentTraceContext("mcp.tool.list_tasks");
|
|
2510
2797
|
const callSpanId = createDocsAgentTraceId("span");
|
|
2511
2798
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2521,20 +2808,34 @@ async function createDocsMcpServer(options) {
|
|
|
2521
2808
|
queryLength: query?.length,
|
|
2522
2809
|
framework,
|
|
2523
2810
|
version,
|
|
2524
|
-
package: packageName
|
|
2811
|
+
package: packageName,
|
|
2812
|
+
hasCursor: cursor !== void 0
|
|
2525
2813
|
},
|
|
2526
2814
|
metadata: { tool: "list_tasks" }
|
|
2527
2815
|
});
|
|
2528
2816
|
try {
|
|
2529
|
-
const
|
|
2817
|
+
const page = paginateDocsMcpItems(listDocsTasks(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext)), {
|
|
2530
2818
|
query,
|
|
2531
2819
|
framework,
|
|
2532
2820
|
version,
|
|
2533
2821
|
package: packageName
|
|
2822
|
+
}).sort(compareDocsMcpTaskSummaries), {
|
|
2823
|
+
kind: "mcp.tool/list_tasks",
|
|
2824
|
+
scope: stableDocsMcpPaginationScope({
|
|
2825
|
+
locale: resolvedLocale ?? null,
|
|
2826
|
+
query: query?.trim().toLowerCase() ?? null,
|
|
2827
|
+
framework: framework?.trim().toLowerCase() ?? null,
|
|
2828
|
+
version: version?.trim().toLowerCase() ?? null,
|
|
2829
|
+
package: packageName?.trim().toLowerCase() ?? null
|
|
2830
|
+
}),
|
|
2831
|
+
cursor
|
|
2534
2832
|
});
|
|
2535
2833
|
const result = {
|
|
2536
|
-
resultCount:
|
|
2537
|
-
|
|
2834
|
+
resultCount: page.resultCount,
|
|
2835
|
+
total: page.total,
|
|
2836
|
+
hasMore: page.hasMore,
|
|
2837
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
2838
|
+
tasks: page.items
|
|
2538
2839
|
};
|
|
2539
2840
|
const elapsed = durationMs(startedAt);
|
|
2540
2841
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
@@ -2547,13 +2848,15 @@ async function createDocsMcpServer(options) {
|
|
|
2547
2848
|
framework,
|
|
2548
2849
|
version,
|
|
2549
2850
|
package: packageName,
|
|
2550
|
-
resultCount:
|
|
2851
|
+
resultCount: page.resultCount,
|
|
2852
|
+
total: page.total,
|
|
2853
|
+
hasMore: page.hasMore,
|
|
2551
2854
|
durationMs: elapsed
|
|
2552
2855
|
}
|
|
2553
2856
|
});
|
|
2554
2857
|
trackMcpTool("list_tasks", {
|
|
2555
2858
|
locale,
|
|
2556
|
-
resultCount:
|
|
2859
|
+
resultCount: page.resultCount
|
|
2557
2860
|
});
|
|
2558
2861
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
2559
2862
|
type: "tool.result",
|
|
@@ -2566,7 +2869,11 @@ async function createDocsMcpServer(options) {
|
|
|
2566
2869
|
durationMs: elapsed,
|
|
2567
2870
|
status: "success",
|
|
2568
2871
|
locale,
|
|
2569
|
-
outputPreview: {
|
|
2872
|
+
outputPreview: {
|
|
2873
|
+
resultCount: page.resultCount,
|
|
2874
|
+
total: page.total,
|
|
2875
|
+
hasMore: page.hasMore
|
|
2876
|
+
},
|
|
2570
2877
|
metadata: { tool: "list_tasks" }
|
|
2571
2878
|
});
|
|
2572
2879
|
return {
|
|
@@ -2595,7 +2902,7 @@ async function createDocsMcpServer(options) {
|
|
|
2595
2902
|
throw error;
|
|
2596
2903
|
}
|
|
2597
2904
|
});
|
|
2598
|
-
if (resolved.tools.readTask)
|
|
2905
|
+
if (resolved.tools.readTask) registerTool("read_task", {
|
|
2599
2906
|
title: "Read a documented task",
|
|
2600
2907
|
description: "Read the full structured agent contract for a page by slug or URL path.",
|
|
2601
2908
|
inputSchema: readTaskInputSchema,
|
|
@@ -2744,7 +3051,7 @@ async function createDocsMcpServer(options) {
|
|
|
2744
3051
|
throw error;
|
|
2745
3052
|
}
|
|
2746
3053
|
});
|
|
2747
|
-
if (resolved.tools.getNavigation)
|
|
3054
|
+
if (resolved.tools.getNavigation) registerTool("get_navigation", {
|
|
2748
3055
|
title: "Get docs navigation",
|
|
2749
3056
|
description: "Return the documentation navigation tree for the current docs site.",
|
|
2750
3057
|
inputSchema: getNavigationInputSchema,
|
|
@@ -2817,7 +3124,7 @@ async function createDocsMcpServer(options) {
|
|
|
2817
3124
|
throw error;
|
|
2818
3125
|
}
|
|
2819
3126
|
});
|
|
2820
|
-
if (resolved.tools.getConfigSchema)
|
|
3127
|
+
if (resolved.tools.getConfigSchema) registerTool("get_config_schema", {
|
|
2821
3128
|
title: "Get docs config schema",
|
|
2822
3129
|
description: "Return structured docs.config.ts option metadata, optionally filtered by option path or query.",
|
|
2823
3130
|
inputSchema: getConfigSchemaInputSchema,
|
|
@@ -2892,13 +3199,119 @@ async function createDocsMcpServer(options) {
|
|
|
2892
3199
|
throw error;
|
|
2893
3200
|
}
|
|
2894
3201
|
});
|
|
2895
|
-
if (resolved.tools.
|
|
3202
|
+
if (resolved.tools.searchFacets) registerTool("list_search_facets", {
|
|
3203
|
+
title: "List documentation search facets",
|
|
3204
|
+
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.",
|
|
3205
|
+
inputSchema: searchFacetsInputSchema,
|
|
3206
|
+
outputSchema: searchFacetsOutputSchema,
|
|
3207
|
+
annotations: { readOnlyHint: true }
|
|
3208
|
+
}, async ({ locale, audience, facet, limit, cursor, framework, version, package: packageName, tags }) => {
|
|
3209
|
+
const startedAt = nowMs();
|
|
3210
|
+
const resolvedAudience = audience ?? "agent";
|
|
3211
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
3212
|
+
const filters = {
|
|
3213
|
+
framework,
|
|
3214
|
+
version,
|
|
3215
|
+
package: packageName,
|
|
3216
|
+
tags
|
|
3217
|
+
};
|
|
3218
|
+
const trace = createDocsAgentTraceContext("mcp.tool.list_search_facets");
|
|
3219
|
+
const callSpanId = createDocsAgentTraceId("span");
|
|
3220
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3221
|
+
type: "tool.call",
|
|
3222
|
+
source: "mcp",
|
|
3223
|
+
traceId: trace.traceId,
|
|
3224
|
+
spanId: callSpanId,
|
|
3225
|
+
name: "list_search_facets",
|
|
3226
|
+
startedAt: trace.startedAt,
|
|
3227
|
+
status: "started",
|
|
3228
|
+
locale,
|
|
3229
|
+
inputPreview: {
|
|
3230
|
+
locale,
|
|
3231
|
+
audience: resolvedAudience,
|
|
3232
|
+
facet,
|
|
3233
|
+
limit,
|
|
3234
|
+
hasCursor: cursor !== void 0,
|
|
3235
|
+
filterFields: Object.entries(filters).filter(([, value]) => value !== void 0).map(([field]) => field)
|
|
3236
|
+
},
|
|
3237
|
+
metadata: { tool: "list_search_facets" }
|
|
3238
|
+
});
|
|
3239
|
+
try {
|
|
3240
|
+
const facets = await buildDocsSearchFacets({
|
|
3241
|
+
pages: toSearchSourcePages(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext))),
|
|
3242
|
+
search: toolSearchConfig ?? true,
|
|
3243
|
+
audience: resolvedAudience,
|
|
3244
|
+
filters,
|
|
3245
|
+
facet,
|
|
3246
|
+
limit,
|
|
3247
|
+
cursor,
|
|
3248
|
+
locale: resolvedLocale,
|
|
3249
|
+
baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0)
|
|
3250
|
+
});
|
|
3251
|
+
const elapsed = durationMs(startedAt);
|
|
3252
|
+
await emitDocsAnalyticsEvent(options.analytics, {
|
|
3253
|
+
type: "mcp_tool",
|
|
3254
|
+
source: "mcp",
|
|
3255
|
+
locale,
|
|
3256
|
+
properties: {
|
|
3257
|
+
tool: "list_search_facets",
|
|
3258
|
+
audience: resolvedAudience,
|
|
3259
|
+
matchedPageCount: facets.matchedPageCount,
|
|
3260
|
+
frameworkCount: facets.facets.framework.valueCount,
|
|
3261
|
+
versionCount: facets.facets.version.valueCount,
|
|
3262
|
+
packageCount: facets.facets.package.valueCount,
|
|
3263
|
+
tagCount: facets.facets.tags.valueCount,
|
|
3264
|
+
durationMs: elapsed
|
|
3265
|
+
}
|
|
3266
|
+
});
|
|
3267
|
+
trackMcpTool("list_search_facets", {
|
|
3268
|
+
locale,
|
|
3269
|
+
resultCount: facets.matchedPageCount
|
|
3270
|
+
});
|
|
3271
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3272
|
+
type: "tool.result",
|
|
3273
|
+
source: "mcp",
|
|
3274
|
+
traceId: trace.traceId,
|
|
3275
|
+
parentSpanId: callSpanId,
|
|
3276
|
+
name: "list_search_facets",
|
|
3277
|
+
startedAt: trace.startedAt,
|
|
3278
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3279
|
+
durationMs: elapsed,
|
|
3280
|
+
status: "success",
|
|
3281
|
+
locale,
|
|
3282
|
+
outputPreview: {
|
|
3283
|
+
matchedPageCount: facets.matchedPageCount,
|
|
3284
|
+
facetValueCount: Object.values(facets.facets).reduce((total, facet) => total + facet.valueCount, 0)
|
|
3285
|
+
},
|
|
3286
|
+
metadata: { tool: "list_search_facets" }
|
|
3287
|
+
});
|
|
3288
|
+
return createStructuredTextResult(facets);
|
|
3289
|
+
} catch (error) {
|
|
3290
|
+
const elapsed = durationMs(startedAt);
|
|
3291
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3292
|
+
type: "tool.error",
|
|
3293
|
+
source: "mcp",
|
|
3294
|
+
traceId: trace.traceId,
|
|
3295
|
+
parentSpanId: callSpanId,
|
|
3296
|
+
name: "list_search_facets",
|
|
3297
|
+
startedAt: trace.startedAt,
|
|
3298
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3299
|
+
durationMs: elapsed,
|
|
3300
|
+
status: "error",
|
|
3301
|
+
locale,
|
|
3302
|
+
outputPreview: { message: error instanceof Error ? error.message : "Unknown error" },
|
|
3303
|
+
metadata: { tool: "list_search_facets" }
|
|
3304
|
+
});
|
|
3305
|
+
throw error;
|
|
3306
|
+
}
|
|
3307
|
+
});
|
|
3308
|
+
if (resolved.tools.searchDocs) registerTool("search_docs", {
|
|
2896
3309
|
title: "Search documentation",
|
|
2897
3310
|
description: "Search the docs by keyword with optional framework, version, package, and tag filters. Returns structured ambiguity and metadata warnings.",
|
|
2898
3311
|
inputSchema: searchDocsInputSchema,
|
|
2899
3312
|
outputSchema: searchDocsOutputSchema,
|
|
2900
3313
|
annotations: { readOnlyHint: true }
|
|
2901
|
-
}, async ({ query, limit, locale, audience, framework, version, package: packageName, tags }) => {
|
|
3314
|
+
}, async ({ query, limit, cursor, locale, audience, framework, version, package: packageName, tags }) => {
|
|
2902
3315
|
const startedAt = nowMs();
|
|
2903
3316
|
const resolvedLimit = limit ?? 10;
|
|
2904
3317
|
const resolvedAudience = audience ?? "agent";
|
|
@@ -2923,6 +3336,7 @@ async function createDocsMcpServer(options) {
|
|
|
2923
3336
|
inputPreview: {
|
|
2924
3337
|
queryLength: query.length,
|
|
2925
3338
|
limit: resolvedLimit,
|
|
3339
|
+
hasCursor: cursor !== void 0,
|
|
2926
3340
|
locale,
|
|
2927
3341
|
audience: resolvedAudience,
|
|
2928
3342
|
filterFields: Object.entries(filters).filter(([, value]) => value !== void 0).map(([field]) => field)
|
|
@@ -2940,7 +3354,8 @@ async function createDocsMcpServer(options) {
|
|
|
2940
3354
|
siteTitle: options.source.siteTitle,
|
|
2941
3355
|
baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0),
|
|
2942
3356
|
syncBaseUrl: options.source.baseUrl ?? null,
|
|
2943
|
-
limit: resolvedLimit
|
|
3357
|
+
limit: resolvedLimit,
|
|
3358
|
+
cursor
|
|
2944
3359
|
});
|
|
2945
3360
|
const elapsed = durationMs(startedAt);
|
|
2946
3361
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
@@ -2954,6 +3369,8 @@ async function createDocsMcpServer(options) {
|
|
|
2954
3369
|
limit: resolvedLimit,
|
|
2955
3370
|
audience: resolvedAudience,
|
|
2956
3371
|
resultCount: searchResponse.resultCount,
|
|
3372
|
+
total: searchResponse.total,
|
|
3373
|
+
hasMore: searchResponse.hasMore,
|
|
2957
3374
|
warningCount: searchResponse.warnings.length,
|
|
2958
3375
|
durationMs: elapsed
|
|
2959
3376
|
}
|
|
@@ -2975,6 +3392,8 @@ async function createDocsMcpServer(options) {
|
|
|
2975
3392
|
locale,
|
|
2976
3393
|
outputPreview: {
|
|
2977
3394
|
resultCount: searchResponse.resultCount,
|
|
3395
|
+
total: searchResponse.total,
|
|
3396
|
+
hasMore: searchResponse.hasMore,
|
|
2978
3397
|
warningCount: searchResponse.warnings.length
|
|
2979
3398
|
},
|
|
2980
3399
|
metadata: { tool: "search_docs" }
|
|
@@ -2999,7 +3418,7 @@ async function createDocsMcpServer(options) {
|
|
|
2999
3418
|
throw error;
|
|
3000
3419
|
}
|
|
3001
3420
|
});
|
|
3002
|
-
if (resolved.tools.getCodeExamples)
|
|
3421
|
+
if (resolved.tools.getCodeExamples) registerTool("get_code_examples", {
|
|
3003
3422
|
title: "Get docs code examples",
|
|
3004
3423
|
description: "Return fenced code examples from the docs with parsed metadata such as title, framework, packageManager, and runnable.",
|
|
3005
3424
|
inputSchema: getCodeExamplesInputSchema,
|
|
@@ -3098,7 +3517,7 @@ async function createDocsMcpServer(options) {
|
|
|
3098
3517
|
throw error;
|
|
3099
3518
|
}
|
|
3100
3519
|
});
|
|
3101
|
-
if (resolved.tools.getContext)
|
|
3520
|
+
if (resolved.tools.getContext) registerTool("get_context", {
|
|
3102
3521
|
title: "Get budgeted docs context",
|
|
3103
3522
|
description: "Build deterministic, section-level documentation context for a query within a conservative UTF-8 byte ceiling derived from the requested token budget, with source URLs and accounting metadata.",
|
|
3104
3523
|
inputSchema: getContextInputSchema,
|
|
@@ -3208,13 +3627,13 @@ async function createDocsMcpServer(options) {
|
|
|
3208
3627
|
throw error;
|
|
3209
3628
|
}
|
|
3210
3629
|
});
|
|
3211
|
-
if (resolved.tools.listPageSections !== false)
|
|
3630
|
+
if (resolved.tools.listPageSections !== false) registerTool("list_page_sections", {
|
|
3212
3631
|
title: "List sections in a docs page",
|
|
3213
3632
|
description: "Discover a page's canonical headings, anchors, hierarchy, line ranges, size estimates, and budget-aware fetch URLs without returning the page body.",
|
|
3214
3633
|
inputSchema: listPageSectionsInputSchema,
|
|
3215
3634
|
outputSchema: pageSectionIndexOutputSchema,
|
|
3216
3635
|
annotations: { readOnlyHint: true }
|
|
3217
|
-
}, async ({ path: requestedPath, locale, tokenBudget, byteBudget }) => {
|
|
3636
|
+
}, async ({ path: requestedPath, locale, tokenBudget, byteBudget, cursor }) => {
|
|
3218
3637
|
const startedAt = nowMs();
|
|
3219
3638
|
const resolvedLocale = resolveSourceLocale(locale);
|
|
3220
3639
|
const trace = createDocsAgentTraceContext("mcp.tool.list_page_sections");
|
|
@@ -3233,7 +3652,8 @@ async function createDocsMcpServer(options) {
|
|
|
3233
3652
|
locale,
|
|
3234
3653
|
resolvedLocale,
|
|
3235
3654
|
tokenBudget,
|
|
3236
|
-
byteBudget
|
|
3655
|
+
byteBudget,
|
|
3656
|
+
hasCursor: cursor !== void 0
|
|
3237
3657
|
},
|
|
3238
3658
|
metadata: { tool: "list_page_sections" }
|
|
3239
3659
|
});
|
|
@@ -3286,12 +3706,31 @@ async function createDocsMcpServer(options) {
|
|
|
3286
3706
|
}
|
|
3287
3707
|
const document = upsertPageAgentContractMarkdown(getDocsMcpSourceMarkdown(page), page.agent);
|
|
3288
3708
|
const publicBaseUrl = options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0);
|
|
3289
|
-
const
|
|
3709
|
+
const completeSectionIndex = buildDocsMarkdownSectionIndex(document, {
|
|
3290
3710
|
canonicalUrl: resolveDocsMcpPublicUrl(withDocsMcpUrlLocale(page.url, resolvedLocale), publicBaseUrl),
|
|
3291
3711
|
markdownUrl: resolveDocsMcpPublicUrl(toDocsMcpPageMarkdownUrl(page.url, resolvedLocale), publicBaseUrl),
|
|
3292
3712
|
tokenBudget,
|
|
3293
3713
|
byteBudget
|
|
3294
3714
|
});
|
|
3715
|
+
const sectionPage = paginateDocsMcpItems(completeSectionIndex.sections, {
|
|
3716
|
+
kind: "mcp.tool/list_page_sections",
|
|
3717
|
+
scope: stableDocsMcpPaginationScope({
|
|
3718
|
+
path: page.url,
|
|
3719
|
+
locale: resolvedLocale ?? null,
|
|
3720
|
+
tokenBudget: tokenBudget ?? null,
|
|
3721
|
+
byteBudget: byteBudget ?? null
|
|
3722
|
+
}),
|
|
3723
|
+
cursor
|
|
3724
|
+
});
|
|
3725
|
+
const sectionIndex = {
|
|
3726
|
+
...completeSectionIndex,
|
|
3727
|
+
sectionCount: completeSectionIndex.sectionCount,
|
|
3728
|
+
resultCount: sectionPage.resultCount,
|
|
3729
|
+
total: sectionPage.total,
|
|
3730
|
+
hasMore: sectionPage.hasMore,
|
|
3731
|
+
...sectionPage.nextCursor ? { nextCursor: sectionPage.nextCursor } : {},
|
|
3732
|
+
sections: sectionPage.items
|
|
3733
|
+
};
|
|
3295
3734
|
const elapsed = durationMs(startedAt);
|
|
3296
3735
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
3297
3736
|
type: "mcp_tool",
|
|
@@ -3304,6 +3743,8 @@ async function createDocsMcpServer(options) {
|
|
|
3304
3743
|
slug: page.slug,
|
|
3305
3744
|
found: true,
|
|
3306
3745
|
sectionCount: sectionIndex.sectionCount,
|
|
3746
|
+
total: sectionIndex.total,
|
|
3747
|
+
hasMore: sectionIndex.hasMore,
|
|
3307
3748
|
estimatedTokens: sectionIndex.estimatedTokens,
|
|
3308
3749
|
utf8Bytes: sectionIndex.utf8Bytes,
|
|
3309
3750
|
tokenBudget,
|
|
@@ -3313,7 +3754,7 @@ async function createDocsMcpServer(options) {
|
|
|
3313
3754
|
});
|
|
3314
3755
|
trackMcpTool("list_page_sections", {
|
|
3315
3756
|
locale: resolvedLocale,
|
|
3316
|
-
resultCount: sectionIndex.
|
|
3757
|
+
resultCount: sectionIndex.resultCount
|
|
3317
3758
|
});
|
|
3318
3759
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
3319
3760
|
type: "tool.result",
|
|
@@ -3331,6 +3772,8 @@ async function createDocsMcpServer(options) {
|
|
|
3331
3772
|
found: true,
|
|
3332
3773
|
slug: page.slug,
|
|
3333
3774
|
sectionCount: sectionIndex.sectionCount,
|
|
3775
|
+
total: sectionIndex.total,
|
|
3776
|
+
hasMore: sectionIndex.hasMore,
|
|
3334
3777
|
estimatedTokens: sectionIndex.estimatedTokens,
|
|
3335
3778
|
utf8Bytes: sectionIndex.utf8Bytes
|
|
3336
3779
|
},
|
|
@@ -3356,7 +3799,7 @@ async function createDocsMcpServer(options) {
|
|
|
3356
3799
|
throw error;
|
|
3357
3800
|
}
|
|
3358
3801
|
});
|
|
3359
|
-
if (resolved.tools.readPage)
|
|
3802
|
+
if (resolved.tools.readPage) registerTool("read_page", {
|
|
3360
3803
|
title: "Read a docs page",
|
|
3361
3804
|
description: "Read a documentation page by slug or URL path, optionally selecting one heading and limiting returned characters.",
|
|
3362
3805
|
inputSchema: readPageInputSchema,
|
|
@@ -4371,6 +4814,18 @@ function toDocsListPageSummary(page) {
|
|
|
4371
4814
|
lastModified: page.lastModified
|
|
4372
4815
|
};
|
|
4373
4816
|
}
|
|
4817
|
+
function compareDocsMcpPageSummaries(left, right) {
|
|
4818
|
+
const urlOrder = left.url.localeCompare(right.url);
|
|
4819
|
+
if (urlOrder !== 0) return urlOrder;
|
|
4820
|
+
const slugOrder = left.slug.localeCompare(right.slug);
|
|
4821
|
+
return slugOrder !== 0 ? slugOrder : left.title.localeCompare(right.title);
|
|
4822
|
+
}
|
|
4823
|
+
function compareDocsMcpTaskSummaries(left, right) {
|
|
4824
|
+
const urlOrder = left.url.localeCompare(right.url);
|
|
4825
|
+
if (urlOrder !== 0) return urlOrder;
|
|
4826
|
+
const slugOrder = left.slug.localeCompare(right.slug);
|
|
4827
|
+
return slugOrder !== 0 ? slugOrder : left.title.localeCompare(right.title);
|
|
4828
|
+
}
|
|
4374
4829
|
function listDocsTasks(pages, filters) {
|
|
4375
4830
|
const query = filters.query?.toLowerCase();
|
|
4376
4831
|
const applicabilityFilters = [
|
|
@@ -4412,6 +4867,8 @@ function listDocsBySection(pages, filters) {
|
|
|
4412
4867
|
const requestedSection = filters.section?.trim();
|
|
4413
4868
|
if (!requestedSection) return {
|
|
4414
4869
|
resultCount: allPages.length,
|
|
4870
|
+
total: allPages.length,
|
|
4871
|
+
hasMore: false,
|
|
4415
4872
|
sectionCount: countDocsSections(tree.sections),
|
|
4416
4873
|
pages: allPages,
|
|
4417
4874
|
rootPages: tree.rootPages,
|
|
@@ -4424,6 +4881,8 @@ function listDocsBySection(pages, filters) {
|
|
|
4424
4881
|
return {
|
|
4425
4882
|
section: requestedSection,
|
|
4426
4883
|
resultCount: matchedPages.length,
|
|
4884
|
+
total: matchedPages.length,
|
|
4885
|
+
hasMore: false,
|
|
4427
4886
|
sectionCount: countDocsSections(sections),
|
|
4428
4887
|
pages: matchedPages,
|
|
4429
4888
|
rootPages: [],
|
|
@@ -4434,6 +4893,8 @@ function listDocsBySection(pages, filters) {
|
|
|
4434
4893
|
if (page) return {
|
|
4435
4894
|
section: requestedSection,
|
|
4436
4895
|
resultCount: 1,
|
|
4896
|
+
total: 1,
|
|
4897
|
+
hasMore: false,
|
|
4437
4898
|
sectionCount: 0,
|
|
4438
4899
|
pages: [page],
|
|
4439
4900
|
rootPages: [page],
|
|
@@ -4442,12 +4903,46 @@ function listDocsBySection(pages, filters) {
|
|
|
4442
4903
|
return {
|
|
4443
4904
|
section: requestedSection,
|
|
4444
4905
|
resultCount: 0,
|
|
4906
|
+
total: 0,
|
|
4907
|
+
hasMore: false,
|
|
4445
4908
|
sectionCount: 0,
|
|
4446
4909
|
pages: [],
|
|
4447
4910
|
rootPages: [],
|
|
4448
4911
|
sections: []
|
|
4449
4912
|
};
|
|
4450
4913
|
}
|
|
4914
|
+
function paginateDocsMcpDocsList(docs, options) {
|
|
4915
|
+
const page = paginateDocsMcpItems([...docs.pages].sort(compareDocsMcpPageSummaries), {
|
|
4916
|
+
kind: "mcp.tool/list_docs",
|
|
4917
|
+
scope: options.scope,
|
|
4918
|
+
cursor: options.cursor
|
|
4919
|
+
});
|
|
4920
|
+
const pageUrls = new Set(page.items.map((item) => item.url));
|
|
4921
|
+
const sections = pruneDocsMcpSections(docs.sections, pageUrls);
|
|
4922
|
+
return {
|
|
4923
|
+
...docs,
|
|
4924
|
+
resultCount: page.resultCount,
|
|
4925
|
+
total: page.total,
|
|
4926
|
+
hasMore: page.hasMore,
|
|
4927
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
4928
|
+
pages: page.items,
|
|
4929
|
+
rootPages: docs.rootPages.filter((item) => pageUrls.has(item.url)),
|
|
4930
|
+
sections,
|
|
4931
|
+
sectionCount: docs.sectionCount
|
|
4932
|
+
};
|
|
4933
|
+
}
|
|
4934
|
+
function pruneDocsMcpSections(sections, pageUrls) {
|
|
4935
|
+
return sections.flatMap((section) => {
|
|
4936
|
+
const pages = section.pages.filter((page) => pageUrls.has(page.url));
|
|
4937
|
+
const childSections = pruneDocsMcpSections(section.sections, pageUrls);
|
|
4938
|
+
if (pages.length === 0 && childSections.length === 0) return [];
|
|
4939
|
+
return [{
|
|
4940
|
+
...section,
|
|
4941
|
+
pages,
|
|
4942
|
+
sections: childSections
|
|
4943
|
+
}];
|
|
4944
|
+
});
|
|
4945
|
+
}
|
|
4451
4946
|
function buildDocsSectionTree(pages) {
|
|
4452
4947
|
const sectionSlugs = /* @__PURE__ */ new Set();
|
|
4453
4948
|
for (const page of pages) {
|