@farming-labs/docs 0.2.74 → 0.2.77
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-D0LEY2Vy.mjs → agent-D4hNGatV.mjs} +2 -2
- package/dist/agent-DRKj42ht.d.mts +938 -0
- package/dist/{agent-BJ0KXN-A.mjs → agent-SRIJ-oF8.mjs} +28 -6
- package/dist/{agent-evals-LIScgQVm.mjs → agent-evals-DmFoKy_y.mjs} +1 -1
- package/dist/{agent-export-B92pNe6g.mjs → agent-export-CM-p9_YD.mjs} +7 -7
- 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-BqvIGQb1.d.mts → agent-skills-server-CJ4D0G9P.d.mts} +2 -2
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/agent-skills-vite.mjs +2 -2
- package/dist/{agents-C228QGbp.mjs → agents-BeLDNCnE.mjs} +7 -16
- package/dist/cli/index.mjs +15 -15
- package/dist/client/react.d.mts +1 -1
- package/dist/{cloud-ask-ai-6X9pVjIY.d.mts → cloud-ask-ai-BCgHPxew.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-CgrUZ3tY.mjs → doctor-DhMVKHjp.mjs} +57 -24
- package/dist/{golden-evaluations-DTEPZeb0.mjs → golden-evaluations-VzE6juQl.mjs} +7 -3
- package/dist/index.d.mts +5 -876
- package/dist/index.mjs +6 -6
- package/dist/{mcp-YD37HlPY.mjs → mcp-CZkQJXtA.mjs} +7 -6
- package/dist/mcp.d.mts +30 -5
- package/dist/mcp.mjs +594 -69
- package/dist/{prompt-references-BIS1eXt4.mjs → prompt-references-B6L3AD98.mjs} +3 -3
- package/dist/{retrieval-digest-9Kp3uSaZ.d.mts → retrieval-digest-rponR4jM.d.mts} +24 -50
- package/dist/{review-Dbzkdl6K.mjs → review-nxoV8jIm.mjs} +5 -5
- package/dist/{robots-RbgmSvPH.mjs → robots-CgH6Stqn.mjs} +2 -2
- package/dist/{robots-DUO0r4UI.mjs → robots-CiQT8mX2.mjs} +3 -3
- package/dist/{search-hcqaEZVN.mjs → search-BTUIkhnT.mjs} +6 -6
- package/dist/{search-DIyIl-tE.mjs → search-Da2AKaFJ.mjs} +624 -122
- package/dist/server.d.mts +9 -6
- package/dist/server.mjs +7 -7
- package/dist/{sitemap-jhkS_jYx.mjs → sitemap-e0_GeCWJ.mjs} +6 -6
- package/dist/{sitemap-server-BfyBM7_V.mjs → sitemap-server-DHaxyPAd.mjs} +12 -3
- package/dist/{standards-discovery-BwL5ffGx.mjs → standards-discovery-BKlEnK_H.mjs} +32 -4
- package/dist/{standards-discovery-CdrOE-05.d.mts → standards-discovery-BbslY4id.d.mts} +34 -7
- package/dist/{types-clg5J1R4.d.mts → types-B-5Kzmkn.d.mts} +73 -1
- package/package.json +1 -1
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 { Kt as normalizeDocsRelated, an as isDocsMcpResourcePath, cn as resolveDocsMcpProtectedResourceMetadataLocation, jt as resolveDocsAudienceMdxContent, ln as resolveDocsMcpResourceLocation, nn as isDocsMcpOAuthScopeToken, on as normalizeDocsMcpAuthorizationServerUrls, qt as renderDocsRelatedMarkdownLines, rn as isDocsMcpProtectedResourceMetadataPath, sn as normalizeDocsMcpEndpointPath } from "./agent-
|
|
2
|
+
import { E as DOCS_MARKDOWN_SECTION_INDEX_FORMAT, Kt as normalizeDocsRelated, P as buildDocsMarkdownSectionIndex, an as isDocsMcpResourcePath, cn as resolveDocsMcpProtectedResourceMetadataLocation, jt as resolveDocsAudienceMdxContent, ln as resolveDocsMcpResourceLocation, nn as isDocsMcpOAuthScopeToken, on as normalizeDocsMcpAuthorizationServerUrls, qt as renderDocsRelatedMarkdownLines, rn as isDocsMcpProtectedResourceMetadataPath, sn as normalizeDocsMcpEndpointPath, wt as toDocsMarkdownUrl } from "./agent-SRIJ-oF8.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 { A as DocsPaginationCursorError, B as stripGeneratedAgentProvenance, D as normalizeAgentLocale, E as normalizeAgentFramework, G as emitDocsTelemetryAgentSurfaceEvent, H as resolvePageSidebarFolderIndexBehavior, J as emitDocsTelemetryProjectEvent, N as isDocsRetrievalCanonicalUrl, O as normalizeAgentScopeValues, T as agentVersionConstraintsOverlap, h as performDocsSearchWithMetadata, j as paginateDocsItems, m as performDocsSearch, p as normalizeDocsSearchFilters, q as emitDocsTelemetryMcpToolEvent, w as agentVersionConstraintMatches } from "./search-Da2AKaFJ.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;
|
|
@@ -1488,6 +1491,13 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
1488
1491
|
default: true,
|
|
1489
1492
|
description: "Expose the list_pages tool."
|
|
1490
1493
|
},
|
|
1494
|
+
{
|
|
1495
|
+
path: "mcp.tools.listPageSections",
|
|
1496
|
+
name: "listPageSections",
|
|
1497
|
+
type: "boolean",
|
|
1498
|
+
default: true,
|
|
1499
|
+
description: "Expose the body-free list_page_sections discovery tool for page headings, anchors, hierarchy, sizes, and follow-up fetch URLs."
|
|
1500
|
+
},
|
|
1491
1501
|
{
|
|
1492
1502
|
path: "mcp.tools.listTasks",
|
|
1493
1503
|
name: "listTasks",
|
|
@@ -1555,17 +1565,26 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
1555
1565
|
default: false,
|
|
1556
1566
|
description: "Generated API reference pages from framework route conventions or a hosted OpenAPI document.",
|
|
1557
1567
|
docs: "/docs/customization/api-reference",
|
|
1558
|
-
children: [
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1568
|
+
children: [
|
|
1569
|
+
{
|
|
1570
|
+
path: "apiReference.specUrl",
|
|
1571
|
+
name: "specUrl",
|
|
1572
|
+
type: "string",
|
|
1573
|
+
description: "Remote OpenAPI JSON URL when the backend owns the schema."
|
|
1574
|
+
},
|
|
1575
|
+
{
|
|
1576
|
+
path: "apiReference.path",
|
|
1577
|
+
name: "path",
|
|
1578
|
+
type: "string",
|
|
1579
|
+
description: "Docs route where the API reference is rendered."
|
|
1580
|
+
},
|
|
1581
|
+
{
|
|
1582
|
+
path: "apiReference.catalogTargets",
|
|
1583
|
+
name: "catalogTargets",
|
|
1584
|
+
type: "string[]",
|
|
1585
|
+
description: "Product API base URLs that the OpenAPI document describes in the RFC 9727 catalog."
|
|
1586
|
+
}
|
|
1587
|
+
]
|
|
1569
1588
|
},
|
|
1570
1589
|
{
|
|
1571
1590
|
path: "codeBlocks",
|
|
@@ -1697,9 +1716,11 @@ export default defineDocs({
|
|
|
1697
1716
|
}
|
|
1698
1717
|
]);
|
|
1699
1718
|
const searchFilterValueSchema = z.union([z.string().trim().min(1).max(128), z.array(z.string().trim().min(1).max(128)).min(1).max(16)]);
|
|
1719
|
+
const paginationCursorInputSchema = z.string().min(1).max(4096).describe("Opaque nextCursor from the preceding response page.").optional();
|
|
1700
1720
|
const searchDocsInputSchema = z.object({
|
|
1701
1721
|
query: z.string().trim().min(1),
|
|
1702
1722
|
limit: z.number().int().min(1).max(25).optional(),
|
|
1723
|
+
cursor: paginationCursorInputSchema,
|
|
1703
1724
|
locale: z.string().trim().min(1).max(128).optional(),
|
|
1704
1725
|
audience: z.enum(["human", "agent"]).optional(),
|
|
1705
1726
|
framework: searchFilterValueSchema.optional(),
|
|
@@ -1713,12 +1734,20 @@ const readPageInputSchema = z.object({
|
|
|
1713
1734
|
section: z.string().trim().min(1).optional(),
|
|
1714
1735
|
maxChars: z.number().int().min(256).max(1e6).optional()
|
|
1715
1736
|
});
|
|
1737
|
+
const listPageSectionsInputSchema = z.object({
|
|
1738
|
+
path: z.string().min(1),
|
|
1739
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1740
|
+
tokenBudget: z.number().int().min(1).max(1e6).optional(),
|
|
1741
|
+
byteBudget: z.number().int().min(1).max(1e6).optional(),
|
|
1742
|
+
cursor: paginationCursorInputSchema
|
|
1743
|
+
});
|
|
1716
1744
|
const listTasksInputSchema = z.object({
|
|
1717
1745
|
query: z.string().trim().min(1).optional(),
|
|
1718
1746
|
framework: z.string().trim().min(1).optional(),
|
|
1719
1747
|
version: z.string().trim().min(1).optional(),
|
|
1720
1748
|
package: z.string().trim().min(1).optional(),
|
|
1721
|
-
locale: z.string().trim().min(1).max(128).optional()
|
|
1749
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1750
|
+
cursor: paginationCursorInputSchema
|
|
1722
1751
|
});
|
|
1723
1752
|
const readTaskInputSchema = readPageInputSchema;
|
|
1724
1753
|
const pageAgentAppliesToOutputSchema = z.object({
|
|
@@ -1762,8 +1791,14 @@ const taskSummaryOutputSchema = z.object({
|
|
|
1762
1791
|
outcome: z.string().optional(),
|
|
1763
1792
|
appliesTo: pageAgentAppliesToOutputSchema.optional()
|
|
1764
1793
|
});
|
|
1794
|
+
const paginationOutputShape = {
|
|
1795
|
+
resultCount: z.number().int().nonnegative().describe("Items returned in this response page."),
|
|
1796
|
+
total: z.number().int().nonnegative().describe("Items in the complete filtered result set."),
|
|
1797
|
+
hasMore: z.boolean().describe("Whether another response page is available."),
|
|
1798
|
+
nextCursor: z.string().describe("Opaque cursor to pass as cursor on the next request.").optional()
|
|
1799
|
+
};
|
|
1765
1800
|
const listTasksOutputSchema = z.object({
|
|
1766
|
-
|
|
1801
|
+
...paginationOutputShape,
|
|
1767
1802
|
tasks: z.array(taskSummaryOutputSchema)
|
|
1768
1803
|
});
|
|
1769
1804
|
const readTaskOutputSchema = z.object({
|
|
@@ -1777,10 +1812,14 @@ const readTaskOutputSchema = z.object({
|
|
|
1777
1812
|
}),
|
|
1778
1813
|
contract: pageAgentContractOutputSchema
|
|
1779
1814
|
});
|
|
1780
|
-
const listPagesInputSchema = z.object({
|
|
1815
|
+
const listPagesInputSchema = z.object({
|
|
1816
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1817
|
+
cursor: paginationCursorInputSchema
|
|
1818
|
+
});
|
|
1781
1819
|
const listDocsInputSchema = z.object({
|
|
1782
1820
|
section: z.string().trim().min(1).optional(),
|
|
1783
|
-
locale: z.string().trim().min(1).max(128).optional()
|
|
1821
|
+
locale: z.string().trim().min(1).max(128).optional(),
|
|
1822
|
+
cursor: paginationCursorInputSchema
|
|
1784
1823
|
});
|
|
1785
1824
|
const getNavigationInputSchema = z.object({ locale: z.string().trim().min(1).max(128).optional() });
|
|
1786
1825
|
const getConfigSchemaInputSchema = z.object({
|
|
@@ -1833,10 +1872,13 @@ const docsSectionOutputSchema = z.lazy(() => z.object({
|
|
|
1833
1872
|
pages: z.array(pageSummaryOutputSchema),
|
|
1834
1873
|
sections: z.array(docsSectionOutputSchema)
|
|
1835
1874
|
}));
|
|
1836
|
-
const listPagesOutputSchema = z.object({
|
|
1875
|
+
const listPagesOutputSchema = z.object({
|
|
1876
|
+
...paginationOutputShape,
|
|
1877
|
+
pages: z.array(pageSummaryOutputSchema)
|
|
1878
|
+
});
|
|
1837
1879
|
const listDocsOutputSchema = z.object({
|
|
1880
|
+
...paginationOutputShape,
|
|
1838
1881
|
section: z.string().optional(),
|
|
1839
|
-
resultCount: z.number().int().nonnegative(),
|
|
1840
1882
|
sectionCount: z.number().int().nonnegative(),
|
|
1841
1883
|
pages: z.array(pageSummaryOutputSchema),
|
|
1842
1884
|
rootPages: z.array(pageSummaryOutputSchema),
|
|
@@ -1938,7 +1980,7 @@ const searchDocsOutputSchema = z.object({
|
|
|
1938
1980
|
audience: z.enum(["human", "agent"]),
|
|
1939
1981
|
filters: searchFiltersOutputSchema,
|
|
1940
1982
|
indexGeneration: retrievalSourceDigestOutputSchema,
|
|
1941
|
-
|
|
1983
|
+
...paginationOutputShape,
|
|
1942
1984
|
results: z.array(searchResultOutputSchema),
|
|
1943
1985
|
warnings: z.array(searchWarningOutputSchema)
|
|
1944
1986
|
});
|
|
@@ -2013,6 +2055,35 @@ const readPageOutputSchema = z.object({
|
|
|
2013
2055
|
totalChars: z.number().int().nonnegative(),
|
|
2014
2056
|
truncated: z.boolean()
|
|
2015
2057
|
});
|
|
2058
|
+
const pageSectionMetadataOutputSchema = z.object({
|
|
2059
|
+
id: z.string(),
|
|
2060
|
+
heading: z.string(),
|
|
2061
|
+
level: z.number().int().positive(),
|
|
2062
|
+
parentId: z.string().optional(),
|
|
2063
|
+
startLine: z.number().int().positive(),
|
|
2064
|
+
endLine: z.number().int().positive(),
|
|
2065
|
+
estimatedTokens: z.number().int().nonnegative(),
|
|
2066
|
+
utf8Bytes: z.number().int().nonnegative(),
|
|
2067
|
+
canonicalUrl: z.string(),
|
|
2068
|
+
markdownUrl: z.string()
|
|
2069
|
+
});
|
|
2070
|
+
const pageSectionIndexOutputSchema = z.object({
|
|
2071
|
+
schemaVersion: z.literal(2),
|
|
2072
|
+
format: z.literal(DOCS_MARKDOWN_SECTION_INDEX_FORMAT),
|
|
2073
|
+
canonicalUrl: z.string(),
|
|
2074
|
+
markdownUrl: z.string(),
|
|
2075
|
+
sectionIndexUrl: z.string(),
|
|
2076
|
+
lineNumbering: z.literal("body"),
|
|
2077
|
+
sectionCount: z.number().int().nonnegative(),
|
|
2078
|
+
...paginationOutputShape,
|
|
2079
|
+
estimatedTokens: z.number().int().nonnegative(),
|
|
2080
|
+
utf8Bytes: z.number().int().nonnegative(),
|
|
2081
|
+
fetchBudget: z.object({
|
|
2082
|
+
tokenBudget: z.number().int().positive().optional(),
|
|
2083
|
+
byteBudget: z.number().int().positive().optional()
|
|
2084
|
+
}).optional(),
|
|
2085
|
+
sections: z.array(pageSectionMetadataOutputSchema)
|
|
2086
|
+
});
|
|
2016
2087
|
const contextSourceOutputSchema = z.object({
|
|
2017
2088
|
id: z.string(),
|
|
2018
2089
|
title: z.string(),
|
|
@@ -2069,6 +2140,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2069
2140
|
tools: {
|
|
2070
2141
|
listDocs: true,
|
|
2071
2142
|
listPages: true,
|
|
2143
|
+
listPageSections: true,
|
|
2072
2144
|
readPage: true,
|
|
2073
2145
|
listTasks: true,
|
|
2074
2146
|
readTask: true,
|
|
@@ -2089,6 +2161,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2089
2161
|
tools: {
|
|
2090
2162
|
listDocs: config.tools?.listDocs ?? true,
|
|
2091
2163
|
listPages: config.tools?.listPages ?? true,
|
|
2164
|
+
listPageSections: config.tools?.listPageSections ?? true,
|
|
2092
2165
|
readPage: config.tools?.readPage ?? true,
|
|
2093
2166
|
listTasks: config.tools?.listTasks ?? true,
|
|
2094
2167
|
readTask: config.tools?.readTask ?? true,
|
|
@@ -2220,16 +2293,155 @@ function createStructuredTextResult(structuredContent, text) {
|
|
|
2220
2293
|
structuredContent
|
|
2221
2294
|
};
|
|
2222
2295
|
}
|
|
2296
|
+
function stableDocsMcpPaginationScope(values) {
|
|
2297
|
+
return JSON.stringify(values);
|
|
2298
|
+
}
|
|
2299
|
+
function docsMcpPaginationSnapshot(values) {
|
|
2300
|
+
return JSON.stringify(values);
|
|
2301
|
+
}
|
|
2302
|
+
function paginateDocsMcpItems(items, options) {
|
|
2303
|
+
return paginateDocsItems(items, {
|
|
2304
|
+
kind: options.kind,
|
|
2305
|
+
scope: options.scope,
|
|
2306
|
+
snapshot: docsMcpPaginationSnapshot(items),
|
|
2307
|
+
cursor: options.cursor,
|
|
2308
|
+
pageSize: options.pageSize ?? DOCS_MCP_TOOL_LIST_PAGE_SIZE
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
function paginateDocsMcpProtocolItems(items, options) {
|
|
2312
|
+
try {
|
|
2313
|
+
return paginateDocsMcpItems(items, {
|
|
2314
|
+
...options,
|
|
2315
|
+
pageSize: DOCS_MCP_PROTOCOL_LIST_PAGE_SIZE
|
|
2316
|
+
});
|
|
2317
|
+
} catch (error) {
|
|
2318
|
+
if (error instanceof DocsPaginationCursorError) throw new McpError(ErrorCode.InvalidParams, error.message);
|
|
2319
|
+
throw error;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
function toDocsMcpProtocolPaginationMeta(result) {
|
|
2323
|
+
return { [DOCS_MCP_PAGINATION_META_KEY]: {
|
|
2324
|
+
hasMore: result.hasMore,
|
|
2325
|
+
total: result.total
|
|
2326
|
+
} };
|
|
2327
|
+
}
|
|
2328
|
+
function paginateDocsMcpSdkListResult(result, field, options) {
|
|
2329
|
+
const page = paginateDocsMcpProtocolItems([...result[field]].sort(options.compare), options);
|
|
2330
|
+
return {
|
|
2331
|
+
...result,
|
|
2332
|
+
[field]: page.items,
|
|
2333
|
+
nextCursor: page.nextCursor,
|
|
2334
|
+
_meta: {
|
|
2335
|
+
...result._meta,
|
|
2336
|
+
...toDocsMcpProtocolPaginationMeta(page)
|
|
2337
|
+
}
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
/**
|
|
2341
|
+
* The MCP SDK owns the live registries and descriptor serialization. Intercepting the
|
|
2342
|
+
* handlers it installs lets pagination operate on that live output without copying private
|
|
2343
|
+
* registry state or drifting from SDK behavior when callers register, update, or disable
|
|
2344
|
+
* tools/resources after this factory returns.
|
|
2345
|
+
*/
|
|
2346
|
+
function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
2347
|
+
const originalSetRequestHandler = server.server.setRequestHandler;
|
|
2348
|
+
const setRequestHandler = originalSetRequestHandler.bind(server.server);
|
|
2349
|
+
const interceptedSetRequestHandler = ((requestSchema, handler) => {
|
|
2350
|
+
const sdkHandler = handler;
|
|
2351
|
+
if (Object.is(requestSchema, ListResourcesRequestSchema)) {
|
|
2352
|
+
setRequestHandler(ListResourcesRequestSchema, async (request, extra) => {
|
|
2353
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resources", {
|
|
2354
|
+
kind: "mcp.protocol/resources-list",
|
|
2355
|
+
scope,
|
|
2356
|
+
cursor: request.params?.cursor,
|
|
2357
|
+
compare: (left, right) => {
|
|
2358
|
+
const uriOrder = left.uri.localeCompare(right.uri);
|
|
2359
|
+
return uriOrder !== 0 ? uriOrder : left.name.localeCompare(right.name);
|
|
2360
|
+
}
|
|
2361
|
+
});
|
|
2362
|
+
});
|
|
2363
|
+
return;
|
|
2364
|
+
}
|
|
2365
|
+
if (Object.is(requestSchema, ListResourceTemplatesRequestSchema)) {
|
|
2366
|
+
setRequestHandler(ListResourceTemplatesRequestSchema, async (request, extra) => {
|
|
2367
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resourceTemplates", {
|
|
2368
|
+
kind: "mcp.protocol/resource-templates-list",
|
|
2369
|
+
scope,
|
|
2370
|
+
cursor: request.params?.cursor,
|
|
2371
|
+
compare: (left, right) => {
|
|
2372
|
+
const uriOrder = left.uriTemplate.localeCompare(right.uriTemplate);
|
|
2373
|
+
return uriOrder !== 0 ? uriOrder : left.name.localeCompare(right.name);
|
|
2374
|
+
}
|
|
2375
|
+
});
|
|
2376
|
+
});
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2379
|
+
if (Object.is(requestSchema, ListToolsRequestSchema)) {
|
|
2380
|
+
setRequestHandler(ListToolsRequestSchema, async (request, extra) => {
|
|
2381
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "tools", {
|
|
2382
|
+
kind: "mcp.protocol/tools-list",
|
|
2383
|
+
scope,
|
|
2384
|
+
cursor: request.params?.cursor,
|
|
2385
|
+
compare: (left, right) => left.name.localeCompare(right.name)
|
|
2386
|
+
});
|
|
2387
|
+
});
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
if (Object.is(requestSchema, ListPromptsRequestSchema)) {
|
|
2391
|
+
setRequestHandler(ListPromptsRequestSchema, async (request, extra) => {
|
|
2392
|
+
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "prompts", {
|
|
2393
|
+
kind: "mcp.protocol/prompts-list",
|
|
2394
|
+
scope,
|
|
2395
|
+
cursor: request.params?.cursor,
|
|
2396
|
+
compare: (left, right) => left.name.localeCompare(right.name)
|
|
2397
|
+
});
|
|
2398
|
+
});
|
|
2399
|
+
return;
|
|
2400
|
+
}
|
|
2401
|
+
setRequestHandler(requestSchema, handler);
|
|
2402
|
+
});
|
|
2403
|
+
server.server.setRequestHandler = interceptedSetRequestHandler;
|
|
2404
|
+
return () => {
|
|
2405
|
+
if (server.server.setRequestHandler === interceptedSetRequestHandler) server.server.setRequestHandler = originalSetRequestHandler;
|
|
2406
|
+
};
|
|
2407
|
+
}
|
|
2408
|
+
function installDocsMcpSdkRegistrationPagination(server, scope) {
|
|
2409
|
+
const wrapRegistration = (registration) => new Proxy(registration, { apply(target, thisArg, argArray) {
|
|
2410
|
+
const restore = installDocsMcpSdkListPaginationInterceptor(server, scope);
|
|
2411
|
+
try {
|
|
2412
|
+
return Reflect.apply(target, thisArg, argArray);
|
|
2413
|
+
} finally {
|
|
2414
|
+
restore();
|
|
2415
|
+
}
|
|
2416
|
+
} });
|
|
2417
|
+
server.registerTool = wrapRegistration(server.registerTool);
|
|
2418
|
+
server.tool = wrapRegistration(server.tool);
|
|
2419
|
+
server.registerResource = wrapRegistration(server.registerResource);
|
|
2420
|
+
server.resource = wrapRegistration(server.resource);
|
|
2421
|
+
server.registerPrompt = wrapRegistration(server.registerPrompt);
|
|
2422
|
+
server.prompt = wrapRegistration(server.prompt);
|
|
2423
|
+
}
|
|
2223
2424
|
async function createDocsMcpServer(options) {
|
|
2224
2425
|
const resolved = resolveDocsMcpConfig(options.mcp, {
|
|
2225
2426
|
defaultName: options.defaultName ?? options.source.siteTitle ?? DEFAULT_MCP_NAME,
|
|
2226
2427
|
defaultVersion: options.defaultVersion
|
|
2227
2428
|
});
|
|
2228
2429
|
const toolSearchConfig = resolveMcpToolSearchConfig(options.search, resolved.route);
|
|
2430
|
+
const protocolScope = stableDocsMcpPaginationScope({
|
|
2431
|
+
name: resolved.name,
|
|
2432
|
+
version: resolved.version
|
|
2433
|
+
});
|
|
2229
2434
|
const server = new McpServer({
|
|
2230
2435
|
name: resolved.name,
|
|
2231
2436
|
version: resolved.version
|
|
2232
2437
|
});
|
|
2438
|
+
installDocsMcpSdkRegistrationPagination(server, protocolScope);
|
|
2439
|
+
const registerResource = (name, uri, metadata, callback) => {
|
|
2440
|
+
return server.registerResource(name, uri, metadata, callback);
|
|
2441
|
+
};
|
|
2442
|
+
const registerTool = (name, config, callback) => {
|
|
2443
|
+
return server.registerTool(name, config, callback);
|
|
2444
|
+
};
|
|
2233
2445
|
const telemetryConfig = {
|
|
2234
2446
|
telemetry: options.telemetry,
|
|
2235
2447
|
mcp: options.mcp,
|
|
@@ -2260,7 +2472,7 @@ async function createDocsMcpServer(options) {
|
|
|
2260
2472
|
const defaultPages = dedupePages(await getSourcePages());
|
|
2261
2473
|
const defaultTree = await getSourceNavigation();
|
|
2262
2474
|
const defaultSkills = await getSourceSkills();
|
|
2263
|
-
|
|
2475
|
+
registerResource("docs-navigation", "docs://navigation", {
|
|
2264
2476
|
title: "Docs Navigation",
|
|
2265
2477
|
description: "Structured navigation tree for the documentation site.",
|
|
2266
2478
|
mimeType: "text/plain"
|
|
@@ -2271,7 +2483,7 @@ async function createDocsMcpServer(options) {
|
|
|
2271
2483
|
}] }));
|
|
2272
2484
|
for (const page of defaultPages) {
|
|
2273
2485
|
const resourceUri = toPageResourceUri(page.url);
|
|
2274
|
-
|
|
2486
|
+
registerResource(`page-${slugToKey(page.slug)}`, resourceUri, {
|
|
2275
2487
|
title: page.title,
|
|
2276
2488
|
description: page.description,
|
|
2277
2489
|
mimeType: "text/markdown"
|
|
@@ -2284,7 +2496,7 @@ async function createDocsMcpServer(options) {
|
|
|
2284
2496
|
for (const skill of defaultSkills) for (const file of skill.files) {
|
|
2285
2497
|
const encodedPath = file.path.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
2286
2498
|
const resourceUri = `docs://skills/${encodeURIComponent(skill.name)}/${encodedPath}`;
|
|
2287
|
-
|
|
2499
|
+
registerResource(`skill-${encodeURIComponent(skill.name)}-${Buffer.from(file.path).toString("base64url")}`, resourceUri, {
|
|
2288
2500
|
title: `${skill.name}: ${file.path}`,
|
|
2289
2501
|
description: `${skill.description} (${file.digest})`,
|
|
2290
2502
|
mimeType: file.mediaType
|
|
@@ -2298,14 +2510,15 @@ async function createDocsMcpServer(options) {
|
|
|
2298
2510
|
blob: Buffer.from(file.content).toString("base64")
|
|
2299
2511
|
}] }));
|
|
2300
2512
|
}
|
|
2301
|
-
if (resolved.tools.listPages)
|
|
2513
|
+
if (resolved.tools.listPages) registerTool("list_pages", {
|
|
2302
2514
|
title: "List docs pages",
|
|
2303
2515
|
description: "List the known documentation pages with titles, slugs, and URLs.",
|
|
2304
2516
|
inputSchema: listPagesInputSchema,
|
|
2305
2517
|
outputSchema: listPagesOutputSchema,
|
|
2306
2518
|
annotations: { readOnlyHint: true }
|
|
2307
|
-
}, async ({ locale }) => {
|
|
2519
|
+
}, async ({ locale, cursor }) => {
|
|
2308
2520
|
const startedAt = nowMs();
|
|
2521
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2309
2522
|
const trace = createDocsAgentTraceContext("mcp.tool.list_pages");
|
|
2310
2523
|
const callSpanId = createDocsAgentTraceId("span");
|
|
2311
2524
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2317,11 +2530,25 @@ async function createDocsMcpServer(options) {
|
|
|
2317
2530
|
startedAt: trace.startedAt,
|
|
2318
2531
|
status: "started",
|
|
2319
2532
|
locale,
|
|
2320
|
-
inputPreview: {
|
|
2533
|
+
inputPreview: {
|
|
2534
|
+
locale,
|
|
2535
|
+
hasCursor: cursor !== void 0
|
|
2536
|
+
},
|
|
2321
2537
|
metadata: { tool: "list_pages" }
|
|
2322
2538
|
});
|
|
2323
2539
|
try {
|
|
2324
|
-
const
|
|
2540
|
+
const page = paginateDocsMcpItems(toPageSummaries(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext))).sort(compareDocsMcpPageSummaries), {
|
|
2541
|
+
kind: "mcp.tool/list_pages",
|
|
2542
|
+
scope: stableDocsMcpPaginationScope({ locale: resolvedLocale ?? null }),
|
|
2543
|
+
cursor
|
|
2544
|
+
});
|
|
2545
|
+
const result = {
|
|
2546
|
+
resultCount: page.resultCount,
|
|
2547
|
+
total: page.total,
|
|
2548
|
+
hasMore: page.hasMore,
|
|
2549
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
2550
|
+
pages: page.items
|
|
2551
|
+
};
|
|
2325
2552
|
const elapsed = durationMs(startedAt);
|
|
2326
2553
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
2327
2554
|
type: "mcp_tool",
|
|
@@ -2329,13 +2556,15 @@ async function createDocsMcpServer(options) {
|
|
|
2329
2556
|
locale,
|
|
2330
2557
|
properties: {
|
|
2331
2558
|
tool: "list_pages",
|
|
2332
|
-
resultCount:
|
|
2559
|
+
resultCount: page.resultCount,
|
|
2560
|
+
total: page.total,
|
|
2561
|
+
hasMore: page.hasMore,
|
|
2333
2562
|
durationMs: elapsed
|
|
2334
2563
|
}
|
|
2335
2564
|
});
|
|
2336
2565
|
trackMcpTool("list_pages", {
|
|
2337
2566
|
locale,
|
|
2338
|
-
resultCount:
|
|
2567
|
+
resultCount: page.resultCount
|
|
2339
2568
|
});
|
|
2340
2569
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
2341
2570
|
type: "tool.result",
|
|
@@ -2348,10 +2577,14 @@ async function createDocsMcpServer(options) {
|
|
|
2348
2577
|
durationMs: elapsed,
|
|
2349
2578
|
status: "success",
|
|
2350
2579
|
locale,
|
|
2351
|
-
outputPreview: {
|
|
2580
|
+
outputPreview: {
|
|
2581
|
+
resultCount: page.resultCount,
|
|
2582
|
+
total: page.total,
|
|
2583
|
+
hasMore: page.hasMore
|
|
2584
|
+
},
|
|
2352
2585
|
metadata: { tool: "list_pages" }
|
|
2353
2586
|
});
|
|
2354
|
-
return createStructuredTextResult(
|
|
2587
|
+
return createStructuredTextResult(result);
|
|
2355
2588
|
} catch (error) {
|
|
2356
2589
|
const elapsed = durationMs(startedAt);
|
|
2357
2590
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2371,14 +2604,15 @@ async function createDocsMcpServer(options) {
|
|
|
2371
2604
|
throw error;
|
|
2372
2605
|
}
|
|
2373
2606
|
});
|
|
2374
|
-
if (resolved.tools.listDocs)
|
|
2607
|
+
if (resolved.tools.listDocs) registerTool("list_docs", {
|
|
2375
2608
|
title: "List docs by section",
|
|
2376
2609
|
description: "List documentation pages grouped by section, optionally narrowed to one section.",
|
|
2377
2610
|
inputSchema: listDocsInputSchema,
|
|
2378
2611
|
outputSchema: listDocsOutputSchema,
|
|
2379
2612
|
annotations: { readOnlyHint: true }
|
|
2380
|
-
}, async ({ section, locale }) => {
|
|
2613
|
+
}, async ({ section, locale, cursor }) => {
|
|
2381
2614
|
const startedAt = nowMs();
|
|
2615
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2382
2616
|
const trace = createDocsAgentTraceContext("mcp.tool.list_docs");
|
|
2383
2617
|
const callSpanId = createDocsAgentTraceId("span");
|
|
2384
2618
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2392,14 +2626,21 @@ async function createDocsMcpServer(options) {
|
|
|
2392
2626
|
locale,
|
|
2393
2627
|
inputPreview: {
|
|
2394
2628
|
section,
|
|
2395
|
-
locale
|
|
2629
|
+
locale,
|
|
2630
|
+
hasCursor: cursor !== void 0
|
|
2396
2631
|
},
|
|
2397
2632
|
metadata: { tool: "list_docs" }
|
|
2398
2633
|
});
|
|
2399
2634
|
try {
|
|
2400
|
-
const docs = listDocsBySection(dedupePages(await
|
|
2635
|
+
const docs = paginateDocsMcpDocsList(listDocsBySection(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext)), {
|
|
2401
2636
|
section,
|
|
2402
2637
|
entry: options.source.entry
|
|
2638
|
+
}), {
|
|
2639
|
+
cursor,
|
|
2640
|
+
scope: stableDocsMcpPaginationScope({
|
|
2641
|
+
locale: resolvedLocale ?? null,
|
|
2642
|
+
section: normalizeDocsListMatchValue(section ?? "")
|
|
2643
|
+
})
|
|
2403
2644
|
});
|
|
2404
2645
|
const elapsed = durationMs(startedAt);
|
|
2405
2646
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
@@ -2410,6 +2651,8 @@ async function createDocsMcpServer(options) {
|
|
|
2410
2651
|
tool: "list_docs",
|
|
2411
2652
|
section,
|
|
2412
2653
|
resultCount: docs.resultCount,
|
|
2654
|
+
total: docs.total,
|
|
2655
|
+
hasMore: docs.hasMore,
|
|
2413
2656
|
sectionCount: docs.sectionCount,
|
|
2414
2657
|
durationMs: elapsed
|
|
2415
2658
|
}
|
|
@@ -2431,6 +2674,8 @@ async function createDocsMcpServer(options) {
|
|
|
2431
2674
|
locale,
|
|
2432
2675
|
outputPreview: {
|
|
2433
2676
|
resultCount: docs.resultCount,
|
|
2677
|
+
total: docs.total,
|
|
2678
|
+
hasMore: docs.hasMore,
|
|
2434
2679
|
sectionCount: docs.sectionCount
|
|
2435
2680
|
},
|
|
2436
2681
|
metadata: { tool: "list_docs" }
|
|
@@ -2455,14 +2700,15 @@ async function createDocsMcpServer(options) {
|
|
|
2455
2700
|
throw error;
|
|
2456
2701
|
}
|
|
2457
2702
|
});
|
|
2458
|
-
if (resolved.tools.listTasks)
|
|
2703
|
+
if (resolved.tools.listTasks) registerTool("list_tasks", {
|
|
2459
2704
|
title: "List documented tasks",
|
|
2460
2705
|
description: "List pages with actionable agent contracts, optionally filtered by text or applicability.",
|
|
2461
2706
|
inputSchema: listTasksInputSchema,
|
|
2462
2707
|
outputSchema: listTasksOutputSchema,
|
|
2463
2708
|
annotations: { readOnlyHint: true }
|
|
2464
|
-
}, async ({ query, framework, version, package: packageName, locale }) => {
|
|
2709
|
+
}, async ({ query, framework, version, package: packageName, locale, cursor }) => {
|
|
2465
2710
|
const startedAt = nowMs();
|
|
2711
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2466
2712
|
const trace = createDocsAgentTraceContext("mcp.tool.list_tasks");
|
|
2467
2713
|
const callSpanId = createDocsAgentTraceId("span");
|
|
2468
2714
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
@@ -2478,20 +2724,34 @@ async function createDocsMcpServer(options) {
|
|
|
2478
2724
|
queryLength: query?.length,
|
|
2479
2725
|
framework,
|
|
2480
2726
|
version,
|
|
2481
|
-
package: packageName
|
|
2727
|
+
package: packageName,
|
|
2728
|
+
hasCursor: cursor !== void 0
|
|
2482
2729
|
},
|
|
2483
2730
|
metadata: { tool: "list_tasks" }
|
|
2484
2731
|
});
|
|
2485
2732
|
try {
|
|
2486
|
-
const
|
|
2733
|
+
const page = paginateDocsMcpItems(listDocsTasks(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext)), {
|
|
2487
2734
|
query,
|
|
2488
2735
|
framework,
|
|
2489
2736
|
version,
|
|
2490
2737
|
package: packageName
|
|
2738
|
+
}).sort(compareDocsMcpTaskSummaries), {
|
|
2739
|
+
kind: "mcp.tool/list_tasks",
|
|
2740
|
+
scope: stableDocsMcpPaginationScope({
|
|
2741
|
+
locale: resolvedLocale ?? null,
|
|
2742
|
+
query: query?.trim().toLowerCase() ?? null,
|
|
2743
|
+
framework: framework?.trim().toLowerCase() ?? null,
|
|
2744
|
+
version: version?.trim().toLowerCase() ?? null,
|
|
2745
|
+
package: packageName?.trim().toLowerCase() ?? null
|
|
2746
|
+
}),
|
|
2747
|
+
cursor
|
|
2491
2748
|
});
|
|
2492
2749
|
const result = {
|
|
2493
|
-
resultCount:
|
|
2494
|
-
|
|
2750
|
+
resultCount: page.resultCount,
|
|
2751
|
+
total: page.total,
|
|
2752
|
+
hasMore: page.hasMore,
|
|
2753
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
2754
|
+
tasks: page.items
|
|
2495
2755
|
};
|
|
2496
2756
|
const elapsed = durationMs(startedAt);
|
|
2497
2757
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
@@ -2504,13 +2764,15 @@ async function createDocsMcpServer(options) {
|
|
|
2504
2764
|
framework,
|
|
2505
2765
|
version,
|
|
2506
2766
|
package: packageName,
|
|
2507
|
-
resultCount:
|
|
2767
|
+
resultCount: page.resultCount,
|
|
2768
|
+
total: page.total,
|
|
2769
|
+
hasMore: page.hasMore,
|
|
2508
2770
|
durationMs: elapsed
|
|
2509
2771
|
}
|
|
2510
2772
|
});
|
|
2511
2773
|
trackMcpTool("list_tasks", {
|
|
2512
2774
|
locale,
|
|
2513
|
-
resultCount:
|
|
2775
|
+
resultCount: page.resultCount
|
|
2514
2776
|
});
|
|
2515
2777
|
await emitDocsAgentTraceEvent(options.observability, {
|
|
2516
2778
|
type: "tool.result",
|
|
@@ -2523,7 +2785,11 @@ async function createDocsMcpServer(options) {
|
|
|
2523
2785
|
durationMs: elapsed,
|
|
2524
2786
|
status: "success",
|
|
2525
2787
|
locale,
|
|
2526
|
-
outputPreview: {
|
|
2788
|
+
outputPreview: {
|
|
2789
|
+
resultCount: page.resultCount,
|
|
2790
|
+
total: page.total,
|
|
2791
|
+
hasMore: page.hasMore
|
|
2792
|
+
},
|
|
2527
2793
|
metadata: { tool: "list_tasks" }
|
|
2528
2794
|
});
|
|
2529
2795
|
return {
|
|
@@ -2552,7 +2818,7 @@ async function createDocsMcpServer(options) {
|
|
|
2552
2818
|
throw error;
|
|
2553
2819
|
}
|
|
2554
2820
|
});
|
|
2555
|
-
if (resolved.tools.readTask)
|
|
2821
|
+
if (resolved.tools.readTask) registerTool("read_task", {
|
|
2556
2822
|
title: "Read a documented task",
|
|
2557
2823
|
description: "Read the full structured agent contract for a page by slug or URL path.",
|
|
2558
2824
|
inputSchema: readTaskInputSchema,
|
|
@@ -2701,7 +2967,7 @@ async function createDocsMcpServer(options) {
|
|
|
2701
2967
|
throw error;
|
|
2702
2968
|
}
|
|
2703
2969
|
});
|
|
2704
|
-
if (resolved.tools.getNavigation)
|
|
2970
|
+
if (resolved.tools.getNavigation) registerTool("get_navigation", {
|
|
2705
2971
|
title: "Get docs navigation",
|
|
2706
2972
|
description: "Return the documentation navigation tree for the current docs site.",
|
|
2707
2973
|
inputSchema: getNavigationInputSchema,
|
|
@@ -2774,7 +3040,7 @@ async function createDocsMcpServer(options) {
|
|
|
2774
3040
|
throw error;
|
|
2775
3041
|
}
|
|
2776
3042
|
});
|
|
2777
|
-
if (resolved.tools.getConfigSchema)
|
|
3043
|
+
if (resolved.tools.getConfigSchema) registerTool("get_config_schema", {
|
|
2778
3044
|
title: "Get docs config schema",
|
|
2779
3045
|
description: "Return structured docs.config.ts option metadata, optionally filtered by option path or query.",
|
|
2780
3046
|
inputSchema: getConfigSchemaInputSchema,
|
|
@@ -2849,13 +3115,13 @@ async function createDocsMcpServer(options) {
|
|
|
2849
3115
|
throw error;
|
|
2850
3116
|
}
|
|
2851
3117
|
});
|
|
2852
|
-
if (resolved.tools.searchDocs)
|
|
3118
|
+
if (resolved.tools.searchDocs) registerTool("search_docs", {
|
|
2853
3119
|
title: "Search documentation",
|
|
2854
3120
|
description: "Search the docs by keyword with optional framework, version, package, and tag filters. Returns structured ambiguity and metadata warnings.",
|
|
2855
3121
|
inputSchema: searchDocsInputSchema,
|
|
2856
3122
|
outputSchema: searchDocsOutputSchema,
|
|
2857
3123
|
annotations: { readOnlyHint: true }
|
|
2858
|
-
}, async ({ query, limit, locale, audience, framework, version, package: packageName, tags }) => {
|
|
3124
|
+
}, async ({ query, limit, cursor, locale, audience, framework, version, package: packageName, tags }) => {
|
|
2859
3125
|
const startedAt = nowMs();
|
|
2860
3126
|
const resolvedLimit = limit ?? 10;
|
|
2861
3127
|
const resolvedAudience = audience ?? "agent";
|
|
@@ -2880,6 +3146,7 @@ async function createDocsMcpServer(options) {
|
|
|
2880
3146
|
inputPreview: {
|
|
2881
3147
|
queryLength: query.length,
|
|
2882
3148
|
limit: resolvedLimit,
|
|
3149
|
+
hasCursor: cursor !== void 0,
|
|
2883
3150
|
locale,
|
|
2884
3151
|
audience: resolvedAudience,
|
|
2885
3152
|
filterFields: Object.entries(filters).filter(([, value]) => value !== void 0).map(([field]) => field)
|
|
@@ -2897,7 +3164,8 @@ async function createDocsMcpServer(options) {
|
|
|
2897
3164
|
siteTitle: options.source.siteTitle,
|
|
2898
3165
|
baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0),
|
|
2899
3166
|
syncBaseUrl: options.source.baseUrl ?? null,
|
|
2900
|
-
limit: resolvedLimit
|
|
3167
|
+
limit: resolvedLimit,
|
|
3168
|
+
cursor
|
|
2901
3169
|
});
|
|
2902
3170
|
const elapsed = durationMs(startedAt);
|
|
2903
3171
|
await emitDocsAnalyticsEvent(options.analytics, {
|
|
@@ -2911,6 +3179,8 @@ async function createDocsMcpServer(options) {
|
|
|
2911
3179
|
limit: resolvedLimit,
|
|
2912
3180
|
audience: resolvedAudience,
|
|
2913
3181
|
resultCount: searchResponse.resultCount,
|
|
3182
|
+
total: searchResponse.total,
|
|
3183
|
+
hasMore: searchResponse.hasMore,
|
|
2914
3184
|
warningCount: searchResponse.warnings.length,
|
|
2915
3185
|
durationMs: elapsed
|
|
2916
3186
|
}
|
|
@@ -2932,6 +3202,8 @@ async function createDocsMcpServer(options) {
|
|
|
2932
3202
|
locale,
|
|
2933
3203
|
outputPreview: {
|
|
2934
3204
|
resultCount: searchResponse.resultCount,
|
|
3205
|
+
total: searchResponse.total,
|
|
3206
|
+
hasMore: searchResponse.hasMore,
|
|
2935
3207
|
warningCount: searchResponse.warnings.length
|
|
2936
3208
|
},
|
|
2937
3209
|
metadata: { tool: "search_docs" }
|
|
@@ -2956,7 +3228,7 @@ async function createDocsMcpServer(options) {
|
|
|
2956
3228
|
throw error;
|
|
2957
3229
|
}
|
|
2958
3230
|
});
|
|
2959
|
-
if (resolved.tools.getCodeExamples)
|
|
3231
|
+
if (resolved.tools.getCodeExamples) registerTool("get_code_examples", {
|
|
2960
3232
|
title: "Get docs code examples",
|
|
2961
3233
|
description: "Return fenced code examples from the docs with parsed metadata such as title, framework, packageManager, and runnable.",
|
|
2962
3234
|
inputSchema: getCodeExamplesInputSchema,
|
|
@@ -3055,7 +3327,7 @@ async function createDocsMcpServer(options) {
|
|
|
3055
3327
|
throw error;
|
|
3056
3328
|
}
|
|
3057
3329
|
});
|
|
3058
|
-
if (resolved.tools.getContext)
|
|
3330
|
+
if (resolved.tools.getContext) registerTool("get_context", {
|
|
3059
3331
|
title: "Get budgeted docs context",
|
|
3060
3332
|
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.",
|
|
3061
3333
|
inputSchema: getContextInputSchema,
|
|
@@ -3165,7 +3437,179 @@ async function createDocsMcpServer(options) {
|
|
|
3165
3437
|
throw error;
|
|
3166
3438
|
}
|
|
3167
3439
|
});
|
|
3168
|
-
if (resolved.tools.
|
|
3440
|
+
if (resolved.tools.listPageSections !== false) registerTool("list_page_sections", {
|
|
3441
|
+
title: "List sections in a docs page",
|
|
3442
|
+
description: "Discover a page's canonical headings, anchors, hierarchy, line ranges, size estimates, and budget-aware fetch URLs without returning the page body.",
|
|
3443
|
+
inputSchema: listPageSectionsInputSchema,
|
|
3444
|
+
outputSchema: pageSectionIndexOutputSchema,
|
|
3445
|
+
annotations: { readOnlyHint: true }
|
|
3446
|
+
}, async ({ path: requestedPath, locale, tokenBudget, byteBudget, cursor }) => {
|
|
3447
|
+
const startedAt = nowMs();
|
|
3448
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
3449
|
+
const trace = createDocsAgentTraceContext("mcp.tool.list_page_sections");
|
|
3450
|
+
const callSpanId = createDocsAgentTraceId("span");
|
|
3451
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3452
|
+
type: "tool.call",
|
|
3453
|
+
source: "mcp",
|
|
3454
|
+
traceId: trace.traceId,
|
|
3455
|
+
spanId: callSpanId,
|
|
3456
|
+
name: "list_page_sections",
|
|
3457
|
+
startedAt: trace.startedAt,
|
|
3458
|
+
status: "started",
|
|
3459
|
+
locale: resolvedLocale,
|
|
3460
|
+
inputPreview: {
|
|
3461
|
+
path: requestedPath,
|
|
3462
|
+
locale,
|
|
3463
|
+
resolvedLocale,
|
|
3464
|
+
tokenBudget,
|
|
3465
|
+
byteBudget,
|
|
3466
|
+
hasCursor: cursor !== void 0
|
|
3467
|
+
},
|
|
3468
|
+
metadata: { tool: "list_page_sections" }
|
|
3469
|
+
});
|
|
3470
|
+
try {
|
|
3471
|
+
const page = findDocsPage(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext)), requestedPath, options.source.entry);
|
|
3472
|
+
if (!page) {
|
|
3473
|
+
const elapsed = durationMs(startedAt);
|
|
3474
|
+
await emitDocsAnalyticsEvent(options.analytics, {
|
|
3475
|
+
type: "mcp_tool",
|
|
3476
|
+
source: "mcp",
|
|
3477
|
+
locale: resolvedLocale,
|
|
3478
|
+
properties: {
|
|
3479
|
+
tool: "list_page_sections",
|
|
3480
|
+
requestedPath,
|
|
3481
|
+
found: false,
|
|
3482
|
+
durationMs: elapsed
|
|
3483
|
+
}
|
|
3484
|
+
});
|
|
3485
|
+
trackMcpTool("list_page_sections", {
|
|
3486
|
+
locale: resolvedLocale,
|
|
3487
|
+
resultCount: 0
|
|
3488
|
+
});
|
|
3489
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3490
|
+
type: "tool.error",
|
|
3491
|
+
source: "mcp",
|
|
3492
|
+
traceId: trace.traceId,
|
|
3493
|
+
parentSpanId: callSpanId,
|
|
3494
|
+
name: "list_page_sections",
|
|
3495
|
+
startedAt: trace.startedAt,
|
|
3496
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3497
|
+
durationMs: elapsed,
|
|
3498
|
+
status: "error",
|
|
3499
|
+
locale: resolvedLocale,
|
|
3500
|
+
outputPreview: {
|
|
3501
|
+
found: false,
|
|
3502
|
+
path: requestedPath
|
|
3503
|
+
},
|
|
3504
|
+
metadata: {
|
|
3505
|
+
tool: "list_page_sections",
|
|
3506
|
+
reason: "not_found"
|
|
3507
|
+
}
|
|
3508
|
+
});
|
|
3509
|
+
return {
|
|
3510
|
+
content: [{
|
|
3511
|
+
type: "text",
|
|
3512
|
+
text: JSON.stringify({ error: `No docs page matched "${requestedPath}".` }, null, 2)
|
|
3513
|
+
}],
|
|
3514
|
+
isError: true
|
|
3515
|
+
};
|
|
3516
|
+
}
|
|
3517
|
+
const document = upsertPageAgentContractMarkdown(getDocsMcpSourceMarkdown(page), page.agent);
|
|
3518
|
+
const publicBaseUrl = options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0);
|
|
3519
|
+
const completeSectionIndex = buildDocsMarkdownSectionIndex(document, {
|
|
3520
|
+
canonicalUrl: resolveDocsMcpPublicUrl(withDocsMcpUrlLocale(page.url, resolvedLocale), publicBaseUrl),
|
|
3521
|
+
markdownUrl: resolveDocsMcpPublicUrl(toDocsMcpPageMarkdownUrl(page.url, resolvedLocale), publicBaseUrl),
|
|
3522
|
+
tokenBudget,
|
|
3523
|
+
byteBudget
|
|
3524
|
+
});
|
|
3525
|
+
const sectionPage = paginateDocsMcpItems(completeSectionIndex.sections, {
|
|
3526
|
+
kind: "mcp.tool/list_page_sections",
|
|
3527
|
+
scope: stableDocsMcpPaginationScope({
|
|
3528
|
+
path: page.url,
|
|
3529
|
+
locale: resolvedLocale ?? null,
|
|
3530
|
+
tokenBudget: tokenBudget ?? null,
|
|
3531
|
+
byteBudget: byteBudget ?? null
|
|
3532
|
+
}),
|
|
3533
|
+
cursor
|
|
3534
|
+
});
|
|
3535
|
+
const sectionIndex = {
|
|
3536
|
+
...completeSectionIndex,
|
|
3537
|
+
sectionCount: completeSectionIndex.sectionCount,
|
|
3538
|
+
resultCount: sectionPage.resultCount,
|
|
3539
|
+
total: sectionPage.total,
|
|
3540
|
+
hasMore: sectionPage.hasMore,
|
|
3541
|
+
...sectionPage.nextCursor ? { nextCursor: sectionPage.nextCursor } : {},
|
|
3542
|
+
sections: sectionPage.items
|
|
3543
|
+
};
|
|
3544
|
+
const elapsed = durationMs(startedAt);
|
|
3545
|
+
await emitDocsAnalyticsEvent(options.analytics, {
|
|
3546
|
+
type: "mcp_tool",
|
|
3547
|
+
source: "mcp",
|
|
3548
|
+
locale: resolvedLocale,
|
|
3549
|
+
path: page.url,
|
|
3550
|
+
properties: {
|
|
3551
|
+
tool: "list_page_sections",
|
|
3552
|
+
requestedPath,
|
|
3553
|
+
slug: page.slug,
|
|
3554
|
+
found: true,
|
|
3555
|
+
sectionCount: sectionIndex.sectionCount,
|
|
3556
|
+
total: sectionIndex.total,
|
|
3557
|
+
hasMore: sectionIndex.hasMore,
|
|
3558
|
+
estimatedTokens: sectionIndex.estimatedTokens,
|
|
3559
|
+
utf8Bytes: sectionIndex.utf8Bytes,
|
|
3560
|
+
tokenBudget,
|
|
3561
|
+
byteBudget,
|
|
3562
|
+
durationMs: elapsed
|
|
3563
|
+
}
|
|
3564
|
+
});
|
|
3565
|
+
trackMcpTool("list_page_sections", {
|
|
3566
|
+
locale: resolvedLocale,
|
|
3567
|
+
resultCount: sectionIndex.resultCount
|
|
3568
|
+
});
|
|
3569
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3570
|
+
type: "tool.result",
|
|
3571
|
+
source: "mcp",
|
|
3572
|
+
traceId: trace.traceId,
|
|
3573
|
+
parentSpanId: callSpanId,
|
|
3574
|
+
name: "list_page_sections",
|
|
3575
|
+
startedAt: trace.startedAt,
|
|
3576
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3577
|
+
durationMs: elapsed,
|
|
3578
|
+
status: "success",
|
|
3579
|
+
locale: resolvedLocale,
|
|
3580
|
+
path: page.url,
|
|
3581
|
+
outputPreview: {
|
|
3582
|
+
found: true,
|
|
3583
|
+
slug: page.slug,
|
|
3584
|
+
sectionCount: sectionIndex.sectionCount,
|
|
3585
|
+
total: sectionIndex.total,
|
|
3586
|
+
hasMore: sectionIndex.hasMore,
|
|
3587
|
+
estimatedTokens: sectionIndex.estimatedTokens,
|
|
3588
|
+
utf8Bytes: sectionIndex.utf8Bytes
|
|
3589
|
+
},
|
|
3590
|
+
metadata: { tool: "list_page_sections" }
|
|
3591
|
+
});
|
|
3592
|
+
return createStructuredTextResult(sectionIndex);
|
|
3593
|
+
} catch (error) {
|
|
3594
|
+
const elapsed = durationMs(startedAt);
|
|
3595
|
+
await emitDocsAgentTraceEvent(options.observability, {
|
|
3596
|
+
type: "tool.error",
|
|
3597
|
+
source: "mcp",
|
|
3598
|
+
traceId: trace.traceId,
|
|
3599
|
+
parentSpanId: callSpanId,
|
|
3600
|
+
name: "list_page_sections",
|
|
3601
|
+
startedAt: trace.startedAt,
|
|
3602
|
+
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3603
|
+
durationMs: elapsed,
|
|
3604
|
+
status: "error",
|
|
3605
|
+
locale: resolvedLocale,
|
|
3606
|
+
outputPreview: { message: error instanceof Error ? error.message : "Unknown error" },
|
|
3607
|
+
metadata: { tool: "list_page_sections" }
|
|
3608
|
+
});
|
|
3609
|
+
throw error;
|
|
3610
|
+
}
|
|
3611
|
+
});
|
|
3612
|
+
if (resolved.tools.readPage) registerTool("read_page", {
|
|
3169
3613
|
title: "Read a docs page",
|
|
3170
3614
|
description: "Read a documentation page by slug or URL path, optionally selecting one heading and limiting returned characters.",
|
|
3171
3615
|
inputSchema: readPageInputSchema,
|
|
@@ -4180,6 +4624,18 @@ function toDocsListPageSummary(page) {
|
|
|
4180
4624
|
lastModified: page.lastModified
|
|
4181
4625
|
};
|
|
4182
4626
|
}
|
|
4627
|
+
function compareDocsMcpPageSummaries(left, right) {
|
|
4628
|
+
const urlOrder = left.url.localeCompare(right.url);
|
|
4629
|
+
if (urlOrder !== 0) return urlOrder;
|
|
4630
|
+
const slugOrder = left.slug.localeCompare(right.slug);
|
|
4631
|
+
return slugOrder !== 0 ? slugOrder : left.title.localeCompare(right.title);
|
|
4632
|
+
}
|
|
4633
|
+
function compareDocsMcpTaskSummaries(left, right) {
|
|
4634
|
+
const urlOrder = left.url.localeCompare(right.url);
|
|
4635
|
+
if (urlOrder !== 0) return urlOrder;
|
|
4636
|
+
const slugOrder = left.slug.localeCompare(right.slug);
|
|
4637
|
+
return slugOrder !== 0 ? slugOrder : left.title.localeCompare(right.title);
|
|
4638
|
+
}
|
|
4183
4639
|
function listDocsTasks(pages, filters) {
|
|
4184
4640
|
const query = filters.query?.toLowerCase();
|
|
4185
4641
|
const applicabilityFilters = [
|
|
@@ -4221,6 +4677,8 @@ function listDocsBySection(pages, filters) {
|
|
|
4221
4677
|
const requestedSection = filters.section?.trim();
|
|
4222
4678
|
if (!requestedSection) return {
|
|
4223
4679
|
resultCount: allPages.length,
|
|
4680
|
+
total: allPages.length,
|
|
4681
|
+
hasMore: false,
|
|
4224
4682
|
sectionCount: countDocsSections(tree.sections),
|
|
4225
4683
|
pages: allPages,
|
|
4226
4684
|
rootPages: tree.rootPages,
|
|
@@ -4233,6 +4691,8 @@ function listDocsBySection(pages, filters) {
|
|
|
4233
4691
|
return {
|
|
4234
4692
|
section: requestedSection,
|
|
4235
4693
|
resultCount: matchedPages.length,
|
|
4694
|
+
total: matchedPages.length,
|
|
4695
|
+
hasMore: false,
|
|
4236
4696
|
sectionCount: countDocsSections(sections),
|
|
4237
4697
|
pages: matchedPages,
|
|
4238
4698
|
rootPages: [],
|
|
@@ -4243,6 +4703,8 @@ function listDocsBySection(pages, filters) {
|
|
|
4243
4703
|
if (page) return {
|
|
4244
4704
|
section: requestedSection,
|
|
4245
4705
|
resultCount: 1,
|
|
4706
|
+
total: 1,
|
|
4707
|
+
hasMore: false,
|
|
4246
4708
|
sectionCount: 0,
|
|
4247
4709
|
pages: [page],
|
|
4248
4710
|
rootPages: [page],
|
|
@@ -4251,12 +4713,46 @@ function listDocsBySection(pages, filters) {
|
|
|
4251
4713
|
return {
|
|
4252
4714
|
section: requestedSection,
|
|
4253
4715
|
resultCount: 0,
|
|
4716
|
+
total: 0,
|
|
4717
|
+
hasMore: false,
|
|
4254
4718
|
sectionCount: 0,
|
|
4255
4719
|
pages: [],
|
|
4256
4720
|
rootPages: [],
|
|
4257
4721
|
sections: []
|
|
4258
4722
|
};
|
|
4259
4723
|
}
|
|
4724
|
+
function paginateDocsMcpDocsList(docs, options) {
|
|
4725
|
+
const page = paginateDocsMcpItems([...docs.pages].sort(compareDocsMcpPageSummaries), {
|
|
4726
|
+
kind: "mcp.tool/list_docs",
|
|
4727
|
+
scope: options.scope,
|
|
4728
|
+
cursor: options.cursor
|
|
4729
|
+
});
|
|
4730
|
+
const pageUrls = new Set(page.items.map((item) => item.url));
|
|
4731
|
+
const sections = pruneDocsMcpSections(docs.sections, pageUrls);
|
|
4732
|
+
return {
|
|
4733
|
+
...docs,
|
|
4734
|
+
resultCount: page.resultCount,
|
|
4735
|
+
total: page.total,
|
|
4736
|
+
hasMore: page.hasMore,
|
|
4737
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
4738
|
+
pages: page.items,
|
|
4739
|
+
rootPages: docs.rootPages.filter((item) => pageUrls.has(item.url)),
|
|
4740
|
+
sections,
|
|
4741
|
+
sectionCount: docs.sectionCount
|
|
4742
|
+
};
|
|
4743
|
+
}
|
|
4744
|
+
function pruneDocsMcpSections(sections, pageUrls) {
|
|
4745
|
+
return sections.flatMap((section) => {
|
|
4746
|
+
const pages = section.pages.filter((page) => pageUrls.has(page.url));
|
|
4747
|
+
const childSections = pruneDocsMcpSections(section.sections, pageUrls);
|
|
4748
|
+
if (pages.length === 0 && childSections.length === 0) return [];
|
|
4749
|
+
return [{
|
|
4750
|
+
...section,
|
|
4751
|
+
pages,
|
|
4752
|
+
sections: childSections
|
|
4753
|
+
}];
|
|
4754
|
+
});
|
|
4755
|
+
}
|
|
4260
4756
|
function buildDocsSectionTree(pages) {
|
|
4261
4757
|
const sectionSlugs = /* @__PURE__ */ new Set();
|
|
4262
4758
|
for (const page of pages) {
|
|
@@ -4611,6 +5107,35 @@ function toStructuredDocsMcpPage(page) {
|
|
|
4611
5107
|
tags: page.tags
|
|
4612
5108
|
};
|
|
4613
5109
|
}
|
|
5110
|
+
function withDocsMcpUrlLocale(value, locale) {
|
|
5111
|
+
if (!locale) return value;
|
|
5112
|
+
const absolute = /^[a-z][a-z\d+.-]*:/iu.test(value);
|
|
5113
|
+
try {
|
|
5114
|
+
const url = new URL(value, "https://docs.invalid");
|
|
5115
|
+
if (!url.searchParams.has("lang")) url.searchParams.set("lang", locale);
|
|
5116
|
+
return absolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
|
|
5117
|
+
} catch {
|
|
5118
|
+
return value;
|
|
5119
|
+
}
|
|
5120
|
+
}
|
|
5121
|
+
function toDocsMcpPageMarkdownUrl(value, locale) {
|
|
5122
|
+
const absolute = /^[a-z][a-z\d+.-]*:/iu.test(value);
|
|
5123
|
+
try {
|
|
5124
|
+
const url = new URL(value, "https://docs.invalid");
|
|
5125
|
+
const markdownPath = toDocsMarkdownUrl(`${url.pathname}${url.search}${url.hash}`, { locale });
|
|
5126
|
+
return absolute ? new URL(markdownPath, url.origin).toString() : markdownPath;
|
|
5127
|
+
} catch {
|
|
5128
|
+
return toDocsMarkdownUrl(value, { locale });
|
|
5129
|
+
}
|
|
5130
|
+
}
|
|
5131
|
+
function resolveDocsMcpPublicUrl(value, baseUrl) {
|
|
5132
|
+
if (!baseUrl || /^[a-z][a-z\d+.-]*:/iu.test(value)) return value;
|
|
5133
|
+
try {
|
|
5134
|
+
return new URL(value, `${baseUrl.replace(/\/+$/u, "")}/`).toString();
|
|
5135
|
+
} catch {
|
|
5136
|
+
return value;
|
|
5137
|
+
}
|
|
5138
|
+
}
|
|
4614
5139
|
function getDocsMcpSourceMarkdown(page) {
|
|
4615
5140
|
return page.agentRawContent ?? page.agentFallbackRawContent ?? page.agentContent ?? page.agentFallbackContent ?? page.rawContent ?? page.content;
|
|
4616
5141
|
}
|
|
@@ -4816,24 +5341,24 @@ async function buildDocsMcpContext(options) {
|
|
|
4816
5341
|
};
|
|
4817
5342
|
}
|
|
4818
5343
|
function findDocsPage(pages, requestedPath, entry) {
|
|
4819
|
-
const normalizedRequest =
|
|
4820
|
-
const
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
const normalizedSlug = normalizePathSegment(requestedPath.replace(
|
|
4826
|
-
|
|
4827
|
-
return null;
|
|
5344
|
+
const normalizedRequest = normalizeDocsMcpPageIdentity(requestedPath, entry, true);
|
|
5345
|
+
for (const page of pages) if (normalizeDocsMcpPageIdentity(page.url, entry, true) === normalizedRequest) return page;
|
|
5346
|
+
const normalizedRequestPath = normalizeDocsMcpPageIdentity(requestedPath, entry, false);
|
|
5347
|
+
const pathMatches = pages.filter((page) => normalizeDocsMcpPageIdentity(page.url, entry, false) === normalizedRequestPath);
|
|
5348
|
+
if (pathMatches.length === 1) return pathMatches[0];
|
|
5349
|
+
if (pathMatches.length > 1) return null;
|
|
5350
|
+
const normalizedSlug = normalizePathSegment(normalizeDocsMcpPageIdentity(requestedPath, void 0, false).replace(/^\//u, ""));
|
|
5351
|
+
const slugMatches = pages.filter((page) => normalizePathSegment(page.slug) === normalizedSlug);
|
|
5352
|
+
return slugMatches.length === 1 ? slugMatches[0] : null;
|
|
4828
5353
|
}
|
|
4829
|
-
function
|
|
5354
|
+
function normalizeDocsMcpPageIdentity(value, entry, includeSearch) {
|
|
4830
5355
|
try {
|
|
4831
|
-
const absolute = /^[a-z][a-z\d+.-]*:/iu.test(value);
|
|
4832
5356
|
const url = new URL(value, "https://docs.local");
|
|
4833
|
-
url.searchParams.
|
|
4834
|
-
return
|
|
5357
|
+
if (includeSearch) url.searchParams.sort();
|
|
5358
|
+
return `${normalizeRequestedPath(url.pathname, entry)}${includeSearch ? url.search : ""}`;
|
|
4835
5359
|
} catch {
|
|
4836
|
-
|
|
5360
|
+
const [pathname = value, search = ""] = value.split("?", 2);
|
|
5361
|
+
return `${normalizeRequestedPath(pathname, entry)}${includeSearch && search ? `?${search}` : ""}`;
|
|
4837
5362
|
}
|
|
4838
5363
|
}
|
|
4839
5364
|
function normalizeRequestedPath(requestedPath, entry) {
|