@mastra/mcp-docs-server 0.0.3 → 0.0.4-alpha.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%2Fastra.md +27 -27
- package/.docs/organized/changelogs/%40mastra%2Fchroma.md +27 -27
- package/.docs/organized/changelogs/%40mastra%2Fclient-js.md +29 -29
- package/.docs/organized/changelogs/%40mastra%2Fcomposio.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fcore.md +23 -23
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-cloudflare.md +36 -36
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-netlify.md +35 -35
- package/.docs/organized/changelogs/%40mastra%2Fdeployer-vercel.md +35 -35
- package/.docs/organized/changelogs/%40mastra%2Fdeployer.md +32 -32
- package/.docs/organized/changelogs/%40mastra%2Fevals.md +27 -27
- package/.docs/organized/changelogs/%40mastra%2Ffirecrawl.md +29 -29
- package/.docs/organized/changelogs/%40mastra%2Fgithub.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Floggers.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fmcp-docs-server.md +26 -0
- package/.docs/organized/changelogs/%40mastra%2Fmcp.md +27 -27
- package/.docs/organized/changelogs/%40mastra%2Fmemory.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fpg.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fpinecone.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fplayground-ui.md +35 -35
- package/.docs/organized/changelogs/%40mastra%2Fqdrant.md +27 -27
- package/.docs/organized/changelogs/%40mastra%2Frag.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fragie.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-azure.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-deepgram.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-elevenlabs.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-google.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-ibm.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-murf.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-openai.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-playai.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-replicate.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fspeech-speechify.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fstabilityai.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fturbopuffer.md +25 -0
- package/.docs/organized/changelogs/%40mastra%2Fupstash.md +31 -31
- package/.docs/organized/changelogs/%40mastra%2Fvectorize.md +30 -30
- package/.docs/organized/changelogs/%40mastra%2Fvoice-azure.md +9 -0
- package/.docs/organized/changelogs/%40mastra%2Fvoice-cloudflare.md +9 -0
- package/.docs/organized/changelogs/%40mastra%2Fvoice-deepgram.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fvoice-elevenlabs.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fvoice-google.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fvoice-murf.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fvoice-openai-realtime.md +25 -0
- package/.docs/organized/changelogs/%40mastra%2Fvoice-openai.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fvoice-playai.md +26 -26
- package/.docs/organized/changelogs/%40mastra%2Fvoice-sarvam.md +27 -0
- package/.docs/organized/changelogs/%40mastra%2Fvoice-speechify.md +26 -26
- package/.docs/organized/changelogs/create-mastra.md +22 -22
- package/.docs/organized/changelogs/mastra.md +47 -47
- package/.docs/organized/code-examples/ai-sdk-useChat.md +2 -1
- package/.docs/raw/agents/02-adding-tools.mdx +6 -0
- package/.docs/raw/agents/02a-mcp-guide.mdx +192 -0
- package/.docs/raw/agents/03-adding-voice.mdx +8 -8
- package/.docs/raw/deployment/deployment.mdx +5 -42
- package/.docs/raw/deployment/server.mdx +45 -3
- package/.docs/raw/evals/00-overview.mdx +2 -2
- package/.docs/raw/evals/03-running-in-ci.mdx +7 -4
- package/.docs/raw/getting-started/mcp-docs-server.mdx +5 -2
- package/.docs/raw/guides/04-research-assistant.mdx +273 -0
- package/.docs/raw/local-dev/mastra-dev.mdx +2 -2
- package/.docs/raw/observability/logging.mdx +38 -0
- package/.docs/raw/observability/nextjs-tracing.mdx +102 -0
- package/.docs/raw/observability/tracing.mdx +110 -0
- package/.docs/raw/rag/overview.mdx +3 -3
- package/.docs/raw/rag/retrieval.mdx +7 -4
- package/.docs/raw/rag/vector-databases.mdx +107 -40
- package/.docs/raw/reference/client-js/memory.mdx +6 -3
- package/.docs/raw/reference/client-js/workflows.mdx +1 -0
- package/.docs/raw/reference/observability/providers/langsmith.mdx +2 -0
- package/.docs/raw/reference/rag/libsql.mdx +3 -3
- package/.docs/raw/reference/rag/upstash.mdx +50 -1
- package/.docs/raw/reference/rag/vectorize.mdx +48 -3
- package/.docs/raw/reference/tools/client.mdx +10 -2
- package/.docs/raw/reference/tools/vector-query-tool.mdx +1 -1
- package/.docs/raw/reference/voice/sarvam.mdx +260 -0
- package/.docs/raw/reference/workflows/afterEvent.mdx +76 -0
- package/.docs/raw/reference/workflows/events.mdx +305 -0
- package/.docs/raw/reference/workflows/resumeWithEvent.mdx +134 -0
- package/.docs/raw/reference/workflows/snapshots.mdx +204 -0
- package/.docs/raw/reference/workflows/step-retries.mdx +203 -0
- package/.docs/raw/voice/overview.mdx +135 -0
- package/.docs/raw/voice/speech-to-text.mdx +45 -0
- package/.docs/raw/voice/text-to-speech.mdx +52 -0
- package/.docs/raw/voice/voice-to-voice.mdx +310 -0
- package/.docs/raw/workflows/dynamic-workflows.mdx +4 -0
- package/.docs/raw/workflows/error-handling.mdx +183 -0
- package/.docs/raw/workflows/steps.mdx +12 -2
- package/.docs/raw/workflows/suspend-and-resume.mdx +207 -2
- package/.docs/raw/workflows/variables.mdx +23 -3
- package/dist/_tsup-dts-rollup.d.ts +83 -0
- package/dist/chunk-YEOOTUPA.js +191 -0
- package/dist/prepare-docs/prepare.d.ts +1 -1
- package/dist/prepare-docs/prepare.js +1 -13
- package/dist/stdio.d.ts +0 -1
- package/dist/stdio.js +352 -5
- package/package.json +9 -15
- package/.docs/raw/deployment/logging-and-tracing.mdx +0 -242
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -19
- package/dist/prepare-docs/code-examples.d.ts +0 -4
- package/dist/prepare-docs/code-examples.js +0 -91
- package/dist/prepare-docs/copy-raw.d.ts +0 -1
- package/dist/prepare-docs/copy-raw.js +0 -41
- package/dist/prepare-docs/index.d.ts +0 -1
- package/dist/prepare-docs/index.js +0 -8
- package/dist/prepare-docs/package-changes.d.ts +0 -4
- package/dist/prepare-docs/package-changes.js +0 -92
- package/dist/sse.d.ts +0 -1
- package/dist/sse.js +0 -9
- package/dist/tools/__tests__/blog.test.d.ts +0 -1
- package/dist/tools/__tests__/blog.test.js +0 -48
- package/dist/tools/__tests__/changes.test.d.ts +0 -1
- package/dist/tools/__tests__/changes.test.js +0 -37
- package/dist/tools/__tests__/docs.test.d.ts +0 -1
- package/dist/tools/__tests__/docs.test.js +0 -46
- package/dist/tools/__tests__/examples.test.d.ts +0 -1
- package/dist/tools/__tests__/examples.test.js +0 -53
- package/dist/tools/blog.d.ts +0 -15
- package/dist/tools/blog.js +0 -73
- package/dist/tools/changes.d.ts +0 -11
- package/dist/tools/changes.js +0 -69
- package/dist/tools/docs.d.ts +0 -11
- package/dist/tools/docs.js +0 -176
- package/dist/tools/examples.d.ts +0 -11
- package/dist/tools/examples.js +0 -61
- package/dist/utils.d.ts +0 -6
- package/dist/utils.js +0 -9
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fromPackageRoot, fromRepoRoot, log } from '../utils.js';
|
|
4
|
-
const EXAMPLES_SOURCE = fromRepoRoot('examples');
|
|
5
|
-
const OUTPUT_DIR = fromPackageRoot('.docs/organized/code-examples');
|
|
6
|
-
/**
|
|
7
|
-
* Scans example directories and creates flattened code example files
|
|
8
|
-
*/
|
|
9
|
-
export async function prepareCodeExamples() {
|
|
10
|
-
// Clean up existing output directory
|
|
11
|
-
try {
|
|
12
|
-
await fs.rm(OUTPUT_DIR, { recursive: true, force: true });
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
// Ignore errors if directory doesn't exist
|
|
16
|
-
}
|
|
17
|
-
// Ensure output directory exists
|
|
18
|
-
await fs.mkdir(OUTPUT_DIR, { recursive: true });
|
|
19
|
-
// Get all example directories
|
|
20
|
-
const examples = await fs.readdir(EXAMPLES_SOURCE, { withFileTypes: true });
|
|
21
|
-
const exampleDirs = examples.filter(entry => entry.isDirectory());
|
|
22
|
-
for (const dir of exampleDirs) {
|
|
23
|
-
const examplePath = path.join(EXAMPLES_SOURCE, dir.name);
|
|
24
|
-
const outputFile = path.join(OUTPUT_DIR, `${dir.name}.md`);
|
|
25
|
-
// Collect all relevant files
|
|
26
|
-
const files = [];
|
|
27
|
-
// First add package.json if it exists
|
|
28
|
-
try {
|
|
29
|
-
const packageJson = await fs.readFile(path.join(examplePath, 'package.json'), 'utf-8');
|
|
30
|
-
files.push({
|
|
31
|
-
path: 'package.json',
|
|
32
|
-
content: packageJson,
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
// Skip if no package.json
|
|
37
|
-
}
|
|
38
|
-
// Then scan for TypeScript files in src
|
|
39
|
-
try {
|
|
40
|
-
const srcPath = path.join(examplePath, 'src');
|
|
41
|
-
await scanDirectory(srcPath, srcPath, files);
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
// Skip if no src directory
|
|
45
|
-
}
|
|
46
|
-
// If we found any files, generate markdown and check line count
|
|
47
|
-
if (files.length > 0) {
|
|
48
|
-
const output = files
|
|
49
|
-
.map(file => `### ${file.path}\n\`\`\`${getFileType(file.path)}\n${file.content}\n\`\`\`\n`)
|
|
50
|
-
.join('\n');
|
|
51
|
-
const totalLines = output.split('\n').length;
|
|
52
|
-
// Skip if total lines would exceed 500
|
|
53
|
-
if (totalLines > 500) {
|
|
54
|
-
log(`Skipping ${dir.name}: ${totalLines} lines exceeds limit of 500`);
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
await fs.writeFile(outputFile, output, 'utf-8');
|
|
58
|
-
log(`Generated ${dir.name}.md with ${totalLines} lines`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Recursively scan a directory for TypeScript files
|
|
64
|
-
*/
|
|
65
|
-
async function scanDirectory(basePath, currentPath, files) {
|
|
66
|
-
const entries = await fs.readdir(currentPath, { withFileTypes: true });
|
|
67
|
-
for (const entry of entries) {
|
|
68
|
-
const fullPath = path.join(currentPath, entry.name);
|
|
69
|
-
const relativePath = path.relative(basePath, fullPath);
|
|
70
|
-
if (entry.isDirectory()) {
|
|
71
|
-
await scanDirectory(basePath, fullPath, files);
|
|
72
|
-
}
|
|
73
|
-
else if (entry.isFile() && entry.name.endsWith('.ts')) {
|
|
74
|
-
const content = await fs.readFile(fullPath, 'utf-8');
|
|
75
|
-
files.push({
|
|
76
|
-
path: relativePath,
|
|
77
|
-
content,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Get the appropriate code fence language based on file extension
|
|
84
|
-
*/
|
|
85
|
-
function getFileType(filePath) {
|
|
86
|
-
if (filePath === 'package.json')
|
|
87
|
-
return 'json';
|
|
88
|
-
if (filePath.endsWith('.ts'))
|
|
89
|
-
return 'typescript';
|
|
90
|
-
return '';
|
|
91
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function copyRaw(): Promise<void>;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fromPackageRoot, fromRepoRoot, log } from '../utils.js';
|
|
4
|
-
const DOCS_SOURCE = fromRepoRoot('docs/src/pages/docs');
|
|
5
|
-
const DOCS_DEST = fromPackageRoot('.docs/raw');
|
|
6
|
-
async function copyDir(src, dest) {
|
|
7
|
-
// Create destination directory
|
|
8
|
-
await fs.mkdir(dest, { recursive: true });
|
|
9
|
-
// Read source directory
|
|
10
|
-
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
11
|
-
for (const entry of entries) {
|
|
12
|
-
const srcPath = path.join(src, entry.name);
|
|
13
|
-
const destPath = path.join(dest, entry.name);
|
|
14
|
-
if (entry.isDirectory()) {
|
|
15
|
-
// Recursively copy directories
|
|
16
|
-
await copyDir(srcPath, destPath);
|
|
17
|
-
}
|
|
18
|
-
else if (entry.isFile() && entry.name.endsWith('.mdx')) {
|
|
19
|
-
// Copy only MDX files
|
|
20
|
-
await fs.copyFile(srcPath, destPath);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
export async function copyRaw() {
|
|
25
|
-
try {
|
|
26
|
-
// Clean up existing docs directory if it exists
|
|
27
|
-
try {
|
|
28
|
-
await fs.rm(DOCS_DEST, { recursive: true });
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
// Ignore if directory doesn't exist
|
|
32
|
-
}
|
|
33
|
-
// Copy docs
|
|
34
|
-
await copyDir(DOCS_SOURCE, DOCS_DEST);
|
|
35
|
-
log('✅ Documentation files copied successfully');
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
console.error('❌ Failed to copy documentation files:', error);
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fromPackageRoot, fromRepoRoot, log } from '../utils.js';
|
|
4
|
-
// Define all source directories to scan
|
|
5
|
-
const SOURCE_DIRS = ['packages', 'speech', 'stores', 'voice', 'integrations', 'deployers', 'client-sdks'].map(fromRepoRoot);
|
|
6
|
-
const CHANGELOGS_DEST = fromPackageRoot('.docs/organized/changelogs');
|
|
7
|
-
const MAX_LINES = 300;
|
|
8
|
-
/**
|
|
9
|
-
* Truncates content to a maximum number of lines and adds a message about hidden lines
|
|
10
|
-
*/
|
|
11
|
-
function truncateContent(content, maxLines) {
|
|
12
|
-
const lines = content.split('\n');
|
|
13
|
-
if (lines.length <= maxLines)
|
|
14
|
-
return content;
|
|
15
|
-
const visibleLines = lines.slice(0, maxLines);
|
|
16
|
-
const hiddenCount = lines.length - maxLines;
|
|
17
|
-
return visibleLines.join('\n') + `\n\n... ${hiddenCount} more lines hidden. See full changelog in package directory.`;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Process a single package directory
|
|
21
|
-
*/
|
|
22
|
-
async function processPackageDir(packagePath, outputDir) {
|
|
23
|
-
// Try to read package.json first
|
|
24
|
-
let packageName;
|
|
25
|
-
try {
|
|
26
|
-
const packageJsonPath = path.join(packagePath, 'package.json');
|
|
27
|
-
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
|
|
28
|
-
packageName = packageJson.name;
|
|
29
|
-
if (!packageName) {
|
|
30
|
-
log(`Skipping ${path.basename(packagePath)}: No package name found in package.json`);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
console.error(`Skipping ${path.basename(packagePath)}: No valid package.json found`);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
// Try to read CHANGELOG.md
|
|
39
|
-
try {
|
|
40
|
-
const changelogPath = path.join(packagePath, 'CHANGELOG.md');
|
|
41
|
-
let changelog;
|
|
42
|
-
try {
|
|
43
|
-
changelog = await fs.readFile(changelogPath, 'utf-8');
|
|
44
|
-
changelog = truncateContent(changelog, MAX_LINES);
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
changelog = 'No changelog available.';
|
|
48
|
-
}
|
|
49
|
-
// Write to output file using URL-encoded package name
|
|
50
|
-
const outputFile = path.join(outputDir, `${encodeURIComponent(packageName)}.md`);
|
|
51
|
-
await fs.writeFile(outputFile, changelog, 'utf-8');
|
|
52
|
-
log(`Generated changelog for ${packageName}`);
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
console.error(`Error processing changelog for ${packageName}:`, error);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Scans package directories and creates organized changelog files
|
|
60
|
-
*/
|
|
61
|
-
export async function preparePackageChanges() {
|
|
62
|
-
const outputDir = path.resolve(process.cwd(), CHANGELOGS_DEST);
|
|
63
|
-
// Clean up existing output directory
|
|
64
|
-
try {
|
|
65
|
-
await fs.rm(outputDir, { recursive: true, force: true });
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
// Ignore errors if directory doesn't exist
|
|
69
|
-
}
|
|
70
|
-
// Ensure output directory exists
|
|
71
|
-
await fs.mkdir(outputDir, { recursive: true });
|
|
72
|
-
// Process each source directory
|
|
73
|
-
for (const sourceDir of SOURCE_DIRS) {
|
|
74
|
-
const fullSourceDir = path.resolve(process.cwd(), sourceDir);
|
|
75
|
-
try {
|
|
76
|
-
// Check if directory exists before trying to read it
|
|
77
|
-
await fs.access(fullSourceDir);
|
|
78
|
-
const entries = await fs.readdir(fullSourceDir, { withFileTypes: true });
|
|
79
|
-
const packageDirs = entries
|
|
80
|
-
.filter(entry => entry.isDirectory())
|
|
81
|
-
.filter(entry => entry.name !== 'docs-mcp' && entry.name !== '_config');
|
|
82
|
-
// Process each package directory
|
|
83
|
-
for (const dir of packageDirs) {
|
|
84
|
-
const packagePath = path.join(fullSourceDir, dir.name);
|
|
85
|
-
await processPackageDir(packagePath, outputDir);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
console.error(`Skipping ${sourceDir}: Directory not found or not accessible`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
package/dist/sse.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/sse.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test, vi } from 'vitest';
|
|
2
|
-
import { blogTool } from '../blog';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
const mockFetch = vi.fn();
|
|
6
|
-
global.fetch = mockFetch;
|
|
7
|
-
describe('blog tool', () => {
|
|
8
|
-
test('fetches and parses blog posts correctly', async () => {
|
|
9
|
-
const fixture = fs.readFileSync(path.join(__dirname, '../__fixtures__/blog-list-raw.txt'), 'utf-8');
|
|
10
|
-
mockFetch.mockResolvedValueOnce({
|
|
11
|
-
text: () => Promise.resolve(fixture),
|
|
12
|
-
});
|
|
13
|
-
const result = await blogTool.execute({ url: '/blog' });
|
|
14
|
-
expect(result).toContain('Mastra.ai Blog Posts:');
|
|
15
|
-
expect(result).toContain('[Announcing our new book: Principles of Building AI agents](/blog/principles-of-ai-engineering)');
|
|
16
|
-
expect(result).toContain('[AI Beats Laboratory: A Multi-Agent Music Generation System](/blog/ai-beats-lab)');
|
|
17
|
-
expect(result).not.toContain('nav');
|
|
18
|
-
expect(result).not.toContain('footer');
|
|
19
|
-
});
|
|
20
|
-
test('handles fetch errors gracefully', async () => {
|
|
21
|
-
mockFetch.mockRejectedValueOnce(new Error('Network error'));
|
|
22
|
-
await expect(blogTool.execute({ url: '/blog' })).rejects.toThrow('Failed to fetch blog posts');
|
|
23
|
-
});
|
|
24
|
-
test('returns specific blog post content when URL is provided', async () => {
|
|
25
|
-
const fixture = fs.readFileSync(path.join(__dirname, '../__fixtures__/blog-post-raw.txt'), 'utf-8');
|
|
26
|
-
mockFetch.mockResolvedValueOnce({
|
|
27
|
-
text: () => Promise.resolve(fixture),
|
|
28
|
-
});
|
|
29
|
-
const result = await blogTool.execute({ url: '/blog/principles-of-ai-engineering' });
|
|
30
|
-
expect(result).toContain('Announcing our new book: Principles of Building AI agents');
|
|
31
|
-
expect(result).toContain('Principles of Building AI agents');
|
|
32
|
-
expect(result).toContain("Today is YC demo day and we're excited to announce the release of our new book");
|
|
33
|
-
});
|
|
34
|
-
test('removes Next.js initialization code from blog post content', async () => {
|
|
35
|
-
const mockContent = `
|
|
36
|
-
<h1>Test Blog Post</h1>
|
|
37
|
-
<p>This is a test blog post.</p>
|
|
38
|
-
<script>(self.__next_f=self.__next_f||[]).push([0]);</script>
|
|
39
|
-
`;
|
|
40
|
-
mockFetch.mockResolvedValueOnce({
|
|
41
|
-
text: () => Promise.resolve(mockContent),
|
|
42
|
-
});
|
|
43
|
-
const result = await blogTool.execute({ url: '/blog/test-post' });
|
|
44
|
-
expect(result).toContain('Test Blog Post');
|
|
45
|
-
expect(result).toContain('This is a test blog post.');
|
|
46
|
-
expect(result).not.toContain('self.__next_f');
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { changesTool } from '../changes';
|
|
3
|
-
describe('changesTool', () => {
|
|
4
|
-
const mockContext = {};
|
|
5
|
-
describe('execute', () => {
|
|
6
|
-
it('should list all package changelogs when no package is specified', async () => {
|
|
7
|
-
const result = await changesTool.execute({}, mockContext);
|
|
8
|
-
// Check for some known packages that should be in the list
|
|
9
|
-
expect(result).toContain('@mastra/core');
|
|
10
|
-
expect(result).toContain('@mastra/deployer');
|
|
11
|
-
expect(result).toContain('mastra');
|
|
12
|
-
});
|
|
13
|
-
it('should return changelog content for a specific package', async () => {
|
|
14
|
-
const result = await changesTool.execute({ package: '@mastra/core' }, mockContext);
|
|
15
|
-
// The changelog should be a markdown file with package name as header
|
|
16
|
-
expect(result).toContain('# @mastra/core');
|
|
17
|
-
expect(result).toMatch(/##\s+v?\d+\.\d+\.\d+/); // Should contain version headers
|
|
18
|
-
});
|
|
19
|
-
it('should handle packages with slashes in names correctly', async () => {
|
|
20
|
-
const result = await changesTool.execute({ package: '@mastra/deployer-vercel' }, mockContext);
|
|
21
|
-
expect(result).toContain('# @mastra/deployer-vercel');
|
|
22
|
-
});
|
|
23
|
-
it('should handle non-existent package gracefully', async () => {
|
|
24
|
-
const result = await changesTool
|
|
25
|
-
.execute({ package: 'non-existent-package' }, mockContext)
|
|
26
|
-
.catch(error => error.message);
|
|
27
|
-
expect(result).toContain('Changelog for "non-existent-package" not found');
|
|
28
|
-
expect(result).toContain('Available packages:');
|
|
29
|
-
expect(result).toContain('@mastra/core'); // Should list available packages
|
|
30
|
-
});
|
|
31
|
-
it('should properly handle special characters in package names', async () => {
|
|
32
|
-
// Test with a package name containing special characters that need URL encoding
|
|
33
|
-
const result = await changesTool.execute({ package: '@mastra/client-js' }, mockContext);
|
|
34
|
-
expect(result).toContain('# @mastra/client-js');
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { docsTool } from '../docs';
|
|
3
|
-
describe('docsTool', () => {
|
|
4
|
-
const mockContext = {};
|
|
5
|
-
describe('execute', () => {
|
|
6
|
-
it('should list directory contents when no specific path is requested', async () => {
|
|
7
|
-
const result = await docsTool.execute({ paths: [''] }, mockContext);
|
|
8
|
-
expect(result).toContain('Directory contents of :');
|
|
9
|
-
expect(result).toContain('Subdirectories:');
|
|
10
|
-
expect(result).toContain('Files in this directory:');
|
|
11
|
-
expect(result).toContain('index.mdx');
|
|
12
|
-
});
|
|
13
|
-
it('should return content for index.mdx', async () => {
|
|
14
|
-
const result = await docsTool.execute({ paths: ['index.mdx'] }, mockContext);
|
|
15
|
-
expect(result).toContain('## index.mdx');
|
|
16
|
-
expect(result).toContain('# About Mastra');
|
|
17
|
-
});
|
|
18
|
-
it('should handle directory listings', async () => {
|
|
19
|
-
const result = await docsTool.execute({ paths: ['reference'] }, mockContext);
|
|
20
|
-
expect(result).toContain('Directory contents of reference');
|
|
21
|
-
expect(result).toContain('Subdirectories:');
|
|
22
|
-
expect(result).toContain('Files in this directory:');
|
|
23
|
-
});
|
|
24
|
-
it('should handle non-existent paths gracefully', async () => {
|
|
25
|
-
const result = await docsTool.execute({ paths: ['non-existent-path'] }, mockContext);
|
|
26
|
-
expect(result).toContain('Path "non-existent-path" not found');
|
|
27
|
-
expect(result).toContain('Here are all available paths');
|
|
28
|
-
});
|
|
29
|
-
it('should handle multiple paths in a single request', async () => {
|
|
30
|
-
const result = await docsTool.execute({
|
|
31
|
-
paths: ['index.mdx', 'reference/tools'],
|
|
32
|
-
}, mockContext);
|
|
33
|
-
expect(result).toContain('## index.mdx');
|
|
34
|
-
expect(result).toContain('## reference/tools');
|
|
35
|
-
});
|
|
36
|
-
it('should find nearest directory when path is partially correct', async () => {
|
|
37
|
-
const result = await docsTool.execute({ paths: ['reference/tools/non-existent'] }, mockContext);
|
|
38
|
-
expect(result).toContain('Path "reference/tools/non-existent" not found');
|
|
39
|
-
expect(result).toContain('Here are the available paths in "reference/tools"');
|
|
40
|
-
});
|
|
41
|
-
it('should handle paths with special characters', async () => {
|
|
42
|
-
const result = await docsTool.execute({ paths: ['reference/tools/'] }, mockContext);
|
|
43
|
-
expect(result).toContain('Directory contents of reference/tools');
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { examplesTool } from '../examples';
|
|
3
|
-
describe('examplesTool', () => {
|
|
4
|
-
const mockContext = {};
|
|
5
|
-
describe('execute', () => {
|
|
6
|
-
it('should list all available examples when no example is specified', async () => {
|
|
7
|
-
const result = await examplesTool.execute({}, mockContext);
|
|
8
|
-
// Check for some known examples that should be in the list
|
|
9
|
-
expect(result).toContain('Available code examples:');
|
|
10
|
-
expect(result).toContain('quick-start');
|
|
11
|
-
expect(result).toContain('agent');
|
|
12
|
-
});
|
|
13
|
-
it('should return example content for a specific example', async () => {
|
|
14
|
-
const result = await examplesTool.execute({ example: 'quick-start' }, mockContext);
|
|
15
|
-
// The example should contain package.json and index.ts files
|
|
16
|
-
expect(result).toContain('### package.json');
|
|
17
|
-
expect(result).toContain('### index.ts');
|
|
18
|
-
expect(result).toContain('```typescript');
|
|
19
|
-
});
|
|
20
|
-
it('should handle examples with or without .md extension', async () => {
|
|
21
|
-
const result1 = await examplesTool.execute({ example: 'quick-start' }, mockContext);
|
|
22
|
-
const result2 = await examplesTool.execute({ example: 'quick-start.md' }, mockContext);
|
|
23
|
-
expect(result1).toBe(result2);
|
|
24
|
-
});
|
|
25
|
-
it('should handle non-existent examples gracefully', async () => {
|
|
26
|
-
const result = await examplesTool
|
|
27
|
-
.execute({ example: 'non-existent-example' }, mockContext)
|
|
28
|
-
.catch(error => error.message);
|
|
29
|
-
expect(result).toContain('Example "non-existent-example.md" not found');
|
|
30
|
-
expect(result).toContain('Available examples:');
|
|
31
|
-
expect(result).toContain('quick-start'); // Should list available examples
|
|
32
|
-
});
|
|
33
|
-
it('should return examples in alphabetical order', async () => {
|
|
34
|
-
const result = (await examplesTool.execute({}, mockContext));
|
|
35
|
-
const lines = result.split('\n').filter((line) => line.startsWith('- '));
|
|
36
|
-
const examples = lines.map((line) => line.replace('- ', ''));
|
|
37
|
-
// Check if the array is sorted
|
|
38
|
-
const sortedExamples = [...examples].sort();
|
|
39
|
-
expect(examples).toEqual(sortedExamples);
|
|
40
|
-
});
|
|
41
|
-
it('should handle examples with special characters in names', async () => {
|
|
42
|
-
const result = await examplesTool.execute({ example: 'bird-checker-with-express' }, mockContext);
|
|
43
|
-
expect(result).toContain('### package.json');
|
|
44
|
-
expect(result).toContain('### index.ts');
|
|
45
|
-
expect(result).toContain('```typescript');
|
|
46
|
-
});
|
|
47
|
-
it('should handle examples with multiple code blocks', async () => {
|
|
48
|
-
const result = (await examplesTool.execute({ example: 'agent' }, mockContext));
|
|
49
|
-
const codeBlockCount = (result.match(/```typescript/g) || []).length;
|
|
50
|
-
expect(codeBlockCount).toBeGreaterThan(1);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
});
|
package/dist/tools/blog.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const blogTool: {
|
|
3
|
-
name: string;
|
|
4
|
-
description: string;
|
|
5
|
-
parameters: z.ZodObject<{
|
|
6
|
-
url: z.ZodString;
|
|
7
|
-
}, "strip", z.ZodTypeAny, {
|
|
8
|
-
url: string;
|
|
9
|
-
}, {
|
|
10
|
-
url: string;
|
|
11
|
-
}>;
|
|
12
|
-
execute: (args: {
|
|
13
|
-
url: string;
|
|
14
|
-
}) => Promise<string>;
|
|
15
|
-
};
|
package/dist/tools/blog.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { JSDOM } from 'jsdom';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
// Helper function to fetch blog posts as markdown
|
|
4
|
-
async function fetchBlogPosts() {
|
|
5
|
-
try {
|
|
6
|
-
const response = await fetch('https://mastra.ai/blog');
|
|
7
|
-
const html = await response.text();
|
|
8
|
-
const dom = new JSDOM(html);
|
|
9
|
-
const document = dom.window.document;
|
|
10
|
-
// Find all blog post links
|
|
11
|
-
const blogLinks = Array.from(document.querySelectorAll('a[href^="/blog/"]'))
|
|
12
|
-
.filter(link => {
|
|
13
|
-
const href = link.getAttribute('href');
|
|
14
|
-
// Exclude the main blog page and any other special pages
|
|
15
|
-
return href !== '/blog' && !href?.includes('authors');
|
|
16
|
-
})
|
|
17
|
-
.map(link => {
|
|
18
|
-
const h2 = link.querySelector('h2');
|
|
19
|
-
const title = h2?.textContent?.trim();
|
|
20
|
-
const href = link.getAttribute('href');
|
|
21
|
-
if (title && href) {
|
|
22
|
-
return `[${title}](${href})`;
|
|
23
|
-
}
|
|
24
|
-
return null;
|
|
25
|
-
})
|
|
26
|
-
.filter(Boolean);
|
|
27
|
-
return 'Mastra.ai Blog Posts:\n\n' + blogLinks.join('\n');
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
throw new Error('Failed to fetch blog posts');
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
// Helper function to fetch and convert a blog post to markdown
|
|
34
|
-
async function fetchBlogPost(url) {
|
|
35
|
-
try {
|
|
36
|
-
const response = await fetch(url);
|
|
37
|
-
const html = await response.text();
|
|
38
|
-
const dom = new JSDOM(html);
|
|
39
|
-
const document = dom.window.document;
|
|
40
|
-
// Remove Next.js initialization code
|
|
41
|
-
const scripts = document.querySelectorAll('script');
|
|
42
|
-
scripts.forEach(script => script.remove());
|
|
43
|
-
return document.body.textContent || '';
|
|
44
|
-
}
|
|
45
|
-
catch (error) {
|
|
46
|
-
throw new Error(`Failed to fetch blog post: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
export const blogTool = {
|
|
50
|
-
name: 'mastraBlog',
|
|
51
|
-
description: 'Get Mastra.ai blog content. Without a URL, returns a list of all blog posts. With a URL, returns the specific blog post content in markdown format. The blog contains changelog posts as well as announcements and posts about Mastra features and AI news',
|
|
52
|
-
parameters: z.object({
|
|
53
|
-
url: z
|
|
54
|
-
.string()
|
|
55
|
-
.describe('URL of a specific blog post to fetch. If the string /blog is passed as the url it returns a list of all blog posts.'),
|
|
56
|
-
}),
|
|
57
|
-
execute: async (args) => {
|
|
58
|
-
try {
|
|
59
|
-
if (args.url !== `/blog`) {
|
|
60
|
-
return await fetchBlogPost(`https://mastra.ai${args.url}`);
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
return await fetchBlogPosts();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
if (error instanceof Error) {
|
|
68
|
-
throw new Error('Failed to fetch blog posts');
|
|
69
|
-
}
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
},
|
|
73
|
-
};
|
package/dist/tools/changes.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Tool } from 'tylerbarnes-fastmcp-fix';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
declare const changesSchema: z.ZodObject<{
|
|
4
|
-
package: z.ZodOptional<z.ZodString>;
|
|
5
|
-
}, "strip", z.ZodTypeAny, {
|
|
6
|
-
package?: string | undefined;
|
|
7
|
-
}, {
|
|
8
|
-
package?: string | undefined;
|
|
9
|
-
}>;
|
|
10
|
-
export declare const changesTool: Tool<any, typeof changesSchema>;
|
|
11
|
-
export {};
|
package/dist/tools/changes.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
-
const __dirname = path.dirname(__filename);
|
|
7
|
-
// Helper function to encode package names for file paths
|
|
8
|
-
function encodePackageName(name) {
|
|
9
|
-
return encodeURIComponent(name);
|
|
10
|
-
}
|
|
11
|
-
// Helper function to decode package names from file paths
|
|
12
|
-
function decodePackageName(name) {
|
|
13
|
-
return decodeURIComponent(name);
|
|
14
|
-
}
|
|
15
|
-
// Helper function to list package changelogs
|
|
16
|
-
async function listPackageChangelogs() {
|
|
17
|
-
const changelogsDir = path.resolve(__dirname, '../../.docs/organized/changelogs');
|
|
18
|
-
try {
|
|
19
|
-
const files = await fs.readdir(changelogsDir);
|
|
20
|
-
return files
|
|
21
|
-
.filter(f => f.endsWith('.md'))
|
|
22
|
-
.map(f => ({
|
|
23
|
-
name: decodePackageName(f.replace('.md', '')),
|
|
24
|
-
path: f,
|
|
25
|
-
}))
|
|
26
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
return [];
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// Helper function to read a package changelog
|
|
33
|
-
async function readPackageChangelog(filename) {
|
|
34
|
-
const changelogsDir = path.resolve(__dirname, '../../.docs/organized/changelogs');
|
|
35
|
-
const encodedName = encodePackageName(filename.replace('.md', '')); // Remove .md if present
|
|
36
|
-
const filePath = path.join(changelogsDir, `${encodedName}.md`);
|
|
37
|
-
try {
|
|
38
|
-
return await fs.readFile(filePath, 'utf-8');
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
const packages = await listPackageChangelogs();
|
|
42
|
-
const availablePackages = packages.map(pkg => `- ${pkg.name}`).join('\n');
|
|
43
|
-
throw new Error(`Changelog for "${filename.replace('.md', '')}" not found.\n\nAvailable packages:\n${availablePackages}`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// Get initial packages for the description
|
|
47
|
-
const initialPackages = await listPackageChangelogs();
|
|
48
|
-
const packagesListing = initialPackages.length > 0
|
|
49
|
-
? '\n\nAvailable packages: ' + initialPackages.map(pkg => pkg.name).join(', ')
|
|
50
|
-
: '\n\nNo package changelogs available yet. Run the documentation preparation script first.';
|
|
51
|
-
const changesSchema = z.object({
|
|
52
|
-
package: z
|
|
53
|
-
.string()
|
|
54
|
-
.optional()
|
|
55
|
-
.describe('Name of the specific package to fetch changelog for. If not provided, lists all available packages.'),
|
|
56
|
-
});
|
|
57
|
-
export const changesTool = {
|
|
58
|
-
name: 'mastraChanges',
|
|
59
|
-
description: 'Get changelog information for Mastra.ai packages. ' + packagesListing,
|
|
60
|
-
parameters: changesSchema,
|
|
61
|
-
execute: async (args, _context) => {
|
|
62
|
-
if (!args.package) {
|
|
63
|
-
const packages = await listPackageChangelogs();
|
|
64
|
-
return ['Available package changelogs:', '', ...packages.map(pkg => `- ${pkg.name}`)].join('\n');
|
|
65
|
-
}
|
|
66
|
-
const content = await readPackageChangelog(args.package);
|
|
67
|
-
return content;
|
|
68
|
-
},
|
|
69
|
-
};
|
package/dist/tools/docs.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Tool } from 'tylerbarnes-fastmcp-fix';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
declare const docsSchema: z.ZodObject<{
|
|
4
|
-
paths: z.ZodArray<z.ZodString, "many">;
|
|
5
|
-
}, "strip", z.ZodTypeAny, {
|
|
6
|
-
paths: string[];
|
|
7
|
-
}, {
|
|
8
|
-
paths: string[];
|
|
9
|
-
}>;
|
|
10
|
-
export declare const docsTool: Tool<any, typeof docsSchema>;
|
|
11
|
-
export {};
|