@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.
Files changed (104) hide show
  1. package/.docs/organized/changelogs/%40internal%2Fstorage-test-utils.md +7 -0
  2. package/.docs/organized/changelogs/%40mastra%2Fagui.md +14 -0
  3. package/.docs/organized/changelogs/%40mastra%2Fchroma.md +13 -13
  4. package/.docs/organized/changelogs/%40mastra%2Fclickhouse.md +26 -26
  5. package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +64 -64
  6. package/.docs/organized/changelogs/%40mastra%2Fcloud.md +14 -14
  7. package/.docs/organized/changelogs/%40mastra%2Fcloudflare-d1.md +15 -15
  8. package/.docs/organized/changelogs/%40mastra%2Fcloudflare.md +10 -10
  9. package/.docs/organized/changelogs/%40mastra%2Fcore.md +65 -65
  10. package/.docs/organized/changelogs/%40mastra%2Fcouchbase.md +12 -0
  11. package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +82 -82
  12. package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +79 -79
  13. package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +77 -77
  14. package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +94 -94
  15. package/.docs/organized/changelogs/%40mastra%2Fdynamodb.md +54 -0
  16. package/.docs/organized/changelogs/%40mastra%2Fevals.md +13 -13
  17. package/.docs/organized/changelogs/%40mastra%2Ffirecrawl.md +16 -16
  18. package/.docs/organized/changelogs/%40mastra%2Fgithub.md +13 -13
  19. package/.docs/organized/changelogs/%40mastra%2Flance.md +12 -0
  20. package/.docs/organized/changelogs/%40mastra%2Flibsql.md +13 -13
  21. package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +47 -47
  22. package/.docs/organized/changelogs/%40mastra%2Fmcp-registry-registry.md +37 -37
  23. package/.docs/organized/changelogs/%40mastra%2Fmcp.md +22 -22
  24. package/.docs/organized/changelogs/%40mastra%2Fmem0.md +13 -13
  25. package/.docs/organized/changelogs/%40mastra%2Fmemory.md +32 -32
  26. package/.docs/organized/changelogs/%40mastra%2Fmongodb.md +27 -27
  27. package/.docs/organized/changelogs/%40mastra%2Fopensearch.md +12 -0
  28. package/.docs/organized/changelogs/%40mastra%2Fpg.md +51 -51
  29. package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +108 -108
  30. package/.docs/organized/changelogs/%40mastra%2Fqdrant.md +13 -13
  31. package/.docs/organized/changelogs/%40mastra%2Frag.md +17 -17
  32. package/.docs/organized/changelogs/%40mastra%2Fragie.md +13 -13
  33. package/.docs/organized/changelogs/%40mastra%2Fserver.md +66 -66
  34. package/.docs/organized/changelogs/%40mastra%2Fturbopuffer.md +13 -13
  35. package/.docs/organized/changelogs/%40mastra%2Fupstash.md +37 -37
  36. package/.docs/organized/changelogs/%40mastra%2Fvoice-azure.md +13 -13
  37. package/.docs/organized/changelogs/%40mastra%2Fvoice-cloudflare.md +13 -13
  38. package/.docs/organized/changelogs/%40mastra%2Fvoice-deepgram.md +13 -13
  39. package/.docs/organized/changelogs/%40mastra%2Fvoice-elevenlabs.md +13 -13
  40. package/.docs/organized/changelogs/%40mastra%2Fvoice-gladia.md +9 -0
  41. package/.docs/organized/changelogs/%40mastra%2Fvoice-google.md +13 -13
  42. package/.docs/organized/changelogs/%40mastra%2Fvoice-murf.md +14 -14
  43. package/.docs/organized/changelogs/%40mastra%2Fvoice-openai-realtime.md +24 -24
  44. package/.docs/organized/changelogs/%40mastra%2Fvoice-openai.md +13 -13
  45. package/.docs/organized/changelogs/%40mastra%2Fvoice-playai.md +13 -13
  46. package/.docs/organized/changelogs/%40mastra%2Fvoice-sarvam.md +13 -13
  47. package/.docs/organized/changelogs/%40mastra%2Fvoice-speechify.md +13 -13
  48. package/.docs/organized/changelogs/create-mastra.md +35 -35
  49. package/.docs/organized/changelogs/mastra.md +124 -124
  50. package/.docs/organized/code-examples/agent.md +5 -2
  51. package/.docs/organized/code-examples/agui.md +4 -1
  52. package/.docs/organized/code-examples/ai-sdk-useChat.md +1 -1
  53. package/.docs/organized/code-examples/fireworks-r1.md +1 -1
  54. package/.docs/organized/code-examples/memory-with-processors.md +2 -2
  55. package/.docs/organized/code-examples/openapi-spec-writer.md +1 -1
  56. package/.docs/organized/code-examples/quick-start.md +1 -1
  57. package/.docs/organized/code-examples/weather-agent.md +7 -1
  58. package/.docs/raw/course/01-first-agent/03-verifying-installation.md +4 -2
  59. package/.docs/raw/course/01-first-agent/16-adding-memory-to-agent.md +1 -1
  60. package/.docs/raw/course/02-agent-tools-mcp/15-updating-mcp-config-github.md +1 -1
  61. package/.docs/raw/course/02-agent-tools-mcp/20-updating-mcp-config-hackernews.md +1 -1
  62. package/.docs/raw/course/02-agent-tools-mcp/26-updating-mcp-config-filesystem.md +1 -1
  63. package/.docs/raw/course/03-agent-memory/03-installing-memory.md +4 -2
  64. package/.docs/raw/course/03-agent-memory/04-creating-basic-memory-agent.md +1 -1
  65. package/.docs/raw/course/03-agent-memory/08-configuring-conversation-history.md +3 -3
  66. package/.docs/raw/course/03-agent-memory/13-vector-store-configuration.md +27 -0
  67. package/.docs/raw/course/03-agent-memory/{13-what-is-semantic-recall.md → 14-what-is-semantic-recall.md} +1 -1
  68. package/.docs/raw/course/03-agent-memory/16-configuring-semantic-recall.md +41 -0
  69. package/.docs/raw/course/03-agent-memory/18-advanced-configuration-semantic-recall.md +28 -0
  70. package/.docs/raw/course/03-agent-memory/21-configuring-working-memory.md +9 -9
  71. package/.docs/raw/course/03-agent-memory/22-custom-working-memory-templates.md +10 -2
  72. package/.docs/raw/course/03-agent-memory/25-combining-memory-features.md +8 -1
  73. package/.docs/raw/course/03-agent-memory/27-creating-learning-assistant.md +8 -1
  74. package/.docs/raw/deployment/deployment.mdx +26 -97
  75. package/.docs/raw/deployment/overview.mdx +18 -3
  76. package/.docs/raw/deployment/web-framework.mdx +63 -0
  77. package/.docs/raw/frameworks/web-frameworks/astro.mdx +7 -1
  78. package/.docs/raw/frameworks/web-frameworks/next-js.mdx +1 -1
  79. package/.docs/raw/getting-started/installation.mdx +98 -558
  80. package/.docs/raw/getting-started/project-structure.mdx +3 -16
  81. package/.docs/raw/rag/vector-databases.mdx +4 -7
  82. package/.docs/raw/reference/agents/generate.mdx +35 -3
  83. package/.docs/raw/reference/agents/stream.mdx +35 -3
  84. package/.docs/raw/reference/client-js/memory.mdx +14 -0
  85. package/.docs/raw/reference/client-js/workflows.mdx +28 -0
  86. package/.docs/raw/reference/deployer/cloudflare.mdx +9 -3
  87. package/.docs/raw/reference/deployer/deployer.mdx +1 -1
  88. package/.docs/raw/reference/deployer/netlify.mdx +25 -4
  89. package/.docs/raw/reference/deployer/vercel.mdx +10 -4
  90. package/.docs/raw/workflows/control-flow.mdx +45 -171
  91. package/.docs/raw/workflows/input-data-mapping.mdx +21 -88
  92. package/.docs/raw/workflows/overview.mdx +24 -47
  93. package/.docs/raw/workflows/suspend-and-resume.mdx +46 -34
  94. package/.docs/raw/workflows/using-with-agents-and-tools.mdx +55 -191
  95. package/dist/_tsup-dts-rollup.d.ts +14 -0
  96. package/dist/{chunk-QWIXFGFR.js → chunk-P5AHYMUI.js} +126 -20
  97. package/dist/prepare-docs/prepare.js +1 -1
  98. package/dist/stdio.js +42 -17
  99. package/package.json +15 -15
  100. package/.docs/raw/course/03-agent-memory/15-configuring-semantic-recall.md +0 -46
  101. package/.docs/raw/course/03-agent-memory/16-vector-store-configuration.md +0 -37
  102. package/.docs/raw/course/03-agent-memory/18-disabling-semantic-recall.md +0 -24
  103. /package/.docs/raw/{deployment/client.mdx → client-js/overview.mdx} +0 -0
  104. /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 fs.rm(OUTPUT_DIR, { recursive: true, force: true });
