@mastra/mcp-docs-server 0.13.0 → 0.13.1-alpha.2
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/.docs/organized/changelogs/%40internal%2Fstorage-test-utils.md +7 -0
- package/.docs/organized/changelogs/%40mastra%2Fagui.md +14 -0
- package/.docs/organized/changelogs/%40mastra%2Fchroma.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fclickhouse.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +64 -64
- package/.docs/organized/changelogs/%40mastra%2Fcloud.md +14 -14
- package/.docs/organized/changelogs/%40mastra%2Fcloudflare-d1.md +15 -15
- package/.docs/organized/changelogs/%40mastra%2Fcloudflare.md +10 -10
- package/.docs/organized/changelogs/%40mastra%2Fcore.md +65 -65
- package/.docs/organized/changelogs/%40mastra%2Fcouchbase.md +12 -0
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +82 -82
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +79 -79
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +77 -77
- package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +94 -94
- package/.docs/organized/changelogs/%40mastra%2Fdynamodb.md +54 -0
- package/.docs/organized/changelogs/%40mastra%2Fevals.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Ffirecrawl.md +16 -16
- package/.docs/organized/changelogs/%40mastra%2Fgithub.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Flance.md +12 -0
- package/.docs/organized/changelogs/%40mastra%2Flibsql.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +47 -47
- package/.docs/organized/changelogs/%40mastra%2Fmcp-registry-registry.md +37 -37
- package/.docs/organized/changelogs/%40mastra%2Fmcp.md +22 -22
- package/.docs/organized/changelogs/%40mastra%2Fmem0.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fmemory.md +32 -32
- package/.docs/organized/changelogs/%40mastra%2Fmongodb.md +27 -27
- package/.docs/organized/changelogs/%40mastra%2Fopensearch.md +12 -0
- package/.docs/organized/changelogs/%40mastra%2Fpg.md +51 -51
- package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +108 -108
- package/.docs/organized/changelogs/%40mastra%2Fqdrant.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Frag.md +17 -17
- package/.docs/organized/changelogs/%40mastra%2Fragie.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fserver.md +66 -66
- package/.docs/organized/changelogs/%40mastra%2Fturbopuffer.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fupstash.md +37 -37
- package/.docs/organized/changelogs/%40mastra%2Fvoice-azure.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-cloudflare.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-deepgram.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-elevenlabs.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-gladia.md +9 -0
- package/.docs/organized/changelogs/%40mastra%2Fvoice-google.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-murf.md +14 -14
- package/.docs/organized/changelogs/%40mastra%2Fvoice-openai-realtime.md +24 -24
- package/.docs/organized/changelogs/%40mastra%2Fvoice-openai.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-playai.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-sarvam.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fvoice-speechify.md +13 -13
- package/.docs/organized/changelogs/create-mastra.md +35 -35
- package/.docs/organized/changelogs/mastra.md +124 -124
- package/.docs/organized/code-examples/agent.md +5 -2
- package/.docs/organized/code-examples/agui.md +4 -1
- package/.docs/organized/code-examples/ai-sdk-useChat.md +1 -1
- package/.docs/organized/code-examples/fireworks-r1.md +1 -1
- package/.docs/organized/code-examples/memory-with-processors.md +2 -2
- package/.docs/organized/code-examples/openapi-spec-writer.md +1 -1
- package/.docs/organized/code-examples/quick-start.md +1 -1
- package/.docs/organized/code-examples/weather-agent.md +7 -1
- package/.docs/raw/course/01-first-agent/03-verifying-installation.md +4 -2
- package/.docs/raw/course/01-first-agent/16-adding-memory-to-agent.md +1 -1
- package/.docs/raw/course/02-agent-tools-mcp/15-updating-mcp-config-github.md +1 -1
- package/.docs/raw/course/02-agent-tools-mcp/20-updating-mcp-config-hackernews.md +1 -1
- package/.docs/raw/course/02-agent-tools-mcp/26-updating-mcp-config-filesystem.md +1 -1
- package/.docs/raw/course/03-agent-memory/03-installing-memory.md +4 -2
- package/.docs/raw/course/03-agent-memory/04-creating-basic-memory-agent.md +1 -1
- package/.docs/raw/course/03-agent-memory/08-configuring-conversation-history.md +3 -3
- package/.docs/raw/course/03-agent-memory/13-vector-store-configuration.md +27 -0
- package/.docs/raw/course/03-agent-memory/{13-what-is-semantic-recall.md → 14-what-is-semantic-recall.md} +1 -1
- package/.docs/raw/course/03-agent-memory/16-configuring-semantic-recall.md +41 -0
- package/.docs/raw/course/03-agent-memory/18-advanced-configuration-semantic-recall.md +28 -0
- package/.docs/raw/course/03-agent-memory/21-configuring-working-memory.md +9 -9
- package/.docs/raw/course/03-agent-memory/22-custom-working-memory-templates.md +10 -2
- package/.docs/raw/course/03-agent-memory/25-combining-memory-features.md +8 -1
- package/.docs/raw/course/03-agent-memory/27-creating-learning-assistant.md +8 -1
- package/.docs/raw/deployment/deployment.mdx +26 -97
- package/.docs/raw/deployment/overview.mdx +18 -3
- package/.docs/raw/deployment/web-framework.mdx +63 -0
- package/.docs/raw/frameworks/web-frameworks/astro.mdx +7 -1
- package/.docs/raw/frameworks/web-frameworks/next-js.mdx +1 -1
- package/.docs/raw/getting-started/installation.mdx +98 -558
- package/.docs/raw/getting-started/project-structure.mdx +3 -16
- package/.docs/raw/rag/vector-databases.mdx +4 -7
- package/.docs/raw/reference/agents/generate.mdx +35 -3
- package/.docs/raw/reference/agents/stream.mdx +35 -3
- package/.docs/raw/reference/client-js/memory.mdx +14 -0
- package/.docs/raw/reference/client-js/workflows.mdx +28 -0
- package/.docs/raw/reference/deployer/cloudflare.mdx +9 -3
- package/.docs/raw/reference/deployer/deployer.mdx +1 -1
- package/.docs/raw/reference/deployer/netlify.mdx +25 -4
- package/.docs/raw/reference/deployer/vercel.mdx +10 -4
- package/.docs/raw/workflows/control-flow.mdx +45 -171
- package/.docs/raw/workflows/input-data-mapping.mdx +21 -88
- package/.docs/raw/workflows/overview.mdx +24 -47
- package/.docs/raw/workflows/suspend-and-resume.mdx +46 -34
- package/.docs/raw/workflows/using-with-agents-and-tools.mdx +55 -191
- package/dist/_tsup-dts-rollup.d.ts +14 -0
- package/dist/{chunk-QWIXFGFR.js → chunk-P5AHYMUI.js} +126 -20
- package/dist/prepare-docs/prepare.js +1 -1
- package/dist/stdio.js +42 -17
- package/package.json +15 -15
- package/.docs/raw/course/03-agent-memory/15-configuring-semantic-recall.md +0 -46
- package/.docs/raw/course/03-agent-memory/16-vector-store-configuration.md +0 -37
- package/.docs/raw/course/03-agent-memory/18-disabling-semantic-recall.md +0 -24
- /package/.docs/raw/{deployment/client.mdx → client-js/overview.mdx} +0 -0
- /package/.docs/raw/course/03-agent-memory/{14-how-semantic-recall-works.md → 15-how-semantic-recall-works.md} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import fs2 from 'fs/promises';
|
|
1
2
|
import path4, { dirname } from 'path';
|
|
2
3
|
import { fileURLToPath } from 'url';
|
|
3
|
-
import fs from 'fs/promises';
|
|
4
4
|
|
|
5
5
|
// src/utils.ts
|
|
6
|
+
var mdxFileCache = /* @__PURE__ */ new Map();
|
|
6
7
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
8
|
function fromRepoRoot(relative) {
|
|
8
9
|
return path4.resolve(__dirname, `../../../`, relative);
|
|
@@ -11,22 +12,127 @@ function fromPackageRoot(relative) {
|
|
|
11
12
|
return path4.resolve(__dirname, `../`, relative);
|
|
12
13
|
}
|
|
13
14
|
var log = console.error;
|
|
15
|
+
async function* walkMdxFiles(dir) {
|
|
16
|
+
if (mdxFileCache.has(dir)) {
|
|
17
|
+
for (const file of mdxFileCache.get(dir)) yield file;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const filesInDir = [];
|
|
21
|
+
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const fullPath = path4.join(dir, entry.name);
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
for await (const file of walkMdxFiles(fullPath)) {
|
|
26
|
+
filesInDir.push(file);
|
|
27
|
+
yield file;
|
|
28
|
+
}
|
|
29
|
+
} else if (entry.isFile() && entry.name.endsWith(".mdx")) {
|
|
30
|
+
filesInDir.push(fullPath);
|
|
31
|
+
yield fullPath;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
mdxFileCache.set(dir, filesInDir);
|
|
35
|
+
}
|
|
36
|
+
async function searchDocumentContent(keywords, baseDir) {
|
|
37
|
+
if (keywords.length === 0) return [];
|
|
38
|
+
const fileScores = /* @__PURE__ */ new Map();
|
|
39
|
+
for await (const filePath of walkMdxFiles(baseDir)) {
|
|
40
|
+
let content;
|
|
41
|
+
try {
|
|
42
|
+
content = await fs2.readFile(filePath, "utf-8");
|
|
43
|
+
} catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const lines = content.split("\n");
|
|
47
|
+
lines.forEach((lineText) => {
|
|
48
|
+
const lowerLine = lineText.toLowerCase();
|
|
49
|
+
for (const keyword of keywords) {
|
|
50
|
+
if (lowerLine.includes(keyword.toLowerCase())) {
|
|
51
|
+
const relativePath = path4.relative(baseDir, filePath).replace(/\\/g, "/");
|
|
52
|
+
if (!fileScores.has(relativePath)) {
|
|
53
|
+
fileScores.set(relativePath, {
|
|
54
|
+
path: relativePath,
|
|
55
|
+
keywordMatches: /* @__PURE__ */ new Set(),
|
|
56
|
+
totalMatches: 0,
|
|
57
|
+
titleMatches: 0,
|
|
58
|
+
pathRelevance: calculatePathRelevance(relativePath, keywords)
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const score = fileScores.get(relativePath);
|
|
62
|
+
score.keywordMatches.add(keyword);
|
|
63
|
+
score.totalMatches++;
|
|
64
|
+
if (lowerLine.includes("#") || lowerLine.includes("title")) {
|
|
65
|
+
score.titleMatches++;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const validFiles = Array.from(fileScores.values()).sort((a, b) => calculateFinalScore(b, keywords.length) - calculateFinalScore(a, keywords.length)).slice(0, 10);
|
|
72
|
+
return validFiles.map((score) => score.path);
|
|
73
|
+
}
|
|
74
|
+
function calculatePathRelevance(filePath, keywords) {
|
|
75
|
+
let relevance = 0;
|
|
76
|
+
const pathLower = filePath.toLowerCase();
|
|
77
|
+
if (pathLower.startsWith("reference/")) relevance += 2;
|
|
78
|
+
keywords.forEach((keyword) => {
|
|
79
|
+
if (pathLower.includes(keyword.toLowerCase())) relevance += 3;
|
|
80
|
+
});
|
|
81
|
+
const highValueDirs = ["rag", "memory", "agents", "workflows"];
|
|
82
|
+
if (highValueDirs.some((dir) => pathLower.includes(dir))) {
|
|
83
|
+
relevance += 1;
|
|
84
|
+
}
|
|
85
|
+
return relevance;
|
|
86
|
+
}
|
|
87
|
+
function calculateFinalScore(score, totalKeywords) {
|
|
88
|
+
const allKeywordsBonus = score.keywordMatches.size === totalKeywords ? 10 : 0;
|
|
89
|
+
return score.totalMatches * 1 + score.titleMatches * 3 + score.pathRelevance * 2 + score.keywordMatches.size * 5 + allKeywordsBonus;
|
|
90
|
+
}
|
|
91
|
+
function extractKeywordsFromPath(path5) {
|
|
92
|
+
const filename = path5.split("/").pop()?.replace(/\.(mdx|md)$/, "") || "";
|
|
93
|
+
const keywords = /* @__PURE__ */ new Set();
|
|
94
|
+
const splitParts = filename.split(/[-_]|(?=[A-Z])/);
|
|
95
|
+
splitParts.forEach((keyword) => {
|
|
96
|
+
if (keyword.length > 2) {
|
|
97
|
+
keywords.add(keyword.toLowerCase());
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return Array.from(keywords);
|
|
101
|
+
}
|
|
102
|
+
function normalizeKeywords(keywords) {
|
|
103
|
+
return Array.from(new Set(keywords.flatMap((k) => k.split(/\s+/).filter(Boolean)).map((k) => k.toLowerCase())));
|
|
104
|
+
}
|
|
105
|
+
async function getMatchingPaths(path5, queryKeywords, baseDir) {
|
|
106
|
+
const pathKeywords = extractKeywordsFromPath(path5);
|
|
107
|
+
const allKeywords = normalizeKeywords([...pathKeywords, ...queryKeywords || []]);
|
|
108
|
+
if (allKeywords.length === 0) {
|
|
109
|
+
return "";
|
|
110
|
+
}
|
|
111
|
+
const suggestedPaths = await searchDocumentContent(allKeywords, baseDir);
|
|
112
|
+
if (suggestedPaths.length === 0) {
|
|
113
|
+
return "";
|
|
114
|
+
}
|
|
115
|
+
const pathList = suggestedPaths.map((path6) => `- ${path6}`).join("\n");
|
|
116
|
+
return `Here are some paths that might be relevant based on your query:
|
|
117
|
+
|
|
118
|
+
${pathList}`;
|
|
119
|
+
}
|
|
14
120
|
var EXAMPLES_SOURCE = fromRepoRoot("examples");
|
|
15
121
|
var OUTPUT_DIR = fromPackageRoot(".docs/organized/code-examples");
|
|
16
122
|
async function prepareCodeExamples() {
|
|
17
123
|
try {
|
|
18
|
-
await
|
|
124
|
+
await fs2.rm(OUTPUT_DIR, { recursive: true, force: true });
|
|
19
125
|
} catch {
|
|
20
126
|
}
|
|
21
|
-
await
|
|
22
|
-
const examples = await
|
|
127
|
+
await fs2.mkdir(OUTPUT_DIR, { recursive: true });
|
|
128
|
+
const examples = await fs2.readdir(EXAMPLES_SOURCE, { withFileTypes: true });
|
|
23
129
|
const exampleDirs = examples.filter((entry) => entry.isDirectory());
|
|
24
130
|
for (const dir of exampleDirs) {
|
|
25
131
|
const examplePath = path4.join(EXAMPLES_SOURCE, dir.name);
|
|
26
132
|
const outputFile = path4.join(OUTPUT_DIR, `${dir.name}.md`);
|
|
27
133
|
const files = [];
|
|
28
134
|
try {
|
|
29
|
-
const packageJson = await
|
|
135
|
+
const packageJson = await fs2.readFile(path4.join(examplePath, "package.json"), "utf-8");
|
|
30
136
|
files.push({
|
|
31
137
|
path: "package.json",
|
|
32
138
|
content: packageJson
|
|
@@ -50,20 +156,20 @@ ${file.content}
|
|
|
50
156
|
log(`Skipping ${dir.name}: ${totalLines} lines exceeds limit of ${limit}`);
|
|
51
157
|
continue;
|
|
52
158
|
}
|
|
53
|
-
await
|
|
159
|
+
await fs2.writeFile(outputFile, output, "utf-8");
|
|
54
160
|
log(`Generated ${dir.name}.md with ${totalLines} lines`);
|
|
55
161
|
}
|
|
56
162
|
}
|
|
57
163
|
}
|
|
58
164
|
async function scanDirectory(basePath, currentPath, files) {
|
|
59
|
-
const entries = await
|
|
165
|
+
const entries = await fs2.readdir(currentPath, { withFileTypes: true });
|
|
60
166
|
for (const entry of entries) {
|
|
61
167
|
const fullPath = path4.join(currentPath, entry.name);
|
|
62
168
|
const relativePath = path4.relative(basePath, fullPath);
|
|
63
169
|
if (entry.isDirectory()) {
|
|
64
170
|
await scanDirectory(basePath, fullPath, files);
|
|
65
171
|
} else if (entry.isFile() && entry.name.endsWith(".ts")) {
|
|
66
|
-
const content = await
|
|
172
|
+
const content = await fs2.readFile(fullPath, "utf-8");
|
|
67
173
|
files.push({
|
|
68
174
|
path: relativePath,
|
|
69
175
|
content
|
|
@@ -83,22 +189,22 @@ var DOCS_DEST = fromPackageRoot(".docs/raw");
|
|
|
83
189
|
var REFERENCE_DEST = path4.join(DOCS_DEST, "reference");
|
|
84
190
|
var COURSE_DEST = path4.join(DOCS_DEST, "course");
|
|
85
191
|
async function copyDir(src, dest) {
|
|
86
|
-
await
|
|
87
|
-
const entries = await
|
|
192
|
+
await fs2.mkdir(dest, { recursive: true });
|
|
193
|
+
const entries = await fs2.readdir(src, { withFileTypes: true });
|
|
88
194
|
for (const entry of entries) {
|
|
89
195
|
const srcPath = path4.join(src, entry.name);
|
|
90
196
|
const destPath = path4.join(dest, entry.name);
|
|
91
197
|
if (entry.isDirectory()) {
|
|
92
198
|
await copyDir(srcPath, destPath);
|
|
93
199
|
} else if (entry.isFile() && (entry.name.endsWith(".mdx") || entry.name.endsWith(".md"))) {
|
|
94
|
-
await
|
|
200
|
+
await fs2.copyFile(srcPath, destPath);
|
|
95
201
|
}
|
|
96
202
|
}
|
|
97
203
|
}
|
|
98
204
|
async function copyRaw() {
|
|
99
205
|
try {
|
|
100
206
|
try {
|
|
101
|
-
await
|
|
207
|
+
await fs2.rm(DOCS_DEST, { recursive: true });
|
|
102
208
|
} catch {
|
|
103
209
|
}
|
|
104
210
|
await copyDir(DOCS_SOURCE, DOCS_DEST);
|
|
@@ -128,7 +234,7 @@ async function processPackageDir(packagePath, outputDir) {
|
|
|
128
234
|
let packageName;
|
|
129
235
|
try {
|
|
130
236
|
const packageJsonPath = path4.join(packagePath, "package.json");
|
|
131
|
-
const packageJson = JSON.parse(await
|
|
237
|
+
const packageJson = JSON.parse(await fs2.readFile(packageJsonPath, "utf-8"));
|
|
132
238
|
packageName = packageJson.name;
|
|
133
239
|
if (!packageName) {
|
|
134
240
|
log(`Skipping ${path4.basename(packagePath)}: No package name found in package.json`);
|
|
@@ -142,13 +248,13 @@ async function processPackageDir(packagePath, outputDir) {
|
|
|
142
248
|
const changelogPath = path4.join(packagePath, "CHANGELOG.md");
|
|
143
249
|
let changelog;
|
|
144
250
|
try {
|
|
145
|
-
changelog = await
|
|
251
|
+
changelog = await fs2.readFile(changelogPath, "utf-8");
|
|
146
252
|
changelog = truncateContent(changelog, MAX_LINES);
|
|
147
253
|
} catch {
|
|
148
254
|
changelog = "No changelog available.";
|
|
149
255
|
}
|
|
150
256
|
const outputFile = path4.join(outputDir, `${encodeURIComponent(packageName)}.md`);
|
|
151
|
-
await
|
|
257
|
+
await fs2.writeFile(outputFile, changelog, "utf-8");
|
|
152
258
|
log(`Generated changelog for ${packageName}`);
|
|
153
259
|
} catch (error) {
|
|
154
260
|
console.error(`Error processing changelog for ${packageName}:`, error);
|
|
@@ -157,15 +263,15 @@ async function processPackageDir(packagePath, outputDir) {
|
|
|
157
263
|
async function preparePackageChanges() {
|
|
158
264
|
const outputDir = path4.resolve(process.cwd(), CHANGELOGS_DEST);
|
|
159
265
|
try {
|
|
160
|
-
await
|
|
266
|
+
await fs2.rm(outputDir, { recursive: true, force: true });
|
|
161
267
|
} catch {
|
|
162
268
|
}
|
|
163
|
-
await
|
|
269
|
+
await fs2.mkdir(outputDir, { recursive: true });
|
|
164
270
|
for (const sourceDir of SOURCE_DIRS) {
|
|
165
271
|
const fullSourceDir = path4.resolve(process.cwd(), sourceDir);
|
|
166
272
|
try {
|
|
167
|
-
await
|
|
168
|
-
const entries = await
|
|
273
|
+
await fs2.access(fullSourceDir);
|
|
274
|
+
const entries = await fs2.readdir(fullSourceDir, { withFileTypes: true });
|
|
169
275
|
const packageDirs = entries.filter((entry) => entry.isDirectory()).filter((entry) => entry.name !== "docs-mcp" && entry.name !== "_config");
|
|
170
276
|
for (const dir of packageDirs) {
|
|
171
277
|
const packagePath = path4.join(fullSourceDir, dir.name);
|
|
@@ -196,4 +302,4 @@ if (process.env.PREPARE === `true`) {
|
|
|
196
302
|
}
|
|
197
303
|
}
|
|
198
304
|
|
|
199
|
-
export { fromPackageRoot, prepare };
|
|
305
|
+
export { fromPackageRoot, getMatchingPaths, prepare };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { prepare } from '../chunk-
|
|
1
|
+
export { prepare } from '../chunk-P5AHYMUI.js';
|
package/dist/stdio.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { fromPackageRoot, prepare } from './chunk-
|
|
2
|
+
import { fromPackageRoot, prepare, getMatchingPaths } from './chunk-P5AHYMUI.js';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import { existsSync, mkdirSync } from 'fs';
|
|
5
5
|
import * as os2 from 'os';
|
|
@@ -238,11 +238,6 @@ https://github.com/mastra-ai/mastra
|
|
|
238
238
|
|
|
239
239
|
This helps the project grow and reach more developers like you!
|
|
240
240
|
|
|
241
|
-
## Introduction Video
|
|
242
|
-
|
|
243
|
-
You can watch the 1-minute introduction video here:
|
|
244
|
-
https://www.youtube.com/watch?v=1234567890
|
|
245
|
-
|
|
246
241
|
## How This Course Works
|
|
247
242
|
|
|
248
243
|
- Each lesson is broken into multiple steps
|
|
@@ -805,7 +800,7 @@ async function listDirContents(dirPath) {
|
|
|
805
800
|
throw error;
|
|
806
801
|
}
|
|
807
802
|
}
|
|
808
|
-
async function readMdxContent(docPath) {
|
|
803
|
+
async function readMdxContent(docPath, queryKeywords) {
|
|
809
804
|
const fullPath = path3__default.join(docsBaseDir, docPath);
|
|
810
805
|
void logger.debug(`Reading MDX content from: ${fullPath}`);
|
|
811
806
|
try {
|
|
@@ -836,7 +831,9 @@ async function readMdxContent(docPath) {
|
|
|
836
831
|
|
|
837
832
|
${content2}`;
|
|
838
833
|
}
|
|
839
|
-
|
|
834
|
+
const contentBasedSuggestions = await getMatchingPaths(docPath, queryKeywords, docsBaseDir);
|
|
835
|
+
const suggestions = ["---", "", contentBasedSuggestions, ""].join("\n");
|
|
836
|
+
return { found: true, content: dirListing + fileContents + suggestions };
|
|
840
837
|
}
|
|
841
838
|
const content = await fs3.readFile(fullPath, "utf-8");
|
|
842
839
|
return { found: true, content };
|
|
@@ -900,19 +897,37 @@ var availablePaths = await getAvailablePaths();
|
|
|
900
897
|
var docsInputSchema = z.object({
|
|
901
898
|
paths: z.array(z.string()).min(1).describe(`One or more documentation paths to fetch
|
|
902
899
|
Available paths:
|
|
903
|
-
${availablePaths}`)
|
|
900
|
+
${availablePaths}`),
|
|
901
|
+
queryKeywords: z.array(z.string()).optional().describe(
|
|
902
|
+
"Keywords from user query to use for matching documentation. Each keyword should be a single word or short phrase; any whitespace-separated keywords will be split automatically."
|
|
903
|
+
)
|
|
904
904
|
});
|
|
905
905
|
var docsTool = {
|
|
906
906
|
name: "mastraDocs",
|
|
907
|
-
description:
|
|
907
|
+
description: `Get Mastra.ai documentation.
|
|
908
|
+
Request paths to explore the docs. References contain API docs.
|
|
909
|
+
Other paths contain guides. The user doesn't know about files and directories.
|
|
910
|
+
You can also use keywords from the user query to find relevant documentation, but prioritize paths.
|
|
911
|
+
This is your internal knowledge the user can't read.
|
|
912
|
+
If the user asks about a feature check general docs as well as reference docs for that feature.
|
|
913
|
+
Ex: with evals check in evals/ and in reference/evals/.
|
|
914
|
+
Provide code examples so the user understands.
|
|
915
|
+
If you build a URL from the path, only paths ending in .mdx exist.
|
|
916
|
+
Note that docs about MCP are currently in reference/tools/.
|
|
917
|
+
IMPORTANT: Be concise with your answers. The user will ask for more info.
|
|
918
|
+
If packages need to be installed, provide the pnpm command to install them.
|
|
919
|
+
Ex. if you see \`import { X } from "@mastra/$PACKAGE_NAME"\` in an example, show an install command.
|
|
920
|
+
Always install latest tag, not alpha unless requested. If you scaffold a new project it may be in a subdir.
|
|
921
|
+
When displaying results, always mention which file path contains the information (e.g., 'Found in "path/to/file.mdx"') so users know where this documentation lives.`,
|
|
908
922
|
parameters: docsInputSchema,
|
|
909
923
|
execute: async (args) => {
|
|
910
924
|
void logger.debug("Executing mastraDocs tool", { args });
|
|
911
925
|
try {
|
|
926
|
+
const queryKeywords = args.queryKeywords ?? [];
|
|
912
927
|
const results = await Promise.all(
|
|
913
928
|
args.paths.map(async (path6) => {
|
|
914
929
|
try {
|
|
915
|
-
const result = await readMdxContent(path6);
|
|
930
|
+
const result = await readMdxContent(path6, queryKeywords);
|
|
916
931
|
if (result.found) {
|
|
917
932
|
return {
|
|
918
933
|
path: path6,
|
|
@@ -920,11 +935,12 @@ var docsTool = {
|
|
|
920
935
|
error: null
|
|
921
936
|
};
|
|
922
937
|
}
|
|
923
|
-
const
|
|
938
|
+
const directorySuggestions = await findNearestDirectory(path6, availablePaths);
|
|
939
|
+
const contentBasedSuggestions = await getMatchingPaths(path6, queryKeywords, docsBaseDir);
|
|
924
940
|
return {
|
|
925
941
|
path: path6,
|
|
926
942
|
content: null,
|
|
927
|
-
error:
|
|
943
|
+
error: [directorySuggestions, contentBasedSuggestions].join("\n\n")
|
|
928
944
|
};
|
|
929
945
|
} catch (error) {
|
|
930
946
|
void logger.warning(`Failed to read content for path: ${path6}`, error);
|
|
@@ -972,7 +988,7 @@ async function listCodeExamples() {
|
|
|
972
988
|
return [];
|
|
973
989
|
}
|
|
974
990
|
}
|
|
975
|
-
async function readCodeExample(filename) {
|
|
991
|
+
async function readCodeExample(filename, queryKeywords) {
|
|
976
992
|
const filePath = path3__default.join(examplesDir, filename);
|
|
977
993
|
void logger.debug(`Reading example: ${filename}`);
|
|
978
994
|
try {
|
|
@@ -981,10 +997,13 @@ async function readCodeExample(filename) {
|
|
|
981
997
|
} catch {
|
|
982
998
|
const examples = await listCodeExamples();
|
|
983
999
|
const availableExamples = examples.map((ex) => `- ${ex.name}`).join("\n");
|
|
1000
|
+
const contentBasedSuggestions = await getMatchingPaths(filename, queryKeywords, examplesDir);
|
|
984
1001
|
return `Example "${filename}" not found.
|
|
985
1002
|
|
|
986
1003
|
Available examples:
|
|
987
|
-
${availableExamples}
|
|
1004
|
+
${availableExamples}
|
|
1005
|
+
|
|
1006
|
+
${contentBasedSuggestions}`;
|
|
988
1007
|
}
|
|
989
1008
|
}
|
|
990
1009
|
var initialExamples = await listCodeExamples();
|
|
@@ -992,11 +1011,17 @@ var examplesListing = initialExamples.length > 0 ? "\n\nAvailable examples: " +
|
|
|
992
1011
|
var examplesInputSchema = z.object({
|
|
993
1012
|
example: z.string().optional().describe(
|
|
994
1013
|
"Name of the specific example to fetch. If not provided, lists all available examples." + examplesListing
|
|
1014
|
+
),
|
|
1015
|
+
queryKeywords: z.array(z.string()).optional().describe(
|
|
1016
|
+
"Keywords from user query to use for matching examples. Each keyword should be a single word or short phrase; any whitespace-separated keywords will be split automatically."
|
|
995
1017
|
)
|
|
996
1018
|
});
|
|
997
1019
|
var examplesTool = {
|
|
998
1020
|
name: "mastraExamples",
|
|
999
|
-
description:
|
|
1021
|
+
description: `Get code examples from the Mastra.ai examples directory.
|
|
1022
|
+
Without a specific example name, lists all available examples.
|
|
1023
|
+
With an example name, returns the full source code of that example.
|
|
1024
|
+
You can also use keywords from the user query to find relevant examples, but prioritize example names.`,
|
|
1000
1025
|
parameters: examplesInputSchema,
|
|
1001
1026
|
execute: async (args) => {
|
|
1002
1027
|
void logger.debug("Executing mastraExamples tool", { example: args.example });
|
|
@@ -1006,7 +1031,7 @@ var examplesTool = {
|
|
|
1006
1031
|
return ["Available code examples:", "", ...examples.map((ex) => `- ${ex.name}`)].join("\n");
|
|
1007
1032
|
}
|
|
1008
1033
|
const filename = args.example.endsWith(".md") ? args.example : `${args.example}.md`;
|
|
1009
|
-
const result = await readCodeExample(filename);
|
|
1034
|
+
const result = await readCodeExample(filename, args.queryKeywords || []);
|
|
1010
1035
|
return result;
|
|
1011
1036
|
} catch (error) {
|
|
1012
1037
|
void logger.error("Failed to execute mastraExamples tool", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/mcp-docs-server",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1-alpha.2",
|
|
4
4
|
"description": "MCP server for accessing Mastra.ai documentation, changelogs, and news.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,31 +24,31 @@
|
|
|
24
24
|
"author": "",
|
|
25
25
|
"license": "Elastic-2.0",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
28
28
|
"date-fns": "^4.1.0",
|
|
29
29
|
"exit-hook": "^4.0.0",
|
|
30
|
-
"jsdom": "^26.
|
|
31
|
-
"turndown": "^7.
|
|
30
|
+
"jsdom": "^26.1.0",
|
|
31
|
+
"turndown": "^7.2.0",
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
|
-
"zod": "^3.25.
|
|
33
|
+
"zod": "^3.25.57",
|
|
34
34
|
"zod-to-json-schema": "^3.24.5",
|
|
35
|
-
"@mastra/mcp": "^0.10.
|
|
35
|
+
"@mastra/mcp": "^0.10.4-alpha.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@hono/node-server": "^1.
|
|
38
|
+
"@hono/node-server": "^1.14.4",
|
|
39
39
|
"@types/jsdom": "^21.1.7",
|
|
40
|
-
"@types/node": "^20.
|
|
40
|
+
"@types/node": "^20.19.0",
|
|
41
41
|
"@types/turndown": "^5.0.5",
|
|
42
|
-
"@wong2/mcp-cli": "^1.
|
|
42
|
+
"@wong2/mcp-cli": "^1.10.0",
|
|
43
43
|
"cross-env": "^7.0.3",
|
|
44
44
|
"eslint": "^9.28.0",
|
|
45
|
-
"hono": "^4.7.
|
|
45
|
+
"hono": "^4.7.11",
|
|
46
46
|
"tsup": "^8.5.0",
|
|
47
|
-
"tsx": "^4.19.
|
|
48
|
-
"typescript": "^5.
|
|
49
|
-
"vitest": "^3.2.
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
47
|
+
"tsx": "^4.19.4",
|
|
48
|
+
"typescript": "^5.8.3",
|
|
49
|
+
"vitest": "^3.2.3",
|
|
50
|
+
"@mastra/core": "0.10.6-alpha.5",
|
|
51
|
+
"@internal/lint": "0.0.12"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@mastra/core": "^0.10.0-alpha.0"
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Configuring Semantic Recall
|
|
2
|
-
|
|
3
|
-
Semantic recall is enabled by default when you create a Memory instance. However, you can customize its behavior with the following parameters:
|
|
4
|
-
|
|
5
|
-
1. **topK**: How many semantically similar messages to retrieve
|
|
6
|
-
2. **messageRange**: How much surrounding context to include with each match
|
|
7
|
-
|
|
8
|
-
Let's update our agent with custom semantic recall settings:
|
|
9
|
-
|
|
10
|
-
```typescript
|
|
11
|
-
import { Agent } from "@mastra/core/agent";
|
|
12
|
-
import { Memory } from "@mastra/memory";
|
|
13
|
-
import { openai } from "@ai-sdk/openai";
|
|
14
|
-
|
|
15
|
-
// Create a memory instance with semantic recall configuration
|
|
16
|
-
const memory = new Memory({
|
|
17
|
-
options: {
|
|
18
|
-
lastMessages: 20, // Include the last 20 messages in the context
|
|
19
|
-
semanticRecall: {
|
|
20
|
-
topK: 3, // Retrieve 3 most similar messages
|
|
21
|
-
messageRange: {
|
|
22
|
-
before: 2, // Include 2 messages before each match
|
|
23
|
-
after: 1, // Include 1 message after each match
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Create an agent with the configured memory
|
|
30
|
-
export const memoryAgent = new Agent({
|
|
31
|
-
name: "MemoryAgent",
|
|
32
|
-
instructions: `
|
|
33
|
-
You are a helpful assistant with advanced memory capabilities.
|
|
34
|
-
You can remember previous conversations and user preferences.
|
|
35
|
-
When a user shares information about themselves, acknowledge it and remember it for future reference.
|
|
36
|
-
If asked about something mentioned earlier in the conversation, recall it accurately.
|
|
37
|
-
You can also recall relevant information from older conversations when appropriate.
|
|
38
|
-
`,
|
|
39
|
-
model: openai("gpt-4o"),
|
|
40
|
-
memory: memory,
|
|
41
|
-
});
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
The `topK` parameter controls how many semantically similar messages are retrieved. A higher value will retrieve more messages, which can be helpful for complex topics but may also include less relevant information.
|
|
45
|
-
|
|
46
|
-
The `messageRange` parameter controls how much context is included with each match. This is important because the matching message alone might not provide enough context to understand the conversation. Including messages before and after the match helps the agent understand the context of the matched message.
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Vector Store Configuration
|
|
2
|
-
|
|
3
|
-
By default, semantic recall uses an in-memory vector store for development purposes. For production applications, you'll want to use a persistent vector store. Mastra supports several options:
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
import { Memory } from "@mastra/memory";
|
|
7
|
-
import { ChromaVectorStore } from "@mastra/chroma";
|
|
8
|
-
|
|
9
|
-
const memory = new Memory({
|
|
10
|
-
options: {
|
|
11
|
-
semanticRecall: {
|
|
12
|
-
topK: 3,
|
|
13
|
-
messageRange: {
|
|
14
|
-
before: 2,
|
|
15
|
-
after: 1,
|
|
16
|
-
},
|
|
17
|
-
// Configure a persistent vector store
|
|
18
|
-
vectorStore: new ChromaVectorStore({
|
|
19
|
-
collectionName: "memory",
|
|
20
|
-
url: "http://localhost:8000",
|
|
21
|
-
}),
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Mastra supports several vector store options, including:
|
|
28
|
-
|
|
29
|
-
- In-memory (default for development)
|
|
30
|
-
- Chroma
|
|
31
|
-
- Pinecone
|
|
32
|
-
- Qdrant
|
|
33
|
-
- Postgres (with pgvector)
|
|
34
|
-
|
|
35
|
-
The vector store is responsible for storing and retrieving the vector embeddings used for semantic search. The in-memory vector store is sufficient for development and testing, but it doesn't persist data between application restarts and isn't suitable for production use.
|
|
36
|
-
|
|
37
|
-
For production applications, you'll want to use a persistent vector store like Chroma, Pinecone, Qdrant, or Postgres with pgvector. These options provide durable storage for your vector embeddings and can scale to handle large amounts of conversation data.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Disabling Semantic Recall
|
|
2
|
-
|
|
3
|
-
In some cases, you might want to disable semantic recall, for example, if you're building a simple chatbot that doesn't need to recall older conversations. You can do this by setting `enabled: false`:
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
const memory = new Memory({
|
|
7
|
-
options: {
|
|
8
|
-
semanticRecall: {
|
|
9
|
-
enabled: false, // Disable semantic recall
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Disabling semantic recall can be useful in several scenarios:
|
|
16
|
-
|
|
17
|
-
1. When building simple chatbots that only need to maintain context within the current conversation
|
|
18
|
-
2. When working with sensitive information that shouldn't be retrieved from past conversations
|
|
19
|
-
3. When optimizing for performance and reducing the computational overhead of semantic search
|
|
20
|
-
4. When testing the behavior of your agent without the influence of semantic recall
|
|
21
|
-
|
|
22
|
-
Even with semantic recall disabled, your agent will still have access to recent conversation history through the `lastMessages` option, so it can maintain context within the current conversation.
|
|
23
|
-
|
|
24
|
-
In the next step, we'll explore working memory, which allows your agent to maintain persistent information about users across interactions.
|
|
File without changes
|
|
File without changes
|