feat: set up mcp for docs #5

Merged
naomi merged 1 commits from feat/mcp into main 2025-07-14 14:15:02 -07:00
9 changed files with 18826 additions and 3 deletions
+1
View File
@@ -7,6 +7,7 @@ export const prompt = `You are a support agent named Hikari. Your personality is
Your role is to help NHCarrigan's customer with their questions about our products. Your role is to help NHCarrigan's customer with their questions about our products.
As such, you should be referencing the following sources: As such, you should be referencing the following sources:
- Our documentation, at https://docs.nhcarrigan.com - Our documentation, at https://docs.nhcarrigan.com
- The MCP for our documentation, at https://hikari.nhcarrigan.com/mcp
- Our source code, at https://git.nhcarrigan.com/nhcarrigan - Our source code, at https://git.nhcarrigan.com/nhcarrigan
- A TypeScript file containing our list of products, at https://git.nhcarrigan.com/nhcarrigan/hikari/raw/branch/main/client/src/app/config/products.ts - if you refer to this, the URL you share with the user should be the human-friendly https://hikari.nhcarrigan.com/products. - A TypeScript file containing our list of products, at https://git.nhcarrigan.com/nhcarrigan/hikari/raw/branch/main/client/src/app/config/products.ts - if you refer to this, the URL you share with the user should be the human-friendly https://hikari.nhcarrigan.com/products.
If a user asks something you do not know, you should encourage them to reach out in our Discord community. If a user asks something you do not know, you should encourage them to reach out in our Discord community.
+77
View File
@@ -124,6 +124,9 @@ importers:
fastify: fastify:
specifier: 5.4.0 specifier: 5.4.0
version: 5.4.0 version: 5.4.0
gray-matter:
specifier: 4.0.3
version: 4.0.3
devDependencies: devDependencies:
'@types/node': '@types/node':
specifier: 24.0.10 specifier: 24.0.10
@@ -1840,6 +1843,9 @@ packages:
resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==}
engines: {node: '>=14'} engines: {node: '>=14'}
argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
argparse@2.0.1: argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
@@ -2655,6 +2661,11 @@ packages:
resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==} resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
esprima@4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
esquery@1.6.0: esquery@1.6.0:
resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
@@ -2690,6 +2701,10 @@ packages:
exsolve@1.0.7: exsolve@1.0.7:
resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==}
extend-shallow@2.0.1:
resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==}
engines: {node: '>=0.10.0'}
extend@3.0.2: extend@3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
@@ -2905,6 +2920,10 @@ packages:
graphemer@1.4.0: graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
gray-matter@4.0.3:
resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==}
engines: {node: '>=6.0'}
hachure-fill@0.5.2: hachure-fill@0.5.2:
resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==}
@@ -3076,6 +3095,10 @@ packages:
resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
is-extendable@0.1.1:
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
engines: {node: '>=0.10.0'}
is-extglob@2.1.1: is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -3232,6 +3255,10 @@ packages:
js-tokens@9.0.1: js-tokens@9.0.1:
resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
js-yaml@4.1.0: js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true hasBin: true
@@ -3332,6 +3359,10 @@ packages:
khroma@2.1.0: khroma@2.1.0:
resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==}
kind-of@6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
kolorist@1.8.0: kolorist@1.8.0:
resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
@@ -4128,6 +4159,10 @@ packages:
sax@1.4.1: sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
section-matter@1.0.0:
resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==}
engines: {node: '>=4'}
secure-json-parse@4.0.0: secure-json-parse@4.0.0:
resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==} resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==}
@@ -4275,6 +4310,9 @@ packages:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'} engines: {node: '>= 10.x'}
sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
sprintf-js@1.1.3: sprintf-js@1.1.3:
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
@@ -4347,6 +4385,10 @@ packages:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
strip-bom-string@1.0.0:
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
engines: {node: '>=0.10.0'}
strip-bom@3.0.0: strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -6662,6 +6704,10 @@ snapshots:
are-docs-informative@0.0.2: {} are-docs-informative@0.0.2: {}
argparse@1.0.10:
dependencies:
sprintf-js: 1.0.3
argparse@2.0.1: {} argparse@2.0.1: {}
array-buffer-byte-length@1.0.2: array-buffer-byte-length@1.0.2:
@@ -7798,6 +7844,8 @@ snapshots:
acorn-jsx: 5.3.2(acorn@7.4.1) acorn-jsx: 5.3.2(acorn@7.4.1)
eslint-visitor-keys: 1.3.0 eslint-visitor-keys: 1.3.0
esprima@4.0.1: {}
esquery@1.6.0: esquery@1.6.0:
dependencies: dependencies:
estraverse: 5.3.0 estraverse: 5.3.0
@@ -7825,6 +7873,10 @@ snapshots:
exsolve@1.0.7: exsolve@1.0.7:
optional: true optional: true
extend-shallow@2.0.1:
dependencies:
is-extendable: 0.1.1
extend@3.0.2: {} extend@3.0.2: {}
external-editor@3.1.0: external-editor@3.1.0:
@@ -8078,6 +8130,13 @@ snapshots:
graphemer@1.4.0: {} graphemer@1.4.0: {}
gray-matter@4.0.3:
dependencies:
js-yaml: 3.14.1
kind-of: 6.0.3
section-matter: 1.0.0
strip-bom-string: 1.0.0
hachure-fill@0.5.2: hachure-fill@0.5.2:
optional: true optional: true
@@ -8257,6 +8316,8 @@ snapshots:
call-bound: 1.0.4 call-bound: 1.0.4
has-tostringtag: 1.0.2 has-tostringtag: 1.0.2
is-extendable@0.1.1: {}
is-extglob@2.1.1: {} is-extglob@2.1.1: {}
is-finalizationregistry@1.1.1: is-finalizationregistry@1.1.1:
@@ -8415,6 +8476,11 @@ snapshots:
js-tokens@9.0.1: {} js-tokens@9.0.1: {}
js-yaml@3.14.1:
dependencies:
argparse: 1.0.10
esprima: 4.0.1
js-yaml@4.1.0: js-yaml@4.1.0:
dependencies: dependencies:
argparse: 2.0.1 argparse: 2.0.1
@@ -8534,6 +8600,8 @@ snapshots:
khroma@2.1.0: khroma@2.1.0:
optional: true optional: true
kind-of@6.0.3: {}
kolorist@1.8.0: kolorist@1.8.0:
optional: true optional: true
@@ -9499,6 +9567,11 @@ snapshots:
sax@1.4.1: sax@1.4.1:
optional: true optional: true
section-matter@1.0.0:
dependencies:
extend-shallow: 2.0.1
kind-of: 6.0.3
secure-json-parse@4.0.0: {} secure-json-parse@4.0.0: {}
select@1.1.2: select@1.1.2:
@@ -9680,6 +9753,8 @@ snapshots:
split2@4.2.0: {} split2@4.2.0: {}
sprintf-js@1.0.3: {}
sprintf-js@1.1.3: {} sprintf-js@1.1.3: {}
ssri@12.0.0: ssri@12.0.0:
@@ -9779,6 +9854,8 @@ snapshots:
dependencies: dependencies:
ansi-regex: 6.1.0 ansi-regex: 6.1.0
strip-bom-string@1.0.0: {}
strip-bom@3.0.0: {} strip-bom@3.0.0: {}
strip-indent@3.0.0: strip-indent@3.0.0:
+76
View File
@@ -0,0 +1,76 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
/**
* This script fetches our documentation from our repository,
* compiles it into an MCP format, and writes it to a JSON file.
* It is intended to run automatically as part of the build process.
*/
import fs from "node:fs/promises";
import path from "node:path";
import matter from "gray-matter";
import { promisify } from "node:util";
import { exec } from "node:child_process";
const execAsync = promisify(exec);
const docsDirectory = path.resolve(process.cwd(), "temp-docs");
const docsPath = path.resolve(process.cwd(), "temp-docs", "src", "content", "docs")
async function walk(directory: string): Promise<Array<string>> {
const dirents = await fs.readdir(directory, { withFileTypes: true });
const files = await Promise.all(
dirents.map(async (dirent) => {
const result = path.resolve(directory, dirent.name);
return dirent.isDirectory() ? await walk(result) : result;
})
);
return files.flat();
}
await execAsync(`git clone https://git.nhcarrigan.com/nhcarrigan/docs.git ${docsDirectory}`, {
cwd: process.cwd(),
stdio: "inherit",
});
const files = await walk(docsPath);
const markdownFiles = files.filter((f) => {
return f.endsWith(".md");
});
const results = await Promise.all(
markdownFiles.map(async (file) => {
const raw = await fs.readFile(file, "utf-8");
const { content, data } = matter(raw);
// Split content by header blocks (basic chunking)
const chunks = content.split(/^#+\s+/gm).map((chunk, index) => {
return {
content: chunk.trim(),
file: path.relative(docsDirectory, file),
id: `${path.relative(docsDirectory, file)}::${index}`,
metadata: data,
title:
index === 0 ? "(intro)" : chunk.split("\n")[0]?.trim() ?? "Unknown",
url: `https://docs.nhcarrigan.com/${path
.relative(docsPath, file)
.replace(/\.md$/, "").replace(/\/$/, "")}#${index === 0 ? "" : chunk.split("\n")[0]?.trim().toLowerCase().replace(/\s+/g, "-").replace(/\./g, "")}`,
};
});
return chunks;
})
);
const flat = results.flat();
await fs.writeFile(
path.resolve(process.cwd(), "src", "data", "docs.json"),
JSON.stringify(flat, null, 2)
);
await fs.rm(docsDirectory, { recursive: true, force: true });
+3 -2
View File
@@ -7,7 +7,7 @@
"scripts": { "scripts": {
"lint": "eslint ./src --max-warnings 0", "lint": "eslint ./src --max-warnings 0",
"dev": "NODE_ENV=dev op run --env-file=./dev.env -- tsx watch ./src/index.ts", "dev": "NODE_ENV=dev op run --env-file=./dev.env -- tsx watch ./src/index.ts",
"build": "tsc", "build": "tsx ./getDocs.ts && tsc",
"start": "op run --env-file=./prod.env -- node ./prod/index.js", "start": "op run --env-file=./prod.env -- node ./prod/index.js",
"test": "echo 'No tests yet' && exit 0" "test": "echo 'No tests yet' && exit 0"
}, },
@@ -19,7 +19,8 @@
"@fastify/cors": "11.0.1", "@fastify/cors": "11.0.1",
"@nhcarrigan/logger": "1.0.0", "@nhcarrigan/logger": "1.0.0",
"@prisma/client": "6.11.1", "@prisma/client": "6.11.1",
"fastify": "5.4.0" "fastify": "5.4.0",
"gray-matter": "4.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "24.0.10", "@types/node": "24.0.10",
+1
View File
@@ -12,4 +12,5 @@ export const routesWithoutCors = [
"/", "/",
"/announcement", "/announcement",
"/health", "/health",
"/mcp",
]; ];
File diff suppressed because one or more lines are too long
+2
View File
@@ -10,6 +10,7 @@ import { corsHook } from "./hooks/cors.js";
import { ipHook } from "./hooks/ips.js"; import { ipHook } from "./hooks/ips.js";
import { announcementRoutes } from "./routes/announcement.js"; import { announcementRoutes } from "./routes/announcement.js";
import { baseRoutes } from "./routes/base.js"; import { baseRoutes } from "./routes/base.js";
import { mcpRoutes } from "./routes/mcp.js";
import { logger } from "./utils/logger.js"; import { logger } from "./utils/logger.js";
const server = fastify({ const server = fastify({
@@ -32,6 +33,7 @@ server.addHook("preHandler", ipHook);
server.register(baseRoutes); server.register(baseRoutes);
server.register(announcementRoutes); server.register(announcementRoutes);
server.register(mcpRoutes);
server.listen({ port: 20_000 }, (error) => { server.listen({ port: 20_000 }, (error) => {
if (error) { if (error) {
+21
View File
@@ -0,0 +1,21 @@
/**
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import documentationData from "../data/docs.json";
import type { FastifyPluginAsync } from "fastify";
/**
* Mounts the Model Context Protocol routes for the application. These routes
* should not require CORS, as they are used by external services
* such as ChatGPT.
* @param server - The Fastify server instance.
*/
export const mcpRoutes: FastifyPluginAsync = async(server) => {
server.get("/mcp", async(_request, reply) => {
return await reply.status(200).send(documentationData);
});
};
+3 -1
View File
@@ -3,5 +3,7 @@
"compilerOptions": { "compilerOptions": {
"rootDir": "./src", "rootDir": "./src",
"outDir": "./prod", "outDir": "./prod",
} "resolveJsonModule": true
},
"exclude": ["./getDocs.ts"]
} }