124
+ await fs2.rm(OUTPUT_DIR, { recursive: true, force: true });
19
125
  } catch {
20
126
  }
21
- await fs.mkdir(OUTPUT_DIR, { recursive: true });
22
- const examples = await fs.readdir(EXAMPLES_SOURCE, { withFileTypes: true });
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 fs.readFile(path4.join(examplePath, "package.json"), "utf-8");
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 fs.writeFile(outputFile, output, "utf-8");
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 fs.readdir(currentPath, { withFileTypes: true });
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 fs.readFile(fullPath, "utf-8");
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 fs.mkdir(dest, { recursive: true });
87
- const entries = await fs.readdir(src, { withFileTypes: true });
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 fs.copyFile(srcPath, destPath);
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 fs.rm(DOCS_DEST, { recursive: true });
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 fs.readFile(packageJsonPath, "utf-8"));
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 fs.readFile(changelogPath, "utf-8");
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 fs.writeFile(outputFile, changelog, "utf-8");
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 fs.rm(outputDir, { recursive: true, force: true });
266
+ await fs2.rm(outputDir, { recursive: true, force: true });
161
267
  } catch {
162
268
  }
163
- await fs.mkdir(outputDir, { recursive: true });
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 fs.access(fullSourceDir);
168
- const entries = await fs.readdir(fullSourceDir, { withFileTypes: true });
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-QWIXFGFR.js';
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-QWIXFGFR.js';
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
- return { found: true, content: dirListing + fileContents };
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: "Get Mastra.ai documentation. Request paths to explore the docs. References contain API docs. Other paths contain guides. The user doesn't know about files and directories. This is your internal knowledge the user can't read. If the user asks about a feature check general docs as well as reference docs for that feature. Ex: with evals check in evals/ and in reference/evals/. Provide code examples so the user understands. If you build a URL from the path, only paths ending in .mdx exist. Note that docs about MCP are currently in reference/tools/. IMPORTANT: Be concise with your answers. The user will ask for more info. If packages need to be installed, provide the pnpm command to install them. Ex. if you see `import { X } from \"@mastra/$PACKAGE_NAME\"` in an example, show an install command. Always install latest tag, not alpha unless requested. If you scaffold a new project it may be in a subdir",
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 suggestions = await findNearestDirectory(path6, availablePaths);
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: suggestions
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: "Get code examples from the Mastra.ai examples directory. Without a specific example name, lists all available examples. With an example name, returns the full source code of that example.",
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.0",
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.9.0",
27
+ "@modelcontextprotocol/sdk": "^1.12.1",
28
28
  "date-fns": "^4.1.0",
