@docsector/docsector-reader 1.4.0 → 1.5.0

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/README.md CHANGED
@@ -30,6 +30,7 @@ Transform Markdown content into beautiful, navigable documentation sites — wit
30
30
  - 🤖 **AI-Friendly robots.txt** — Scaffold includes a `robots.txt` explicitly allowing 23 AI crawlers (GPTBot, ClaudeBot, PerplexityBot, GrokBot, etc.)
31
31
  - 🧭 **Content Signals** — Optional `Content-Signal` directive for declaring AI usage policy (`ai-train`, `search`, `ai-input`) in `robots.txt`
32
32
  - 🧩 **Agent Skills Discovery Index** — Optional `/.well-known/agent-skills/index.json` with RFC v0.2.0 schema and SHA-256 digests
33
+ - 🪪 **MCP Server Card** — Optional `/.well-known/mcp/server-card.json` for MCP server discovery before connection
33
34
  - 🔗 **Homepage Link Headers** — Auto-generated `Link` response headers for agent discovery (`api-catalog`, `service-doc`, `service-desc`, `describedby`) per RFC 8288 / RFC 9727
34
35
  - 🔌 **MCP Server** — Auto-generated [MCP](https://modelcontextprotocol.io) server at `/mcp` for AI assistant integration (Claude Desktop, VS Code, etc.)
35
36
  - 📄 **llms.txt / llms-full.txt** — Auto-generated [llms.txt](https://llmstxt.org) index and full-content file for LLM discovery (requires `siteUrl` in config)
@@ -141,6 +142,69 @@ curl -X POST http://localhost:8788/mcp \
141
142
 
142
143
  ---
143
144
 
145
+ ## 🪪 MCP Server Card Discovery
146
+
147
+ Docsector Reader can publish an MCP Server Card at:
148
+
149
+ - `/.well-known/mcp/server-card.json`
150
+
151
+ This supports pre-connection MCP discovery, exposing:
152
+
153
+ - `serverInfo` (`name`, `version`)
154
+ - MCP transport endpoint (defaults to `/mcp`)
155
+ - `capabilities` for tools/resources/prompts
156
+
157
+ When MCP is enabled, tool capabilities are derived from the generated server:
158
+
159
+ - `search_{toolSuffix}`
160
+ - `get_page_{toolSuffix}`
161
+
162
+ ### Configure
163
+
164
+ ```javascript
165
+ export default {
166
+ // ...other config
167
+
168
+ mcp: {
169
+ serverName: 'my-docs',
170
+ toolSuffix: 'my_docs'
171
+ },
172
+
173
+ mcpServerCard: {
174
+ enabled: true,
175
+ path: '/.well-known/mcp/server-card.json',
176
+ transportEndpoint: '/mcp',
177
+ transportType: 'streamable-http',
178
+ protocolVersion: '2025-03-26',
179
+ capabilities: {
180
+ tools: { supported: true },
181
+ resources: { supported: false },
182
+ prompts: { supported: false }
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ ### Validate
189
+
190
+ ```bash
191
+ npx docsector build
192
+ cat dist/spa/.well-known/mcp/server-card.json
193
+ cat dist/spa/_headers
194
+ ```
195
+
196
+ External validation:
197
+
198
+ ```bash
199
+ curl -X POST https://isitagentready.com/api/scan \
200
+ -H 'Content-Type: application/json' \
201
+ -d '{"url":"https://YOUR-SITE.com"}'
202
+ ```
203
+
204
+ Check `checks.discovery.mcpServerCard.status` equals `"pass"`.
205
+
206
+ ---
207
+
144
208
  ## � llms.txt (LLM Discovery)
145
209
 
146
210
  Docsector Reader automatically generates [llms.txt](https://llmstxt.org) files at build time when `siteUrl` is configured (same requirement as sitemap.xml).
@@ -550,6 +614,14 @@ export default {
550
614
  agentFallback: true
551
615
  },
552
616
 
617
+ mcpServerCard: {
618
+ enabled: true,
619
+ path: '/.well-known/mcp/server-card.json',
620
+ transportEndpoint: '/mcp',
621
+ transportType: 'streamable-http',
622
+ protocolVersion: '2025-03-26'
623
+ },
624
+
553
625
  contentSignals: {
554
626
  enabled: true,
555
627
  aiTrain: 'yes',
package/bin/docsector.js CHANGED
@@ -23,7 +23,7 @@ const packageRoot = resolve(__dirname, '..')
23
23
  const args = process.argv.slice(2)
24
24
  const command = args[0]
25
25
 
26
- const VERSION = '1.4.0'
26
+ const VERSION = '1.5.0'
27
27
 
28
28
  const HELP = `
29
29
  Docsector Reader v${VERSION}
@@ -133,6 +133,21 @@ export default {
133
133
  // toolSuffix: 'my_docs'
134
134
  // },
135
135
 
136
+ // @ MCP Server Card discovery (optional)
137
+ // Publishes /.well-known/mcp/server-card.json for pre-connection discovery.
138
+ // mcpServerCard: {
139
+ // enabled: true,
140
+ // path: '/.well-known/mcp/server-card.json',
141
+ // transportEndpoint: '/mcp',
142
+ // transportType: 'streamable-http',
143
+ // protocolVersion: '2025-03-26',
144
+ // capabilities: {
145
+ // tools: { supported: true },
146
+ // resources: { supported: false },
147
+ // prompts: { supported: false }
148
+ // }
149
+ // },
150
+
136
151
  // @ Homepage Link headers for agent discovery (optional)
137
152
  // linkHeaders: {
138
153
  // enabled: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docsector/docsector-reader",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "A documentation rendering engine built with Vue 3, Quasar v2 and Vite. Transform Markdown into beautiful, navigable documentation sites.",
5
5
  "productName": "Docsector Reader",
6
6
  "author": "Rodrigo de Araujo Vieira",
package/src/index.js CHANGED
@@ -78,6 +78,15 @@
78
78
  * @param {string} [config.agentSkills.path='/.well-known/agent-skills/index.json'] - Output URI path for Agent Skills index
79
79
  * @param {string} [config.agentSkills.schema='https://schemas.agentskills.io/discovery/0.2.0/schema.json'] - JSON Schema identifier for index payload
80
80
  * @param {Array<{name:string,type:'skill-md'|'archive',description:string,url:string,digest?:string}>} [config.agentSkills.skills=[]] - Skills to publish in discovery index
81
+ * @param {Object} [config.mcpServerCard] - MCP Server Card discovery settings
82
+ * @param {boolean} [config.mcpServerCard.enabled=false] - Enables generation of MCP Server Card discovery document
83
+ * @param {string} [config.mcpServerCard.path='/.well-known/mcp/server-card.json'] - Output URI path for MCP Server Card
84
+ * @param {string} [config.mcpServerCard.transportEndpoint='/mcp'] - MCP transport endpoint exposed by the server
85
+ * @param {string} [config.mcpServerCard.transportType='streamable-http'] - Transport type label for discovery metadata
86
+ * @param {string} [config.mcpServerCard.protocolVersion='2025-03-26'] - Protocol version advertised by the server card
87
+ * @param {Object} [config.mcpServerCard.capabilities] - Optional capability overrides for tools/resources/prompts
88
+ * @param {Array<Object>} [config.mcpServerCard.remotes=[]] - Optional additional remotes to include in the server card
89
+ * @param {Object} [config.mcpServerCard.metadata] - Optional additional metadata merged into the server card payload
81
90
  * @returns {Object} Resolved Docsector configuration
82
91
  */
83
92
  export function createDocsector (config = {}) {
@@ -169,6 +178,18 @@ export function createDocsector (config = {}) {
169
178
  schema: 'https://schemas.agentskills.io/discovery/0.2.0/schema.json',
170
179
  skills: [],
171
180
  ...config.agentSkills
181
+ },
182
+
183
+ mcpServerCard: {
184
+ enabled: false,
185
+ path: '/.well-known/mcp/server-card.json',
186
+ transportEndpoint: '/mcp',
187
+ transportType: 'streamable-http',
188
+ protocolVersion: '2025-03-26',
189
+ capabilities: null,
190
+ remotes: [],
191
+ metadata: null,
192
+ ...config.mcpServerCard
172
193
  }
173
194
  }
174
195
  }
@@ -757,6 +757,8 @@ function createMarkdownBuildPlugin (projectRoot) {
757
757
  const contentSignalsEnabled = contentSignalsConfig.enabled === true
758
758
  const agentSkillsConfig = config.agentSkills || {}
759
759
  const agentSkillsEnabled = agentSkillsConfig.enabled === true
760
+ const mcpServerCardConfig = config.mcpServerCard || {}
761
+ const mcpServerCardEnabled = mcpServerCardConfig.enabled === true
760
762
 
761
763
  const toUrl = (href) => {
762
764
  if (!href) return null
@@ -1112,6 +1114,54 @@ export async function onRequest (context) {
1112
1114
  }
1113
1115
  }
1114
1116
 
1117
+ if (mcpServerCardEnabled) {
1118
+ if (!config.mcp) {
1119
+ console.warn('\x1b[33m[docsector]\x1b[0m Skipped MCP Server Card generation: mcp config is not enabled')
1120
+ } else {
1121
+ const mcpServerCardPath = mcpServerCardConfig.path || '/.well-known/mcp/server-card.json'
1122
+ const cardDistPath = normalizeLocalPath(mcpServerCardPath)
1123
+
1124
+ if (!cardDistPath) {
1125
+ console.warn(`\x1b[33m[docsector]\x1b[0m Skipped MCP Server Card generation: path must be a local URI path, got "${mcpServerCardPath}"`)
1126
+ } else {
1127
+ const cardHref = mcpServerCardPath.startsWith('/') ? mcpServerCardPath : `/${mcpServerCardPath}`
1128
+ const mcpServerName = config.mcp.serverName || config.branding?.name || 'docs'
1129
+ const mcpServerVersion = config.branding?.version || '1.0.0'
1130
+ const mcpToolSuffix = config.mcp.toolSuffix || 'docs'
1131
+ const transportEndpoint = mcpServerCardConfig.transportEndpoint || '/mcp'
1132
+ const endpoint = toUrl(transportEndpoint)
1133
+
1134
+ if (!endpoint) {
1135
+ console.warn('\x1b[33m[docsector]\x1b[0m Skipped MCP Server Card generation: unable to resolve transport endpoint URL')
1136
+ } else {
1137
+ const cardPayload = buildMcpServerCardPayload({
1138
+ config,
1139
+ mcpServerCardConfig,
1140
+ serverName: mcpServerName,
1141
+ serverVersion: mcpServerVersion,
1142
+ endpoint,
1143
+ toolSuffix: mcpToolSuffix
1144
+ })
1145
+
1146
+ const cardDir = resolve(distDir, cardDistPath, '..')
1147
+ mkdirSync(cardDir, { recursive: true })
1148
+ writeFileSync(
1149
+ resolve(distDir, cardDistPath),
1150
+ JSON.stringify(cardPayload, null, 2) + '\n'
1151
+ )
1152
+ console.log(`\x1b[36m[docsector]\x1b[0m Generated ${cardHref}`)
1153
+
1154
+ const headersWithServerCard = readFileSync(headersPath, 'utf-8')
1155
+ if (!headersWithServerCard.includes(cardHref)) {
1156
+ const serverCardHeaders = `${cardHref}\n Content-Type: application/json; charset=utf-8\n`
1157
+ writeFileSync(headersPath, headersWithServerCard.trimEnd() + '\n\n' + serverCardHeaders)
1158
+ console.log(`\x1b[36m[docsector]\x1b[0m Added _headers rule for ${cardHref}`)
1159
+ }
1160
+ }
1161
+ }
1162
+ }
1163
+ }
1164
+
1115
1165
  console.log(`\x1b[36m[docsector]\x1b[0m Added _headers rule for .md files`)
1116
1166
 
1117
1167
  // Add homepage Link headers for agent discovery (RFC 8288 / RFC 9727)
@@ -1504,6 +1554,87 @@ function resolveAgentSkillArtifactPath (artifactUrl, { siteUrl, distDir }) {
1504
1554
  return resolve(distDir, relativePath)
1505
1555
  }
1506
1556
 
1557
+ function mergeObjects (base, override) {
1558
+ if (!override || typeof override !== 'object' || Array.isArray(override)) {
1559
+ return base
1560
+ }
1561
+
1562
+ return { ...base, ...override }
1563
+ }
1564
+
1565
+ function buildMcpServerCardPayload ({
1566
+ config,
1567
+ mcpServerCardConfig,
1568
+ serverName,
1569
+ serverVersion,
1570
+ endpoint,
1571
+ toolSuffix
1572
+ }) {
1573
+ const transportType = mcpServerCardConfig.transportType || 'streamable-http'
1574
+ const protocolVersion = mcpServerCardConfig.protocolVersion || '2025-03-26'
1575
+ const baseTools = [
1576
+ `search_${toolSuffix}`,
1577
+ `get_page_${toolSuffix}`
1578
+ ]
1579
+
1580
+ const defaultCapabilities = {
1581
+ tools: {
1582
+ supported: true,
1583
+ names: baseTools
1584
+ },
1585
+ resources: {
1586
+ supported: false
1587
+ },
1588
+ prompts: {
1589
+ supported: false
1590
+ }
1591
+ }
1592
+
1593
+ const capabilitiesOverride = (mcpServerCardConfig.capabilities && typeof mcpServerCardConfig.capabilities === 'object' && !Array.isArray(mcpServerCardConfig.capabilities))
1594
+ ? mcpServerCardConfig.capabilities
1595
+ : {}
1596
+ const capabilities = {
1597
+ ...capabilitiesOverride,
1598
+ tools: mergeObjects(defaultCapabilities.tools, capabilitiesOverride.tools),
1599
+ resources: mergeObjects(defaultCapabilities.resources, capabilitiesOverride.resources),
1600
+ prompts: mergeObjects(defaultCapabilities.prompts, capabilitiesOverride.prompts)
1601
+ }
1602
+
1603
+ const primaryRemote = {
1604
+ transportType,
1605
+ endpoint,
1606
+ supportedProtocolVersions: [protocolVersion]
1607
+ }
1608
+
1609
+ const customRemotes = Array.isArray(mcpServerCardConfig.remotes)
1610
+ ? mcpServerCardConfig.remotes
1611
+ : []
1612
+ const remotes = [primaryRemote, ...customRemotes]
1613
+
1614
+ const payload = {
1615
+ serverInfo: {
1616
+ name: serverName,
1617
+ version: serverVersion
1618
+ },
1619
+ title: config.branding?.name || serverName,
1620
+ description: config.branding?.description || null,
1621
+ transport: {
1622
+ type: transportType,
1623
+ endpoint
1624
+ },
1625
+ remotes,
1626
+ capabilities,
1627
+ tools: baseTools.map(name => ({ name }))
1628
+ }
1629
+
1630
+ const metadata = mcpServerCardConfig.metadata
1631
+ if (metadata && typeof metadata === 'object' && !Array.isArray(metadata)) {
1632
+ return { ...payload, ...metadata }
1633
+ }
1634
+
1635
+ return payload
1636
+ }
1637
+
1507
1638
  /**
1508
1639
  * Create a complete Quasar configuration for a docsector-reader consumer project.
1509
1640
  *