@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.
Files changed (77) hide show
  1. package/.docs/organized/changelogs/%40mastra%2Fclickhouse.md +15 -15
  2. package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +44 -44
  3. package/.docs/organized/changelogs/%40mastra%2Fcloudflare-d1.md +15 -15
  4. package/.docs/organized/changelogs/%40mastra%2Fcore.md +37 -37
  5. package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +53 -53
  6. package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +53 -53
  7. package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +54 -54
  8. package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +63 -63
  9. package/.docs/organized/changelogs/%40mastra%2Fdynamodb.md +40 -0
  10. package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +19 -19
  11. package/.docs/organized/changelogs/%40mastra%2Fmcp-registry-registry.md +24 -24
  12. package/.docs/organized/changelogs/%40mastra%2Fmcp.md +8 -8
  13. package/.docs/organized/changelogs/%40mastra%2Fmemory.md +13 -13
  14. package/.docs/organized/changelogs/%40mastra%2Fmongodb.md +14 -14
  15. package/.docs/organized/changelogs/%40mastra%2Fpg.md +31 -31
  16. package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +50 -50
  17. package/.docs/organized/changelogs/%40mastra%2Fserver.md +47 -47
  18. package/.docs/organized/changelogs/%40mastra%2Fupstash.md +37 -37
  19. package/.docs/organized/changelogs/%40mastra%2Fvoice-gladia.md +9 -0
  20. package/.docs/organized/changelogs/%40mastra%2Fvoice-openai-realtime.md +12 -12
  21. package/.docs/organized/changelogs/create-mastra.md +15 -15
  22. package/.docs/organized/changelogs/mastra.md +86 -86
  23. package/.docs/organized/code-examples/agent.md +1 -1
  24. package/.docs/organized/code-examples/agui.md +4 -1
  25. package/.docs/organized/code-examples/ai-sdk-useChat.md +1 -1
  26. package/.docs/organized/code-examples/fireworks-r1.md +1 -1
  27. package/.docs/organized/code-examples/memory-with-processors.md +2 -2
  28. package/.docs/organized/code-examples/openapi-spec-writer.md +1 -1
  29. package/.docs/organized/code-examples/quick-start.md +1 -1
  30. package/.docs/organized/code-examples/weather-agent.md +7 -1
  31. package/.docs/raw/course/01-first-agent/03-verifying-installation.md +4 -2
  32. package/.docs/raw/course/01-first-agent/16-adding-memory-to-agent.md +1 -1
  33. package/.docs/raw/course/02-agent-tools-mcp/15-updating-mcp-config-github.md +1 -1
  34. package/.docs/raw/course/02-agent-tools-mcp/20-updating-mcp-config-hackernews.md +1 -1
  35. package/.docs/raw/course/02-agent-tools-mcp/26-updating-mcp-config-filesystem.md +1 -1
  36. package/.docs/raw/course/03-agent-memory/03-installing-memory.md +4 -2
  37. package/.docs/raw/course/03-agent-memory/04-creating-basic-memory-agent.md +1 -1
  38. package/.docs/raw/course/03-agent-memory/08-configuring-conversation-history.md +3 -3
  39. package/.docs/raw/course/03-agent-memory/13-vector-store-configuration.md +27 -0
  40. package/.docs/raw/course/03-agent-memory/{13-what-is-semantic-recall.md → 14-what-is-semantic-recall.md} +1 -1
  41. package/.docs/raw/course/03-agent-memory/16-configuring-semantic-recall.md +41 -0
  42. package/.docs/raw/course/03-agent-memory/18-advanced-configuration-semantic-recall.md +28 -0
  43. package/.docs/raw/course/03-agent-memory/21-configuring-working-memory.md +9 -9
  44. package/.docs/raw/course/03-agent-memory/22-custom-working-memory-templates.md +10 -2
  45. package/.docs/raw/course/03-agent-memory/25-combining-memory-features.md +8 -1
  46. package/.docs/raw/course/03-agent-memory/27-creating-learning-assistant.md +8 -1
  47. package/.docs/raw/deployment/deployment.mdx +26 -97
  48. package/.docs/raw/deployment/overview.mdx +18 -3
  49. package/.docs/raw/deployment/web-framework.mdx +63 -0
  50. package/.docs/raw/frameworks/web-frameworks/astro.mdx +7 -1
  51. package/.docs/raw/frameworks/web-frameworks/next-js.mdx +1 -1
  52. package/.docs/raw/getting-started/installation.mdx +98 -558
  53. package/.docs/raw/getting-started/project-structure.mdx +3 -16
  54. package/.docs/raw/rag/vector-databases.mdx +4 -7
  55. package/.docs/raw/reference/agents/generate.mdx +35 -3
  56. package/.docs/raw/reference/agents/stream.mdx +35 -3
  57. package/.docs/raw/reference/client-js/memory.mdx +14 -0
  58. package/.docs/raw/reference/client-js/workflows.mdx +28 -0
  59. package/.docs/raw/reference/deployer/cloudflare.mdx +9 -3
  60. package/.docs/raw/reference/deployer/deployer.mdx +1 -1
  61. package/.docs/raw/reference/deployer/netlify.mdx +25 -4
  62. package/.docs/raw/reference/deployer/vercel.mdx +10 -4
  63. package/.docs/raw/workflows/control-flow.mdx +45 -171
  64. package/.docs/raw/workflows/input-data-mapping.mdx +21 -88
  65. package/.docs/raw/workflows/overview.mdx +23 -46
  66. package/.docs/raw/workflows/suspend-and-resume.mdx +46 -34
  67. package/.docs/raw/workflows/using-with-agents-and-tools.mdx +55 -191
  68. package/dist/_tsup-dts-rollup.d.ts +14 -0
  69. package/dist/{chunk-QWIXFGFR.js → chunk-P5AHYMUI.js} +126 -20
  70. package/dist/prepare-docs/prepare.js +1 -1
  71. package/dist/stdio.js +42 -12
  72. package/package.json +4 -4
  73. package/.docs/raw/course/03-agent-memory/15-configuring-semantic-recall.md +0 -46
  74. package/.docs/raw/course/03-agent-memory/16-vector-store-configuration.md +0 -37
  75. package/.docs/raw/course/03-agent-memory/18-disabling-semantic-recall.md +0 -24
  76. /package/.docs/raw/{deployment/client.mdx → client-js/overview.mdx} +0 -0
  77. /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';
@@ -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
- 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 };
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: "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.`,
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 suggestions = await findNearestDirectory(path6, availablePaths);
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: suggestions
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: "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.`,
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-alpha.0",
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-alpha.0"
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
- "@mastra/core": "0.10.6-alpha.0",
51
- "@internal/lint": "0.0.12"
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.