29
29
  "exit-hook": "^4.0.0",
30
- "jsdom": "^26.0.0",
31
- "turndown": "^7.1.2",
30
+ "jsdom": "^26.1.0",
31
+ "turndown": "^7.2.0",
32
32
  "uuid": "^11.1.0",
33
- "zod": "^3.25.56",
33
+ "zod": "^3.25.57",
34
34
  "zod-to-json-schema": "^3.24.5",
35
- "@mastra/mcp": "^0.10.3"
35
+ "@mastra/mcp": "^0.10.4-alpha.1"
36
36
  },
37
37
  "devDependencies": {
38
- "@hono/node-server": "^1.13.8",
38
+ "@hono/node-server": "^1.14.4",
39
39
  "@types/jsdom": "^21.1.7",
40
- "@types/node": "^20.17.57",
40
+ "@types/node": "^20.19.0",
41
41
  "@types/turndown": "^5.0.5",
42
- "@wong2/mcp-cli": "^1.6.0",
42
+ "@wong2/mcp-cli": "^1.10.0",
43
43
  "cross-env": "^7.0.3",
44
44
  "eslint": "^9.28.0",
45
- "hono": "^4.7.4",
45
+ "hono": "^4.7.11",
46
46
  "tsup": "^8.5.0",
47
- "tsx": "^4.19.3",
48
- "typescript": "^5.3.3",
49
- "vitest": "^3.2.2",
50
- "@internal/lint": "0.0.12",
51
- "@mastra/core": "0.10.5"
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.