@mastra/mcp-docs-server 0.13.1-alpha.0 → 0.13.1
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/%40mastra%2Fclickhouse.md +15 -15
- package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +44 -44
- package/.docs/organized/changelogs/%40mastra%2Fcloudflare-d1.md +15 -15
- package/.docs/organized/changelogs/%40mastra%2Fcore.md +37 -37
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +53 -53
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +53 -53
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +54 -54
- package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +63 -63
- package/.docs/organized/changelogs/%40mastra%2Fdynamodb.md +40 -0
- package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +19 -19
- package/.docs/organized/changelogs/%40mastra%2Fmcp-registry-registry.md +24 -24
- package/.docs/organized/changelogs/%40mastra%2Fmcp.md +8 -8
- package/.docs/organized/changelogs/%40mastra%2Fmemory.md +13 -13
- package/.docs/organized/changelogs/%40mastra%2Fmongodb.md +14 -14
- package/.docs/organized/changelogs/%40mastra%2Fpg.md +31 -31
- package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +50 -50
- package/.docs/organized/changelogs/%40mastra%2Fserver.md +47 -47
- package/.docs/organized/changelogs/%40mastra%2Fupstash.md +37 -37
- package/.docs/organized/changelogs/%40mastra%2Fvoice-gladia.md +9 -0
- package/.docs/organized/changelogs/%40mastra%2Fvoice-openai-realtime.md +12 -12
- package/.docs/organized/changelogs/create-mastra.md +15 -15
- package/.docs/organized/changelogs/mastra.md +86 -86
- package/.docs/organized/code-examples/agent.md +1 -1
- 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 +23 -46
- 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 -12
- package/package.json +4 -4
- 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';
|
|
@@ -800,7 +800,7 @@ async function listDirContents(dirPath) {
|
|
|
800
800
|
throw error;
|
|
801
801
|
}
|
|
802
802
|
}
|
|
803
|
-
async function readMdxContent(docPath) {
|
|
803
|
+
async function readMdxContent(docPath, queryKeywords) {
|
|
804
804
|
const fullPath = path3__default.join(docsBaseDir, docPath);
|
|
805
805
|
void logger.debug(`Reading MDX content from: ${fullPath}`);
|
|
806
806
|
try {
|
|
@@ -831,7 +831,9 @@ async function readMdxContent(docPath) {
|
|
|
831
831
|
|
|
832
832
|
${content2}`;
|
|
833
833
|
}
|
|
834
|
-
|
|
834
|
+
const contentBasedSuggestions = await getMatchingPaths(docPath, queryKeywords, docsBaseDir);
|
|
835
|
+
const suggestions = ["---", "", contentBasedSuggestions, ""].join("\n");
|
|
836
|
+
return { found: true, content: dirListing + fileContents + suggestions };
|
|
835
837
|
}
|
|
836
838
|
const content = await fs3.readFile(fullPath, "utf-8");
|
|
837
839
|
return { found: true, content };
|
|
@@ -895,19 +897,37 @@ var availablePaths = await getAvailablePaths();
|
|
|
895
897
|
var docsInputSchema = z.object({
|
|
896
898
|
paths: z.array(z.string()).min(1).describe(`One or more documentation paths to fetch
|
|
897
899
|
Available paths:
|
|
898
|
-
${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
|
+
)
|
|
899
904
|
});
|
|
900
905
|
var docsTool = {
|
|
901
906
|
name: "mastraDocs",
|
|
902
|
-
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.`,
|
|
903
922
|
parameters: docsInputSchema,
|
|
904
923
|
execute: async (args) => {
|
|
905
924
|
void logger.debug("Executing mastraDocs tool", { args });
|
|
906
925
|
try {
|
|
926
|
+
const queryKeywords = args.queryKeywords ?? [];
|
|
907
927
|
const results = await Promise.all(
|
|
908
928
|
args.paths.map(async (path6) => {
|
|
909
929
|
try {
|
|
910
|
-
const result = await readMdxContent(path6);
|
|
930
|
+
const result = await readMdxContent(path6, queryKeywords);
|
|
911
931
|
if (result.found) {
|
|
912
932
|
return {
|
|
913
933
|
path: path6,
|
|
@@ -915,11 +935,12 @@ var docsTool = {
|
|
|
915
935
|
error: null
|
|
916
936
|
};
|
|
917
937
|
}
|
|
918
|
-
const
|
|
938
|
+
const directorySuggestions = await findNearestDirectory(path6, availablePaths);
|
|
939
|
+
const contentBasedSuggestions = await getMatchingPaths(path6, queryKeywords, docsBaseDir);
|
|
919
940
|
return {
|
|
920
941
|
path: path6,
|
|
921
942
|
content: null,
|
|
922
|
-
error:
|
|
943
|
+
error: [directorySuggestions, contentBasedSuggestions].join("\n\n")
|
|
923
944
|
};
|
|
924
945
|
} catch (error) {
|
|
925
946
|
void logger.warning(`Failed to read content for path: ${path6}`, error);
|
|
@@ -967,7 +988,7 @@ async function listCodeExamples() {
|
|
|
967
988
|
return [];
|
|
968
989
|
}
|
|
969
990
|
}
|
|
970
|
-
async function readCodeExample(filename) {
|
|
991
|
+
async function readCodeExample(filename, queryKeywords) {
|
|
971
992
|
const filePath = path3__default.join(examplesDir, filename);
|
|
972
993
|
void logger.debug(`Reading example: ${filename}`);
|
|
973
994
|
try {
|
|
@@ -976,10 +997,13 @@ async function readCodeExample(filename) {
|
|
|
976
997
|
} catch {
|
|
977
998
|
const examples = await listCodeExamples();
|
|
978
999
|
const availableExamples = examples.map((ex) => `- ${ex.name}`).join("\n");
|
|
1000
|
+
const contentBasedSuggestions = await getMatchingPaths(filename, queryKeywords, examplesDir);
|
|
979
1001
|
return `Example "${filename}" not found.
|
|
980
1002
|
|
|
981
1003
|
Available examples:
|
|
982
|
-
${availableExamples}
|
|
1004
|
+
${availableExamples}
|
|
1005
|
+
|
|
1006
|
+
${contentBasedSuggestions}`;
|
|
983
1007
|
}
|
|
984
1008
|
}
|
|
985
1009
|
var initialExamples = await listCodeExamples();
|
|
@@ -987,11 +1011,17 @@ var examplesListing = initialExamples.length > 0 ? "\n\nAvailable examples: " +
|
|
|
987
1011
|
var examplesInputSchema = z.object({
|
|
988
1012
|
example: z.string().optional().describe(
|
|
989
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."
|
|
990
1017
|
)
|
|
991
1018
|
});
|
|
992
1019
|
var examplesTool = {
|
|
993
1020
|
name: "mastraExamples",
|
|
994
|
-
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.`,
|
|
995
1025
|
parameters: examplesInputSchema,
|
|
996
1026
|
execute: async (args) => {
|
|
997
1027
|
void logger.debug("Executing mastraExamples tool", { example: args.example });
|
|
@@ -1001,7 +1031,7 @@ var examplesTool = {
|
|
|
1001
1031
|
return ["Available code examples:", "", ...examples.map((ex) => `- ${ex.name}`)].join("\n");
|
|
1002
1032
|
}
|
|
1003
1033
|
const filename = args.example.endsWith(".md") ? args.example : `${args.example}.md`;
|
|
1004
|
-
const result = await readCodeExample(filename);
|
|
1034
|
+
const result = await readCodeExample(filename, args.queryKeywords || []);
|
|
1005
1035
|
return result;
|
|
1006
1036
|
} catch (error) {
|
|
1007
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.1
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "MCP server for accessing Mastra.ai documentation, changelogs, and news.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"uuid": "^11.1.0",
|
|
33
33
|
"zod": "^3.25.57",
|
|
34
34
|
"zod-to-json-schema": "^3.24.5",
|
|
35
|
-
"@mastra/mcp": "^0.10.4
|
|
35
|
+
"@mastra/mcp": "^0.10.4"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@hono/node-server": "^1.14.4",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"tsx": "^4.19.4",
|
|
48
48
|
"typescript": "^5.8.3",
|
|
49
49
|
"vitest": "^3.2.3",
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
50
|
+
"@internal/lint": "0.0.13",
|
|
51
|
+
"@mastra/core": "0.10.6"
|
|
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
|