@farming-labs/docs 0.2.78 → 0.2.80
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-Ba94vwM2.mjs → agent-Cj50nyeV.mjs} +40 -3
- package/dist/{agent-CHgWJcK_.d.mts → agent-DGALg9hQ.d.mts} +256 -14
- package/dist/{agent-CM-hzhfh.mjs → agent-aWl_O6xn.mjs} +2 -2
- package/dist/{agent-evals-C8dkgJMN.mjs → agent-evals-DvQQtN62.mjs} +1 -1
- package/dist/{agent-export-DdF-IVfg.mjs → agent-export-BISSb83U.mjs} +5 -5
- package/dist/{agent-provenance-D8UBpnMc.mjs → agent-provenance-C_jgqNTW.mjs} +1 -1
- package/dist/agent-skills-bundle.d.mts +1 -1
- package/dist/{agent-skills-server-zvs0Yknt.d.mts → agent-skills-server-Daq-FOay.d.mts} +2 -2
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/{agents-v0Em2KZo.mjs → agents-DLNUgcgU.mjs} +4 -4
- package/dist/cli/index.mjs +14 -14
- package/dist/client/react.d.mts +1 -1
- package/dist/{cloud-ask-ai-BwsdF7AQ.d.mts → cloud-ask-ai-o41WfOTk.d.mts} +1 -1
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/{doctor-BbrN0rdC.mjs → doctor-BxP-UHaE.mjs} +9 -9
- package/dist/{golden-evaluations-Bk9t-HNq.mjs → golden-evaluations-Bk8MBi3Z.mjs} +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +5 -5
- package/dist/{mcp-DT-WNsA-.mjs → mcp-BU63wzaM.mjs} +5 -4
- package/dist/mcp.d.mts +18 -6
- package/dist/mcp.mjs +292 -56
- package/dist/{prompt-references-CoDorsvS.mjs → prompt-references-CMMoF6AY.mjs} +2 -2
- package/dist/retrieval-digest-DIbiu0TW.d.mts +190 -0
- package/dist/{review-DrCaaT7G.mjs → review-D14mUw5D.mjs} +4 -4
- package/dist/{robots-C_v2HK43.mjs → robots-BukukxNm.mjs} +1 -1
- package/dist/{robots-izJbM9cv.mjs → robots-DmczzidR.mjs} +2 -2
- package/dist/{search-YiZMZDfb.mjs → search-DP96dV3e.mjs} +4 -4
- package/dist/server.d.mts +7 -7
- package/dist/server.mjs +6 -6
- package/dist/{sitemap-NO8UMO6Y.mjs → sitemap-DuosRvmn.mjs} +4 -4
- package/dist/{sitemap-server-Dgxs9V6S.mjs → sitemap-server-DzlV1NOB.mjs} +1 -1
- package/dist/{standards-discovery-BWyNgZSs.d.mts → standards-discovery-C2cUIQzW.d.mts} +1 -1
- package/dist/{types-CpLnwHak.d.mts → types-o-ULHPK6.d.mts} +2 -0
- package/package.json +6 -2
- package/dist/retrieval-digest-CO3wqeMk.d.mts +0 -413
package/dist/mcp.mjs
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { a as emitDocsAnalyticsEvent, i as emitDocsAgentTraceEvent, n as createDocsAgentTraceContext, r as createDocsAgentTraceId } from "./analytics-Bx44lg6d.mjs";
|
|
2
|
-
import { $n as
|
|
2
|
+
import { $n as normalizeDocsMcpEndpointPath, An as normalizeAgentFramework, E as DOCS_MARKDOWN_SECTION_INDEX_FORMAT, En as resolveDocsAudienceMdxContent, Fn as paginateDocsItems, Jn as isDocsMcpOAuthScopeToken, Jt as resolveDocsContentChangesConfig, Kt as isDocsContentChangeGeneration, Ln as isDocsRetrievalCanonicalUrl, Mn as normalizeAgentScopeValues, On as agentVersionConstraintMatches, P as buildDocsMarkdownSectionIndex, Pn as DocsPaginationCursorError, Qn as normalizeDocsMcpAuthorizationServerUrls, Rn as normalizeDocsRelated, Ut as DocsContentChangesRequestError, Wt as createDocsContentChangeFeed, Yn as isDocsMcpProtectedResourceMetadataPath, Zn as isDocsMcpResourcePath, dn as performDocsSearch, er as resolveDocsMcpProtectedResourceMetadataLocation, fn as performDocsSearchWithMetadata, jn as normalizeAgentLocale, kn as agentVersionConstraintsOverlap, tn as buildDocsSearchFacets, tr as resolveDocsMcpResourceLocation, un as normalizeDocsSearchFilters, wt as toDocsMarkdownUrl, yn as resolveLocalDocsMcpSearchConfig, zn as renderDocsRelatedMarkdownLines } from "./agent-Cj50nyeV.mjs";
|
|
3
3
|
import { S as upsertPageAgentContractMarkdown, _ as hasStructuredPageAgentContract, o as findDocsMarkdownSection, s as parseDocsMarkdownSections, v as normalizePageAgentFrontmatter } from "./markdown-sections-7OoA7ylx.mjs";
|
|
4
4
|
import "./standards-discovery-BKlEnK_H.mjs";
|
|
5
|
-
import { f as emitDocsTelemetryAgentSurfaceEvent, h as emitDocsTelemetryProjectEvent, l as resolvePageSidebarFolderIndexBehavior, m as emitDocsTelemetryMcpToolEvent, s as stripGeneratedAgentProvenance } from "./agent-provenance-
|
|
5
|
+
import { f as emitDocsTelemetryAgentSurfaceEvent, h as emitDocsTelemetryProjectEvent, l as resolvePageSidebarFolderIndexBehavior, m as emitDocsTelemetryMcpToolEvent, s as stripGeneratedAgentProvenance } from "./agent-provenance-C_jgqNTW.mjs";
|
|
6
6
|
import matter from "gray-matter";
|
|
7
7
|
import fs from "node:fs";
|
|
8
8
|
import path from "node:path";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
12
|
-
import { ErrorCode, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
10
|
+
import { InMemoryServerEventBus, McpServer, ProtocolError, ProtocolErrorCode, ResourceTemplate, createMcpHandler, isInitializeRequest } from "@modelcontextprotocol/server";
|
|
13
11
|
import * as z from "zod/v4";
|
|
14
12
|
|
|
15
13
|
//#region src/mcp.ts
|
|
@@ -21,6 +19,9 @@ const MAX_MCP_CONTEXT_TOKEN_BUDGET = 32e3;
|
|
|
21
19
|
const DOCS_MCP_PROTOCOL_LIST_PAGE_SIZE = 10;
|
|
22
20
|
const DOCS_MCP_TOOL_LIST_PAGE_SIZE = 25;
|
|
23
21
|
const DOCS_MCP_PAGINATION_META_KEY = "dev.farming-labs/pagination";
|
|
22
|
+
const DOCS_MCP_CONTENT_CHANGES_CURRENT_URI = "docs://changes/current";
|
|
23
|
+
const DOCS_MCP_CONTENT_CHANGES_URI_TEMPLATE = "docs://changes/{generation}";
|
|
24
|
+
const DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS = 3e4;
|
|
24
25
|
const UTF8_ENCODER = new TextEncoder();
|
|
25
26
|
const DEFAULT_DOCS_MCP_MAX_BODY_BYTES = 1024 * 1024;
|
|
26
27
|
const DEFAULT_DOCS_MCP_CORS_MAX_AGE_SECONDS = 600;
|
|
@@ -29,6 +30,8 @@ const DEFAULT_DOCS_MCP_CORS_ALLOWED_HEADERS = Object.freeze([
|
|
|
29
30
|
"Authorization",
|
|
30
31
|
"Content-Type",
|
|
31
32
|
"Last-Event-ID",
|
|
33
|
+
"MCP-Method",
|
|
34
|
+
"MCP-Name",
|
|
32
35
|
"MCP-Protocol-Version",
|
|
33
36
|
"MCP-Session-Id"
|
|
34
37
|
]);
|
|
@@ -1568,6 +1571,13 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
|
|
|
1568
1571
|
default: true,
|
|
1569
1572
|
description: "Expose the list_search_facets tool for body-free framework, version, package, and tag discovery."
|
|
1570
1573
|
},
|
|
1574
|
+
{
|
|
1575
|
+
path: "mcp.tools.listContentChanges",
|
|
1576
|
+
name: "listContentChanges",
|
|
1577
|
+
type: "boolean",
|
|
1578
|
+
default: true,
|
|
1579
|
+
description: "Expose list_content_changes polling and docs://changes resources when agent.contentChanges is enabled."
|
|
1580
|
+
},
|
|
1571
1581
|
{
|
|
1572
1582
|
path: "mcp.tools.readPage",
|
|
1573
1583
|
name: "readPage",
|
|
@@ -1880,6 +1890,10 @@ const listDocsInputSchema = z.object({
|
|
|
1880
1890
|
cursor: paginationCursorInputSchema
|
|
1881
1891
|
});
|
|
1882
1892
|
const getNavigationInputSchema = z.object({ locale: z.string().trim().min(1).max(128).optional() });
|
|
1893
|
+
const listContentChangesInputSchema = z.object({
|
|
1894
|
+
since: z.string().refine(isDocsContentChangeGeneration, "Expected a SHA-256 index generation").optional(),
|
|
1895
|
+
locale: z.string().trim().min(1).max(128).optional()
|
|
1896
|
+
});
|
|
1883
1897
|
const getConfigSchemaInputSchema = z.object({
|
|
1884
1898
|
option: z.string().trim().min(1).optional(),
|
|
1885
1899
|
query: z.string().trim().min(1).optional()
|
|
@@ -1987,6 +2001,37 @@ const retrievalSourceScopeOutputSchema = z.object({
|
|
|
1987
2001
|
])).max(4).optional()
|
|
1988
2002
|
});
|
|
1989
2003
|
const retrievalSourceDigestOutputSchema = z.string().regex(/^sha256:[a-f\d]{64}$/iu);
|
|
2004
|
+
const contentChangeDocumentOutputSchema = z.object({
|
|
2005
|
+
url: z.string(),
|
|
2006
|
+
canonicalUrl: z.string().max(4096).refine(isDocsRetrievalCanonicalUrl, "Expected a safe HTTP(S) URL or root-relative path"),
|
|
2007
|
+
digest: retrievalSourceDigestOutputSchema,
|
|
2008
|
+
lastModified: z.string().optional()
|
|
2009
|
+
});
|
|
2010
|
+
const contentChangesOutputSchema = z.object({
|
|
2011
|
+
format: z.literal("docs-content-changes.v1"),
|
|
2012
|
+
audience: z.enum(["human", "agent"]),
|
|
2013
|
+
locale: z.string().optional(),
|
|
2014
|
+
since: retrievalSourceDigestOutputSchema.nullable(),
|
|
2015
|
+
indexGeneration: retrievalSourceDigestOutputSchema,
|
|
2016
|
+
mode: z.enum([
|
|
2017
|
+
"snapshot",
|
|
2018
|
+
"delta",
|
|
2019
|
+
"reset"
|
|
2020
|
+
]),
|
|
2021
|
+
resetRequired: z.boolean(),
|
|
2022
|
+
documentCount: z.number().int().nonnegative(),
|
|
2023
|
+
counts: z.object({
|
|
2024
|
+
added: z.number().int().nonnegative(),
|
|
2025
|
+
changed: z.number().int().nonnegative(),
|
|
2026
|
+
deleted: z.number().int().nonnegative()
|
|
2027
|
+
}),
|
|
2028
|
+
added: z.array(contentChangeDocumentOutputSchema),
|
|
2029
|
+
changed: z.array(contentChangeDocumentOutputSchema.extend({
|
|
2030
|
+
previousDigest: retrievalSourceDigestOutputSchema,
|
|
2031
|
+
previousLastModified: z.string().optional()
|
|
2032
|
+
})),
|
|
2033
|
+
deleted: z.array(contentChangeDocumentOutputSchema)
|
|
2034
|
+
});
|
|
1990
2035
|
const retrievalSourceOutputSchema = z.object({
|
|
1991
2036
|
canonicalUrl: z.string().max(4096).refine(isDocsRetrievalCanonicalUrl, "Expected a safe HTTP(S) URL or root-relative path"),
|
|
1992
2037
|
scope: retrievalSourceScopeOutputSchema,
|
|
@@ -2228,6 +2273,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2228
2273
|
readTask: true,
|
|
2229
2274
|
searchDocs: true,
|
|
2230
2275
|
searchFacets: true,
|
|
2276
|
+
listContentChanges: true,
|
|
2231
2277
|
getNavigation: true,
|
|
2232
2278
|
getCodeExamples: true,
|
|
2233
2279
|
getConfigSchema: true,
|
|
@@ -2250,6 +2296,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
|
|
|
2250
2296
|
readTask: config.tools?.readTask ?? true,
|
|
2251
2297
|
searchDocs: config.tools?.searchDocs ?? true,
|
|
2252
2298
|
searchFacets: config.tools?.searchFacets ?? true,
|
|
2299
|
+
listContentChanges: config.tools?.listContentChanges ?? true,
|
|
2253
2300
|
getNavigation: config.tools?.getNavigation ?? true,
|
|
2254
2301
|
getCodeExamples: config.tools?.getCodeExamples ?? true,
|
|
2255
2302
|
getConfigSchema: config.tools?.getConfigSchema ?? true,
|
|
@@ -2368,6 +2415,54 @@ function nowMs() {
|
|
|
2368
2415
|
function durationMs(startedAt) {
|
|
2369
2416
|
return Math.max(0, Date.now() - startedAt);
|
|
2370
2417
|
}
|
|
2418
|
+
function createDocsMcpContentChangeMonitor(options) {
|
|
2419
|
+
let context;
|
|
2420
|
+
let generation;
|
|
2421
|
+
let timer;
|
|
2422
|
+
let running = false;
|
|
2423
|
+
let closed = false;
|
|
2424
|
+
const schedule = () => {
|
|
2425
|
+
if (closed || timer || running || options.isActive?.() === false) return;
|
|
2426
|
+
timer = setTimeout(async () => {
|
|
2427
|
+
timer = void 0;
|
|
2428
|
+
if (closed || context === void 0 || options.isActive?.() === false) return;
|
|
2429
|
+
running = true;
|
|
2430
|
+
try {
|
|
2431
|
+
const nextGeneration = await options.readGeneration(context);
|
|
2432
|
+
if (generation && nextGeneration !== generation) {
|
|
2433
|
+
generation = nextGeneration;
|
|
2434
|
+
await options.notify();
|
|
2435
|
+
} else generation = nextGeneration;
|
|
2436
|
+
} catch {} finally {
|
|
2437
|
+
running = false;
|
|
2438
|
+
schedule();
|
|
2439
|
+
}
|
|
2440
|
+
}, options.pollIntervalMs);
|
|
2441
|
+
if (options.unrefTimer) timer.unref?.();
|
|
2442
|
+
};
|
|
2443
|
+
return {
|
|
2444
|
+
async start(nextContext) {
|
|
2445
|
+
if (closed) return;
|
|
2446
|
+
context = nextContext;
|
|
2447
|
+
if (timer) {
|
|
2448
|
+
clearTimeout(timer);
|
|
2449
|
+
timer = void 0;
|
|
2450
|
+
}
|
|
2451
|
+
try {
|
|
2452
|
+
generation = await options.readGeneration(nextContext);
|
|
2453
|
+
} catch {
|
|
2454
|
+
generation = void 0;
|
|
2455
|
+
}
|
|
2456
|
+
schedule();
|
|
2457
|
+
},
|
|
2458
|
+
close() {
|
|
2459
|
+
closed = true;
|
|
2460
|
+
context = void 0;
|
|
2461
|
+
if (timer) clearTimeout(timer);
|
|
2462
|
+
timer = void 0;
|
|
2463
|
+
}
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2371
2466
|
function createStructuredTextResult(structuredContent, text) {
|
|
2372
2467
|
return {
|
|
2373
2468
|
content: [{
|
|
@@ -2399,7 +2494,7 @@ function paginateDocsMcpProtocolItems(items, options) {
|
|
|
2399
2494
|
pageSize: DOCS_MCP_PROTOCOL_LIST_PAGE_SIZE
|
|
2400
2495
|
});
|
|
2401
2496
|
} catch (error) {
|
|
2402
|
-
if (error instanceof DocsPaginationCursorError) throw new
|
|
2497
|
+
if (error instanceof DocsPaginationCursorError) throw new ProtocolError(ProtocolErrorCode.InvalidParams, error.message);
|
|
2403
2498
|
throw error;
|
|
2404
2499
|
}
|
|
2405
2500
|
}
|
|
@@ -2430,10 +2525,10 @@ function paginateDocsMcpSdkListResult(result, field, options) {
|
|
|
2430
2525
|
function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
2431
2526
|
const originalSetRequestHandler = server.server.setRequestHandler;
|
|
2432
2527
|
const setRequestHandler = originalSetRequestHandler.bind(server.server);
|
|
2433
|
-
const interceptedSetRequestHandler = ((
|
|
2528
|
+
const interceptedSetRequestHandler = ((method, handler) => {
|
|
2434
2529
|
const sdkHandler = handler;
|
|
2435
|
-
if (
|
|
2436
|
-
setRequestHandler(
|
|
2530
|
+
if (method === "resources/list") {
|
|
2531
|
+
setRequestHandler("resources/list", async (request, extra) => {
|
|
2437
2532
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resources", {
|
|
2438
2533
|
kind: "mcp.protocol/resources-list",
|
|
2439
2534
|
scope,
|
|
@@ -2446,8 +2541,8 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2446
2541
|
});
|
|
2447
2542
|
return;
|
|
2448
2543
|
}
|
|
2449
|
-
if (
|
|
2450
|
-
setRequestHandler(
|
|
2544
|
+
if (method === "resources/templates/list") {
|
|
2545
|
+
setRequestHandler("resources/templates/list", async (request, extra) => {
|
|
2451
2546
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "resourceTemplates", {
|
|
2452
2547
|
kind: "mcp.protocol/resource-templates-list",
|
|
2453
2548
|
scope,
|
|
@@ -2460,8 +2555,8 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2460
2555
|
});
|
|
2461
2556
|
return;
|
|
2462
2557
|
}
|
|
2463
|
-
if (
|
|
2464
|
-
setRequestHandler(
|
|
2558
|
+
if (method === "tools/list") {
|
|
2559
|
+
setRequestHandler("tools/list", async (request, extra) => {
|
|
2465
2560
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "tools", {
|
|
2466
2561
|
kind: "mcp.protocol/tools-list",
|
|
2467
2562
|
scope,
|
|
@@ -2471,8 +2566,8 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2471
2566
|
});
|
|
2472
2567
|
return;
|
|
2473
2568
|
}
|
|
2474
|
-
if (
|
|
2475
|
-
setRequestHandler(
|
|
2569
|
+
if (method === "prompts/list") {
|
|
2570
|
+
setRequestHandler("prompts/list", async (request, extra) => {
|
|
2476
2571
|
return paginateDocsMcpSdkListResult(await sdkHandler(request, extra), "prompts", {
|
|
2477
2572
|
kind: "mcp.protocol/prompts-list",
|
|
2478
2573
|
scope,
|
|
@@ -2482,7 +2577,7 @@ function installDocsMcpSdkListPaginationInterceptor(server, scope) {
|
|
|
2482
2577
|
});
|
|
2483
2578
|
return;
|
|
2484
2579
|
}
|
|
2485
|
-
setRequestHandler(
|
|
2580
|
+
setRequestHandler(method, handler);
|
|
2486
2581
|
});
|
|
2487
2582
|
server.server.setRequestHandler = interceptedSetRequestHandler;
|
|
2488
2583
|
return () => {
|
|
@@ -2499,27 +2594,26 @@ function installDocsMcpSdkRegistrationPagination(server, scope) {
|
|
|
2499
2594
|
}
|
|
2500
2595
|
} });
|
|
2501
2596
|
server.registerTool = wrapRegistration(server.registerTool);
|
|
2502
|
-
server.tool = wrapRegistration(server.tool);
|
|
2503
2597
|
server.registerResource = wrapRegistration(server.registerResource);
|
|
2504
|
-
server.resource = wrapRegistration(server.resource);
|
|
2505
2598
|
server.registerPrompt = wrapRegistration(server.registerPrompt);
|
|
2506
|
-
server.prompt = wrapRegistration(server.prompt);
|
|
2507
2599
|
}
|
|
2508
2600
|
async function createDocsMcpServer(options) {
|
|
2509
2601
|
const resolved = resolveDocsMcpConfig(options.mcp, {
|
|
2510
2602
|
defaultName: options.defaultName ?? options.source.siteTitle ?? DEFAULT_MCP_NAME,
|
|
2511
2603
|
defaultVersion: options.defaultVersion
|
|
2512
2604
|
});
|
|
2513
|
-
const toolSearchConfig =
|
|
2605
|
+
const toolSearchConfig = resolveLocalDocsMcpSearchConfig(options.search, options.mcp, options.requestContext?.request?.url);
|
|
2514
2606
|
const protocolScope = stableDocsMcpPaginationScope({
|
|
2515
2607
|
name: resolved.name,
|
|
2516
2608
|
version: resolved.version
|
|
2517
2609
|
});
|
|
2610
|
+
const contentChangesEnabled = resolveDocsContentChangesConfig(options.contentChanges).enabled && resolved.tools.listContentChanges !== false;
|
|
2518
2611
|
const server = new McpServer({
|
|
2519
2612
|
name: resolved.name,
|
|
2520
2613
|
version: resolved.version
|
|
2521
2614
|
});
|
|
2522
2615
|
installDocsMcpSdkRegistrationPagination(server, protocolScope);
|
|
2616
|
+
if (contentChangesEnabled) server.server.registerCapabilities({ resources: { subscribe: true } });
|
|
2523
2617
|
const registerResource = (name, uri, metadata, callback) => {
|
|
2524
2618
|
return server.registerResource(name, uri, metadata, callback);
|
|
2525
2619
|
};
|
|
@@ -2556,6 +2650,26 @@ async function createDocsMcpServer(options) {
|
|
|
2556
2650
|
const defaultPages = dedupePages(await getSourcePages());
|
|
2557
2651
|
const defaultTree = await getSourceNavigation();
|
|
2558
2652
|
const defaultSkills = await getSourceSkills();
|
|
2653
|
+
const contentChangeFeed = options.contentChangeFeed ?? createDocsContentChangeFeed(options.contentChanges);
|
|
2654
|
+
async function resolveContentChanges(since, locale) {
|
|
2655
|
+
if (!contentChangesEnabled) throw new ProtocolError(ProtocolErrorCode.MethodNotFound, "Content changes are disabled.");
|
|
2656
|
+
if (since && !isDocsContentChangeGeneration(since)) throw new ProtocolError(ProtocolErrorCode.InvalidParams, "Content-change `since` must be a SHA-256 index generation.");
|
|
2657
|
+
const resolvedLocale = resolveSourceLocale(locale);
|
|
2658
|
+
try {
|
|
2659
|
+
return await contentChangeFeed.resolve({
|
|
2660
|
+
pages: toSearchSourcePages(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext))),
|
|
2661
|
+
search: options.search,
|
|
2662
|
+
audience: "agent",
|
|
2663
|
+
locale: resolvedLocale,
|
|
2664
|
+
baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0),
|
|
2665
|
+
...since ? { since } : {},
|
|
2666
|
+
...options.requestContext?.request ? { request: options.requestContext.request.clone() } : {}
|
|
2667
|
+
});
|
|
2668
|
+
} catch (error) {
|
|
2669
|
+
if (error instanceof DocsContentChangesRequestError) throw new ProtocolError(ProtocolErrorCode.InvalidParams, error.message);
|
|
2670
|
+
throw error;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2559
2673
|
registerResource("docs-navigation", "docs://navigation", {
|
|
2560
2674
|
title: "Docs Navigation",
|
|
2561
2675
|
description: "Structured navigation tree for the documentation site.",
|
|
@@ -2565,6 +2679,65 @@ async function createDocsMcpServer(options) {
|
|
|
2565
2679
|
mimeType: "text/plain",
|
|
2566
2680
|
text: renderNavigationTree(defaultTree)
|
|
2567
2681
|
}] }));
|
|
2682
|
+
if (contentChangesEnabled) {
|
|
2683
|
+
const readChanges = async (generation) => {
|
|
2684
|
+
const result = await resolveContentChanges(generation && generation !== "current" ? generation : void 0);
|
|
2685
|
+
return { contents: [{
|
|
2686
|
+
uri: generation && generation !== "current" ? `docs://changes/${generation}` : DOCS_MCP_CONTENT_CHANGES_CURRENT_URI,
|
|
2687
|
+
mimeType: "application/json",
|
|
2688
|
+
text: JSON.stringify(result, null, 2)
|
|
2689
|
+
}] };
|
|
2690
|
+
};
|
|
2691
|
+
registerResource("docs-content-changes-current", DOCS_MCP_CONTENT_CHANGES_CURRENT_URI, {
|
|
2692
|
+
title: "Current docs content changes",
|
|
2693
|
+
description: "Stable subscription target for body-free documentation change notifications.",
|
|
2694
|
+
mimeType: "application/json"
|
|
2695
|
+
}, async () => readChanges());
|
|
2696
|
+
server.registerResource("docs-content-changes-by-generation", new ResourceTemplate(DOCS_MCP_CONTENT_CHANGES_URI_TEMPLATE, { list: async () => {
|
|
2697
|
+
return { resources: [{
|
|
2698
|
+
uri: `docs://changes/${(await resolveContentChanges()).indexGeneration}`,
|
|
2699
|
+
name: "Docs changes from current generation",
|
|
2700
|
+
title: "Docs changes from current generation",
|
|
2701
|
+
description: "Read this URI later to retrieve changes since the listed generation.",
|
|
2702
|
+
mimeType: "application/json"
|
|
2703
|
+
}] };
|
|
2704
|
+
} }), {
|
|
2705
|
+
title: "Docs content changes by generation",
|
|
2706
|
+
description: "Body-free documentation changes from a SHA-256 index generation to the current generation.",
|
|
2707
|
+
mimeType: "application/json"
|
|
2708
|
+
}, async (_uri, variables) => {
|
|
2709
|
+
const generation = variables.generation;
|
|
2710
|
+
if (typeof generation !== "string" || !isDocsContentChangeGeneration(generation)) throw new ProtocolError(ProtocolErrorCode.InvalidParams, "Change resource generation must be a SHA-256 index generation.");
|
|
2711
|
+
return readChanges(generation);
|
|
2712
|
+
});
|
|
2713
|
+
registerTool("list_content_changes", {
|
|
2714
|
+
title: "List docs content changes",
|
|
2715
|
+
description: "Synchronize body-free document metadata. Save indexGeneration and pass it as since on the next poll. A reset response means the named snapshot is no longer available.",
|
|
2716
|
+
inputSchema: listContentChangesInputSchema,
|
|
2717
|
+
outputSchema: contentChangesOutputSchema,
|
|
2718
|
+
annotations: { readOnlyHint: true }
|
|
2719
|
+
}, async ({ since, locale }) => {
|
|
2720
|
+
const startedAt = nowMs();
|
|
2721
|
+
const result = await resolveContentChanges(since, locale);
|
|
2722
|
+
trackMcpTool("list_content_changes", {
|
|
2723
|
+
locale,
|
|
2724
|
+
resultCount: result.counts.added + result.counts.changed + result.counts.deleted
|
|
2725
|
+
});
|
|
2726
|
+
await emitDocsAnalyticsEvent(options.analytics, {
|
|
2727
|
+
type: "mcp_tool",
|
|
2728
|
+
source: "mcp",
|
|
2729
|
+
locale,
|
|
2730
|
+
properties: {
|
|
2731
|
+
tool: "list_content_changes",
|
|
2732
|
+
mode: result.mode,
|
|
2733
|
+
resetRequired: result.resetRequired,
|
|
2734
|
+
resultCount: result.counts.added + result.counts.changed + result.counts.deleted,
|
|
2735
|
+
durationMs: durationMs(startedAt)
|
|
2736
|
+
}
|
|
2737
|
+
});
|
|
2738
|
+
return createStructuredTextResult(result);
|
|
2739
|
+
});
|
|
2740
|
+
}
|
|
2568
2741
|
for (const page of defaultPages) {
|
|
2569
2742
|
const resourceUri = toPageResourceUri(page.url);
|
|
2570
2743
|
registerResource(`page-${slugToKey(page.slug)}`, resourceUri, {
|
|
@@ -4051,20 +4224,48 @@ function createDocsMcpHttpHandler(options) {
|
|
|
4051
4224
|
data: { reason: "mcp_disabled" }
|
|
4052
4225
|
}),
|
|
4053
4226
|
DELETE: async () => createJsonErrorResponse(404, disabledMessage),
|
|
4054
|
-
OPTIONS: async () => createJsonErrorResponse(404, disabledMessage)
|
|
4227
|
+
OPTIONS: async () => createJsonErrorResponse(404, disabledMessage),
|
|
4228
|
+
close: async () => {}
|
|
4055
4229
|
};
|
|
4056
|
-
|
|
4057
|
-
|
|
4230
|
+
const contentChangesEnabled = resolveDocsContentChangesConfig(options.contentChanges).enabled && resolved.tools.listContentChanges !== false;
|
|
4231
|
+
const contentChangeFeed = options.contentChangeFeed ?? createDocsContentChangeFeed(options.contentChanges);
|
|
4232
|
+
const eventBus = new InMemoryServerEventBus();
|
|
4233
|
+
const mcpHandler = createMcpHandler(async (context) => {
|
|
4234
|
+
const internalAuth = context.authInfo;
|
|
4235
|
+
return createDocsMcpServer({
|
|
4058
4236
|
...options,
|
|
4059
|
-
|
|
4237
|
+
contentChangeFeed,
|
|
4238
|
+
requestContext: {
|
|
4239
|
+
transport: "http",
|
|
4240
|
+
...context.requestInfo ? { request: context.requestInfo.clone() } : {},
|
|
4241
|
+
...internalAuth?.principal ? { auth: internalAuth.principal } : {}
|
|
4242
|
+
}
|
|
4060
4243
|
});
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4244
|
+
}, {
|
|
4245
|
+
legacy: "stateless",
|
|
4246
|
+
bus: eventBus
|
|
4247
|
+
});
|
|
4248
|
+
const configuredPollInterval = options.contentChangePollIntervalMs;
|
|
4249
|
+
const contentChangePollIntervalMs = typeof configuredPollInterval === "number" && Number.isFinite(configuredPollInterval) && configuredPollInterval >= 10 ? Math.floor(configuredPollInterval) : DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS;
|
|
4250
|
+
async function readMonitoredGeneration(context) {
|
|
4251
|
+
const locale = options.source.resolveLocale?.(void 0, context);
|
|
4252
|
+
const pages = dedupePages(await options.source.getPages(locale, context));
|
|
4253
|
+
return (await contentChangeFeed.resolve({
|
|
4254
|
+
pages: toSearchSourcePages(pages),
|
|
4255
|
+
search: options.search,
|
|
4256
|
+
audience: "agent",
|
|
4257
|
+
locale,
|
|
4258
|
+
baseUrl: options.source.baseUrl ?? (context.request ? new URL(context.request.url).origin : void 0),
|
|
4259
|
+
...context.request ? { request: context.request.clone() } : {}
|
|
4260
|
+
})).indexGeneration;
|
|
4067
4261
|
}
|
|
4262
|
+
const contentChangeMonitor = createDocsMcpContentChangeMonitor({
|
|
4263
|
+
pollIntervalMs: contentChangePollIntervalMs,
|
|
4264
|
+
readGeneration: readMonitoredGeneration,
|
|
4265
|
+
notify: () => mcpHandler.notify.resourceUpdated(DOCS_MCP_CONTENT_CHANGES_CURRENT_URI),
|
|
4266
|
+
isActive: () => eventBus.listenerCount > 0,
|
|
4267
|
+
unrefTimer: true
|
|
4268
|
+
});
|
|
4068
4269
|
async function handle(request) {
|
|
4069
4270
|
const originalUrl = new URL(request.url);
|
|
4070
4271
|
const method = request.method.toUpperCase();
|
|
@@ -4147,26 +4348,77 @@ function createDocsMcpHttpHandler(options) {
|
|
|
4147
4348
|
code: -32700,
|
|
4148
4349
|
message: "Parse error: Invalid JSON"
|
|
4149
4350
|
}));
|
|
4150
|
-
|
|
4351
|
+
const requestContext = {
|
|
4151
4352
|
transport: "http",
|
|
4152
4353
|
request: request.clone(),
|
|
4153
4354
|
auth
|
|
4154
|
-
}
|
|
4355
|
+
};
|
|
4356
|
+
const isContentChangeSubscription = contentChangesEnabled && method === "POST" && typeof parsedBody === "object" && parsedBody !== null && !Array.isArray(parsedBody) && parsedBody.method === "subscriptions/listen";
|
|
4357
|
+
const authInfo = auth ? {
|
|
4358
|
+
token: "",
|
|
4359
|
+
clientId: auth.id,
|
|
4360
|
+
scopes: auth.scopes ?? [],
|
|
4361
|
+
principal: auth
|
|
4362
|
+
} : void 0;
|
|
4363
|
+
const response = await mcpHandler.fetch(request, {
|
|
4364
|
+
...parsedBody === void 0 ? {} : { parsedBody },
|
|
4365
|
+
...authInfo ? { authInfo } : {}
|
|
4366
|
+
});
|
|
4367
|
+
if (isContentChangeSubscription) await contentChangeMonitor.start(requestContext);
|
|
4368
|
+
return withCors(response);
|
|
4155
4369
|
}
|
|
4156
4370
|
return {
|
|
4157
4371
|
GET: async ({ request }) => handle(request),
|
|
4158
4372
|
POST: async ({ request }) => handle(request),
|
|
4159
4373
|
DELETE: async ({ request }) => handle(request),
|
|
4160
|
-
OPTIONS: async ({ request }) => handle(request)
|
|
4374
|
+
OPTIONS: async ({ request }) => handle(request),
|
|
4375
|
+
close: async () => {
|
|
4376
|
+
contentChangeMonitor.close();
|
|
4377
|
+
await mcpHandler.close();
|
|
4378
|
+
}
|
|
4161
4379
|
};
|
|
4162
4380
|
}
|
|
4163
4381
|
async function runDocsMcpStdio(options) {
|
|
4164
|
-
const
|
|
4165
|
-
|
|
4166
|
-
|
|
4382
|
+
const resolved = resolveDocsMcpConfig(options.mcp, {
|
|
4383
|
+
defaultName: options.defaultName ?? options.source.siteTitle ?? DEFAULT_MCP_NAME,
|
|
4384
|
+
defaultVersion: options.defaultVersion
|
|
4385
|
+
});
|
|
4386
|
+
const contentChangesEnabled = resolveDocsContentChangesConfig(options.contentChanges).enabled && resolved.tools.listContentChanges !== false;
|
|
4387
|
+
const contentChangeFeed = options.contentChangeFeed ?? createDocsContentChangeFeed(options.contentChanges);
|
|
4388
|
+
const configuredPollInterval = options.contentChangePollIntervalMs;
|
|
4389
|
+
const pollIntervalMs = typeof configuredPollInterval === "number" && Number.isFinite(configuredPollInterval) && configuredPollInterval >= 10 ? Math.floor(configuredPollInterval) : DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS;
|
|
4390
|
+
serveStdio(async () => {
|
|
4391
|
+
const requestContext = { transport: "stdio" };
|
|
4392
|
+
const server = await createDocsMcpServer({
|
|
4393
|
+
...options,
|
|
4394
|
+
contentChangeFeed,
|
|
4395
|
+
requestContext
|
|
4396
|
+
});
|
|
4397
|
+
if (!contentChangesEnabled) return server;
|
|
4398
|
+
const readGeneration = async () => {
|
|
4399
|
+
const locale = options.source.resolveLocale?.(void 0, requestContext);
|
|
4400
|
+
const pages = dedupePages(await options.source.getPages(locale, requestContext));
|
|
4401
|
+
return (await contentChangeFeed.resolve({
|
|
4402
|
+
pages: toSearchSourcePages(pages),
|
|
4403
|
+
search: options.search,
|
|
4404
|
+
audience: "agent",
|
|
4405
|
+
locale,
|
|
4406
|
+
baseUrl: options.source.baseUrl
|
|
4407
|
+
})).indexGeneration;
|
|
4408
|
+
};
|
|
4409
|
+
const monitor = createDocsMcpContentChangeMonitor({
|
|
4410
|
+
pollIntervalMs,
|
|
4411
|
+
readGeneration: () => readGeneration(),
|
|
4412
|
+
notify: () => server.server.sendResourceUpdated({ uri: DOCS_MCP_CONTENT_CHANGES_CURRENT_URI })
|
|
4413
|
+
});
|
|
4414
|
+
await monitor.start(requestContext);
|
|
4415
|
+
const closeServer = server.close.bind(server);
|
|
4416
|
+
server.close = async () => {
|
|
4417
|
+
monitor.close();
|
|
4418
|
+
await closeServer();
|
|
4419
|
+
};
|
|
4420
|
+
return server;
|
|
4167
4421
|
});
|
|
4168
|
-
const transport = new StdioServerTransport();
|
|
4169
|
-
await server.connect(transport);
|
|
4170
4422
|
}
|
|
4171
4423
|
async function isDocsMcpOriginAllowed(request, allowedOrigins) {
|
|
4172
4424
|
const origin = request.headers.get("origin");
|
|
@@ -4766,22 +5018,6 @@ function countConfigSchemaOptions(options) {
|
|
|
4766
5018
|
function normalizeConfigSchemaToken(value) {
|
|
4767
5019
|
return value.trim().toLowerCase().replace(/^docs\.config\.?/, "").replace(/[`'"]/g, "").replace(/[_\-\s]+/g, "");
|
|
4768
5020
|
}
|
|
4769
|
-
function isSelfMcpSearchEndpoint(search, route) {
|
|
4770
|
-
if (!search || search === true || typeof search !== "object" || search.provider !== "mcp") return false;
|
|
4771
|
-
const endpoint = search.endpoint.trim();
|
|
4772
|
-
if (!endpoint.startsWith("/")) return false;
|
|
4773
|
-
return normalizeDocsMcpRoute(endpoint) === normalizeDocsMcpRoute(route);
|
|
4774
|
-
}
|
|
4775
|
-
function resolveMcpToolSearchConfig(search, route) {
|
|
4776
|
-
if (!isSelfMcpSearchEndpoint(search, route)) return search;
|
|
4777
|
-
const config = search;
|
|
4778
|
-
return {
|
|
4779
|
-
provider: "simple",
|
|
4780
|
-
enabled: config.enabled,
|
|
4781
|
-
maxResults: config.maxResults,
|
|
4782
|
-
chunking: config.chunking
|
|
4783
|
-
};
|
|
4784
|
-
}
|
|
4785
5021
|
function toAgentContractSummary(value) {
|
|
4786
5022
|
const agent = normalizePageAgentFrontmatter(value);
|
|
4787
5023
|
const hasContract = hasStructuredPageAgentContract(agent);
|
|
@@ -5607,4 +5843,4 @@ function toPageResourceUri(url) {
|
|
|
5607
5843
|
}
|
|
5608
5844
|
|
|
5609
5845
|
//#endregion
|
|
5610
|
-
export { DEFAULT_DOCS_MCP_CORS_ALLOWED_HEADERS, DEFAULT_DOCS_MCP_CORS_EXPOSED_HEADERS, DEFAULT_DOCS_MCP_CORS_MAX_AGE_SECONDS, DEFAULT_DOCS_MCP_MAX_BODY_BYTES, DOCS_CONFIG_SCHEMA_OPTIONS, buildDocsMcpContext, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, getDocsConfigSchema, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio };
|
|
5846
|
+
export { DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS, DEFAULT_DOCS_MCP_CORS_ALLOWED_HEADERS, DEFAULT_DOCS_MCP_CORS_EXPOSED_HEADERS, DEFAULT_DOCS_MCP_CORS_MAX_AGE_SECONDS, DEFAULT_DOCS_MCP_MAX_BODY_BYTES, DOCS_CONFIG_SCHEMA_OPTIONS, DOCS_MCP_CONTENT_CHANGES_CURRENT_URI, DOCS_MCP_CONTENT_CHANGES_URI_TEMPLATE, buildDocsMcpContext, createDocsMcpHttpHandler, createDocsMcpServer, createFilesystemDocsMcpSource, getDocsConfigSchema, normalizeDocsMcpRoute, resolveDocsMcpConfig, runDocsMcpStdio };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { At as DEFAULT_SITEMAP_XML_ROUTE, Ot as DEFAULT_SITEMAP_MD_ROUTE,
|
|
1
|
+
import { At as DEFAULT_SITEMAP_XML_ROUTE, Ot as DEFAULT_SITEMAP_MD_ROUTE, Un as DEFAULT_MCP_WELL_KNOWN_ROUTE, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, f as DEFAULT_DOCS_CONFIG_ROUTE, h as DEFAULT_LLMS_FULL_TXT_ROUTE, i as DEFAULT_AGENT_FEEDBACK_ROUTE, m as DEFAULT_DOCS_DIAGNOSTICS_ROUTE, t as DEFAULT_AGENTS_MD_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, x as DEFAULT_SKILL_MD_ROUTE } from "./agent-Cj50nyeV.mjs";
|
|
2
2
|
import { isDocsAgentSkillName, validateDocsAgentSkillFrontmatter } from "./agent-skills-spec.mjs";
|
|
3
3
|
import { C as DOCS_AGENT_MANIFEST_SCHEMA_MEDIA_TYPE, S as DOCS_AGENT_MANIFEST_FORMAT, T as DOCS_AGENT_MANIFEST_VERSION, f as DEFAULT_AGENT_SKILLS_ROUTE_PREFIX, n as API_CATALOG_MEDIA_TYPE, r as API_CATALOG_PROFILE_URI, t as AGENT_SKILLS_DISCOVERY_SCHEMA_URI, u as DEFAULT_AGENT_SKILLS_INDEX_ROUTE, v as DEFAULT_API_CATALOG_ROUTE, w as DOCS_AGENT_MANIFEST_SCHEMA_URI } from "./standards-discovery-BKlEnK_H.mjs";
|
|
4
|
-
import { n as DEFAULT_ROBOTS_TXT_ROUTE } from "./robots-
|
|
4
|
+
import { n as DEFAULT_ROBOTS_TXT_ROUTE } from "./robots-BukukxNm.mjs";
|
|
5
5
|
import matter from "gray-matter";
|
|
6
6
|
|
|
7
7
|
//#region src/define-docs.ts
|