Skip to content

Commit adc707c

Browse files
authored
fix(docs): curate LLM exports and correct authentication guidance (#1734)
## Problem and change The documentation LLM index advertised 71 unpublished pages that returned 404, while the full export included internal research, plans and historical investigations. Share the HTML publication allowlist/exclusions with the LLM plugin so both exports contain only published docs. The resulting index contains 129 links, all matched to Docusaurus metadata and generated HTML. Correct the MCP authentication reference to distinguish optional local HTTP auth, compatibility admin access for anonymous callers, enforced auth, Server edition and OS-authenticated local transports. Replace the homepage's overclaiming diagram with an accessible SVG stating the limits of protection. Add descriptions to seven category pages, exclude noindexed search from the sitemap, and publish robots.txt with the sitemap location. ## Validation - `npm ci --no-audit --no-fund` - `npm run build` — production build and automatic postbuild validation passed. - New verifier reproduced the original defect: `LLM export links to unpublished page: https://docs.mcpproxy.app/docs/E2E_TESTING`. - Fixed output: `Verified 129 published LLM links, full-export regression markers, category metadata, sitemap and robots.txt.` - Mutation checks rejected an injected unpublished URL and internal workflow marker; generated files restored and verifier passed again. - Browser inspection confirmed the SVG and authentication table render correctly. - Independent fresh-context review: `VERDICT: PASS` after correcting the anonymous-admin compatibility wording. No remaining actionable findings. The postbuild gate runs through the existing PR, main deployment and release `npm run build` paths. Runtime behavior is unchanged. Broader navigation and per-page Markdown work remain outside this PR. ## Deployed preview [Cloudflare preview](https://68e931e9.mcpproxy-docs.pages.dev/) verified live: all 129 exported routes load; the full export excludes the known internal-note regression markers; the auth matrix, replacement SVG, sitemap and robots declaration are present. Full export is approximately 1.43 MB, down from 3.04 MB in the audited production snapshot. The publication arrays remain literal in `docusaurus.config.js` for the existing release-gate parser, while both builders reference that same object. Reproduced the three parser failures from the first CI run, fixed compatibility, and passed `go test ./cmd/release-gate -count=1`, a fresh production docs build, and independent follow-up review (`VERDICT: PASS`).
1 parent 97c8c8f commit adc707c

8 files changed

Lines changed: 129 additions & 47 deletions

File tree

‎docs/api/mcp-protocol.md‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,23 @@ Each routing mode has a dedicated endpoint that is always available regardless o
3434

3535
See [Routing Modes](../features/routing-modes.md) for details on each mode.
3636

37-
**Note:** MCP endpoints do not require API key authentication for client compatibility.
37+
### Authentication
38+
39+
Authentication depends on the deployment and transport:
40+
41+
| Surface | Authentication |
42+
| --- | --- |
43+
| Local MCP over HTTP, default configuration | Authentication is optional (`require_mcp_auth: false`). Anonymous callers retain admin-level tool and management access for compatibility, subject to enabled tools and configuration gates; they cannot use the opt-in raw secret-header reveal. |
44+
| MCP over HTTP with `require_mcp_auth: true` | Requires a valid credential, such as an admin API key or a scoped agent token. Enable this before exposing MCP beyond localhost. |
45+
| Server edition with `server_edition.enabled: true` | Forces MCP authentication on, even if `require_mcp_auth` is explicitly false. |
46+
| REST API over HTTP | Requires authentication independently of `require_mcp_auth`. |
47+
| Local Unix socket / Windows named pipe | Uses OS-level access control; trusted local connections do not need an API key. |
48+
49+
See [configuration defaults](/configuration/config-file#server-settings),
50+
[agent tokens and MCP authentication](/features/agent-tokens#enforcing-authentication-on-mcp),
51+
[REST authentication](/api/rest-api#authentication), and
52+
[Server edition authentication](/development/server-edition-multiuser-auth)
53+
for credential formats and access rules.
3854

3955
## Built-in Tools
4056

‎docs/intro.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ keywords: [mcp, proxy, ai agents, tool discovery, security, docker]
1212

1313
**A smart proxy for AI agents using the Model Context Protocol (MCP)**
1414

15-
![MCPProxy Architecture](/img/mcpproxy-architecture.jpeg)
15+
![AI clients connect to MCPProxy, which discovers tools across upstream MCP servers. Review and isolation controls reduce risk but do not guarantee safety.](/img/mcpproxy-architecture.svg)
1616

1717
## What is MCPProxy?
1818

‎website/docusaurus.config.js‎

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@
33

44
const {themes: prismThemes} = require('prism-react-renderer');
55

6+
// Shared publication boundary for HTML pages and both LLM exports.
7+
// Keep internal research, plans and QA notes outside these patterns.
8+
// Keep these literal lists here: cmd/release-gate also reads them to guard
9+
// claims and links across every published page.
10+
const publishedDocs = {
11+
include: [
12+
'intro.md',
13+
'getting-started/**/*.{md,mdx}',
14+
'configuration/**/*.{md,mdx}',
15+
'cli/**/*.{md,mdx}',
16+
'api/**/*.{md,mdx}',
17+
'web-ui/**/*.{md,mdx}',
18+
'features/**/*.{md,mdx}',
19+
'code_execution/**/*.{md,mdx}',
20+
'operations/**/*.{md,mdx}',
21+
'errors/**/*.{md,mdx}',
22+
'development/**/*.{md,mdx}',
23+
'contributing.md',
24+
// Standalone references with no structured counterpart
25+
'cli-client-mode.md',
26+
'cli-output-formatting.md',
27+
'logging.md',
28+
'prerelease-builds.md',
29+
'registries.md',
30+
'socket-communication.md',
31+
],
32+
exclude: [
33+
'development/sandbox-snap-docker-harness.md',
34+
'development/sandbox-spike-mcp-34.md',
35+
],
36+
};
37+
638
/** @type {import('@docusaurus/types').Config} */
739
// Version shown in the navbar badge. Supplied by CI: docs.yml derives it from
840
// the latest stable release tag reachable from main, and release.yml's
@@ -53,35 +85,11 @@ const config = {
5385
routeBasePath: '/', // docs at root
5486
sidebarPath: './sidebars.js',
5587
editUrl: 'https://github.com/smart-mcp-proxy/mcpproxy-go/edit/main/',
56-
// Only include structured documentation pages
57-
include: [
58-
'intro.md',
59-
'getting-started/**/*.{md,mdx}',
60-
'configuration/**/*.{md,mdx}',
61-
'cli/**/*.{md,mdx}',
62-
'api/**/*.{md,mdx}',
63-
'web-ui/**/*.{md,mdx}',
64-
'features/**/*.{md,mdx}',
65-
'code_execution/**/*.{md,mdx}',
66-
'operations/**/*.{md,mdx}',
67-
'errors/**/*.{md,mdx}',
68-
'development/**/*.{md,mdx}',
69-
'contributing.md',
70-
// Standalone references with no structured counterpart
71-
'cli-client-mode.md',
72-
'cli-output-formatting.md',
73-
'logging.md',
74-
'prerelease-builds.md',
75-
'registries.md',
76-
'socket-communication.md',
77-
],
78-
// Internal working documents that live in the repo but are not published
79-
exclude: [
80-
'development/sandbox-snap-docker-harness.md',
81-
'development/sandbox-spike-mcp-34.md',
82-
],
88+
include: publishedDocs.include,
89+
exclude: publishedDocs.exclude,
8390
},
8491
blog: false,
92+
sitemap: { ignorePatterns: ['/search'] },
8593
theme: {
8694
customCss: './src/css/custom.css',
8795
},
@@ -97,16 +105,10 @@ const config = {
97105
generateLLMsFullTxt: true,
98106
excludeImports: true,
99107
removeDuplicateHeadings: true,
100-
includeOrder: [
101-
'getting-started/*',
102-
'configuration/*',
103-
'cli/*',
104-
'api/*',
105-
'web-ui/*',
106-
'features/*',
107-
'code_execution/*',
108-
'operations/*',
109-
],
108+
docsDir: [{ path: 'docs', routeBasePath: '/' }],
109+
includeOrder: publishedDocs.include,
110+
includeUnmatchedLast: false,
111+
ignoreFiles: publishedDocs.exclude,
110112
},
111113
],
112114
],

‎website/package.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
"clear": "docusaurus clear",
1212
"serve": "docusaurus serve",
1313
"write-translations": "docusaurus write-translations",
14-
"write-heading-ids": "docusaurus write-heading-ids"
14+
"write-heading-ids": "docusaurus write-heading-ids",
15+
"postbuild": "node scripts/verify-docs-build.js",
16+
"verify:build": "node scripts/verify-docs-build.js"
1517
},
1618
"dependencies": {
1719
"@docusaurus/core": "^3.10.2",
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env node
2+
// Verify the actual generated artifacts, not just the source glob settings.
3+
const assert = require('node:assert/strict');
4+
const fs = require('node:fs');
5+
const path = require('node:path');
6+
7+
const siteDir = path.resolve(__dirname, '..');
8+
const buildDir = path.join(siteDir, 'build');
9+
const metadataDir = path.join(siteDir, '.docusaurus/docusaurus-plugin-content-docs/default');
10+
const normalize = value => new URL(value, 'https://docs.mcpproxy.app').pathname.replace(/\/$/, '') || '/';
11+
const read = file => fs.readFileSync(path.join(buildDir, file), 'utf8');
12+
const metadata = fs.readdirSync(metadataDir)
13+
.filter(file => file.endsWith('.json') && !file.startsWith('__'))
14+
.map(file => JSON.parse(fs.readFileSync(path.join(metadataDir, file), 'utf8')))
15+
.filter(doc => doc.source && doc.permalink && !doc.draft && !doc.unlisted);
16+
assert(metadata.length > 0, 'No published document metadata found');
17+
const published = new Set(metadata.map(doc => normalize(doc.permalink)));
18+
const index = read('llms.txt');
19+
const links = [...index.matchAll(/^- \[[^\n]*\]\((https:\/\/docs\.mcpproxy\.app[^)\s]*)\)/gm)].map(match => match[1]);
20+
assert(links.length > 0, 'LLM index is empty');
21+
const exported = new Set();
22+
for (const link of links) {
23+
const route = normalize(link);
24+
assert(published.has(route), `LLM export links to unpublished page: ${link}`);
25+
assert(!exported.has(route), `Duplicate LLM export route: ${link}`);
26+
exported.add(route);
27+
const relative = route.replace(/^\//, '');
28+
assert([path.join(buildDir, relative, 'index.html'), path.join(buildDir, `${relative}.html`)]
29+
.some(file => fs.existsSync(file)), `LLM export has no built HTML page: ${link}`);
30+
}
31+
assert.deepEqual([...exported].sort(), [...published].sort(), 'LLM index must cover every published document');
32+
const full = read('llms-full.txt');
33+
assert(full.length > index.length, 'Full LLM export is empty or incomplete');
34+
// Regressions from the original export: excluded docs had no HTML routes but
35+
// their bodies (including agent workflow instructions) appeared in llms-full.
36+
for (const marker of [
37+
'CRITICAL SECURITY VULNERABILITY: Skipped API Key Tests',
38+
'REQUIRED SUB-SKILL:',
39+
'TPA Scanner: Inline Findings & Background Scanning — Authoritative Design',
40+
]) {
41+
assert(!full.includes(marker), `Unpublished content in full LLM export: ${marker}`);
42+
}
43+
assert(!/<loc>https:\/\/docs\.mcpproxy\.app\/search\/?<\/loc>/.test(read('sitemap.xml')), 'Noindexed search page is in sitemap');
44+
assert(read('robots.txt').includes('Sitemap: https://docs.mcpproxy.app/sitemap.xml'), 'robots.txt is missing sitemap declaration');
45+
for (const category of ['getting-started', 'configuration', 'cli', 'api', 'web-ui', 'features', 'operations']) {
46+
const html = fs.existsSync(path.join(buildDir, category, 'index.html')) ? read(`${category}/index.html`) : read(`${category}.html`);
47+
assert(/<meta[^>]*name="description"[^>]*content="[^"]+"/.test(html), `Missing category description: ${category}`);
48+
}
49+
console.log(`Verified ${exported.size} published LLM links, full-export regression markers, category metadata, sitemap and robots.txt.`);

‎website/sidebars.js‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const sidebars = {
2424
// reads _category_.json for AUTOGENERATED sidebars. Without this the
2525
// /getting-started URL 404s, which is where the marketing site's
2626
// "Getting Started" card used to land.
27-
link: { type: 'generated-index', slug: '/getting-started' },
27+
link: { type: 'generated-index', slug: '/getting-started', description: 'Install MCPProxy and make your first successful MCP tool call.' },
2828
items: [
2929
'getting-started/installation',
3030
'getting-started/quick-start',
@@ -34,7 +34,7 @@ const sidebars = {
3434
type: 'category',
3535
label: 'Configuration',
3636
// See the note on Getting Started above — same reason.
37-
link: { type: 'generated-index', slug: '/configuration' },
37+
link: { type: 'generated-index', slug: '/configuration', description: 'Configure MCPProxy, upstream servers, environment variables and sensitive data detection.' },
3838
items: [
3939
'configuration/config-file',
4040
'configuration/upstream-servers',
@@ -45,7 +45,7 @@ const sidebars = {
4545
{
4646
type: 'category',
4747
label: 'CLI',
48-
link: { type: 'generated-index', slug: '/cli' },
48+
link: { type: 'generated-index', slug: '/cli', description: 'Manage MCPProxy servers, profiles, security reviews and activity from the command line.' },
4949
items: [
5050
'cli/command-reference',
5151
'cli/management-commands',
@@ -66,7 +66,7 @@ const sidebars = {
6666
{
6767
type: 'category',
6868
label: 'API',
69-
link: { type: 'generated-index', slug: '/api' },
69+
link: { type: 'generated-index', slug: '/api', description: 'Integrate with the MCPProxy REST API and MCP protocol endpoints.' },
7070
items: [
7171
'api/rest-api',
7272
'api/mcp-protocol',
@@ -75,7 +75,7 @@ const sidebars = {
7575
{
7676
type: 'category',
7777
label: 'Web UI',
78-
link: { type: 'generated-index', slug: '/web-ui' },
78+
link: { type: 'generated-index', slug: '/web-ui', description: 'Use the MCPProxy dashboard to manage servers, settings and activity.' },
7979
items: [
8080
'web-ui/dashboard',
8181
'web-ui/server-detail',
@@ -86,7 +86,7 @@ const sidebars = {
8686
{
8787
type: 'category',
8888
label: 'Features',
89-
link: { type: 'generated-index', slug: '/features' },
89+
link: { type: 'generated-index', slug: '/features', description: 'Explore tool discovery, routing, client connections and security controls.' },
9090
items: [
9191
'features/routing-modes',
9292
'features/schema-deferred-direct-mode',
@@ -156,7 +156,7 @@ const sidebars = {
156156
{
157157
type: 'category',
158158
label: 'Operations',
159-
link: { type: 'generated-index', slug: '/operations' },
159+
link: { type: 'generated-index', slug: '/operations', description: 'Deploy, monitor and maintain MCPProxy locally or for a team.' },
160160
items: [
161161
'operations/reverse-proxy',
162162
'operations/deploying-for-a-team',
Lines changed: 9 additions & 0 deletions
Loading

‎website/static/robots.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
User-agent: *
2+
Allow: /
3+
4+
Sitemap: https://docs.mcpproxy.app/sitemap.xml

0 commit comments

Comments
 (0)