@mastra/mcp-docs-server 1.2.15 → 1.2.16-alpha.3
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/docs/agents/agent-approval.md +5 -5
- package/.docs/docs/agents/overview.md +4 -4
- package/.docs/docs/browser/overview.md +1 -1
- package/.docs/docs/capabilities/channels.md +5 -5
- package/.docs/docs/capabilities/subagents.md +1 -1
- package/.docs/docs/connections/overview.md +1 -1
- package/.docs/docs/datasets/overview.md +1 -1
- package/.docs/docs/deployment/cloud-providers.md +4 -2
- package/.docs/docs/deployment/mastra-server.md +1 -1
- package/.docs/docs/deployment/monorepo.md +1 -1
- package/.docs/docs/deployment/overview.md +4 -1
- package/.docs/docs/deployment/sandbox.md +1 -1
- package/.docs/docs/deployment/web-framework.md +1 -1
- package/.docs/docs/deployment/workers.md +248 -2
- package/.docs/docs/evals/overview.md +1 -1
- package/.docs/docs/evals/quick-checks.md +1 -1
- package/.docs/docs/guides/multi-agent-systems.md +1 -1
- package/.docs/docs/harness/agent-controller.md +5 -5
- package/.docs/docs/harness/overview.md +1 -1
- package/.docs/docs/index.md +3 -3
- package/.docs/docs/long-running-agents/signal-providers.md +2 -2
- package/.docs/docs/mastra-platform/deploy.md +1 -1
- package/.docs/docs/mastra-platform/observability.md +63 -18
- package/.docs/docs/mastra-platform/overview.md +1 -1
- package/.docs/docs/mcp/overview.md +1 -1
- package/.docs/docs/memory/working-memory.md +1 -1
- package/.docs/docs/observability/integrations/exporters/mastra-storage.md +2 -2
- package/.docs/docs/observability/logging.md +1 -1
- package/.docs/docs/observability/metrics/overview.md +1 -1
- package/.docs/docs/observability/overview.md +1 -5
- package/.docs/docs/observability/tracing/overview.md +3 -6
- package/.docs/docs/server/auth/workers.md +1 -1
- package/.docs/docs/server/auth.md +5 -5
- package/.docs/docs/server/mastra-client.md +1 -1
- package/.docs/docs/server/mastra-server.md +1 -1
- package/.docs/docs/storage/overview.md +7 -6
- package/.docs/docs/workflows/human-in-the-loop.md +2 -2
- package/.docs/docs/workflows/overview.md +2 -2
- package/.docs/docs/workspace/lsp.md +27 -0
- package/.docs/docs/workspace/sandbox.md +11 -12
- package/.docs/integrations/agentic-ui/ai-sdk-ui.md +1 -1
- package/.docs/integrations/agentic-ui/assistant-ui.md +1 -1
- package/.docs/integrations/agentic-ui/copilotkit.md +1 -1
- package/.docs/integrations/agentic-ui/openui.md +1 -1
- package/.docs/integrations/databases/postgresql.md +8 -8
- package/.docs/integrations/deploy/amazon-ec2.md +2 -2
- package/.docs/integrations/deploy/aws-bedrock-agentcore.md +1 -1
- package/.docs/integrations/deploy/aws-lambda.md +2 -2
- package/.docs/integrations/deploy/azure-app-services.md +2 -2
- package/.docs/integrations/deploy/cloudflare.md +2 -2
- package/.docs/integrations/deploy/digital-ocean.md +2 -2
- package/.docs/integrations/deploy/inngest.md +1 -1
- package/.docs/integrations/deploy/kubernetes.md +2 -3
- package/.docs/integrations/deploy/netlify.md +2 -2
- package/.docs/integrations/deploy/temporal.md +1 -1
- package/.docs/integrations/deploy/vercel.md +2 -2
- package/.docs/integrations/file-storage/agentfs.md +1 -1
- package/.docs/integrations/file-storage/amazon-s3.md +1 -1
- package/.docs/integrations/file-storage/archil.md +1 -1
- package/.docs/integrations/file-storage/azure-blob.md +1 -1
- package/.docs/integrations/file-storage/google-cloud-storage.md +1 -1
- package/.docs/integrations/file-storage/google-drive.md +1 -1
- package/.docs/integrations/file-storage/mesa.md +1 -1
- package/.docs/integrations/file-storage/vercel-files.md +1 -1
- package/.docs/integrations/frameworks/astro.md +1 -1
- package/.docs/integrations/frameworks/electron.md +1 -1
- package/.docs/integrations/frameworks/express.md +1 -1
- package/.docs/integrations/frameworks/hono.md +1 -1
- package/.docs/integrations/frameworks/nestjs.md +1 -1
- package/.docs/integrations/frameworks/next-js.md +1 -1
- package/.docs/integrations/frameworks/nuxt.md +1 -1
- package/.docs/integrations/frameworks/sveltekit.md +1 -1
- package/.docs/integrations/frameworks/vite-react.md +1 -1
- package/.docs/integrations/sandboxes/agentcore.md +1 -1
- package/.docs/integrations/sandboxes/apple-container.md +1 -1
- package/.docs/integrations/sandboxes/blaxel.md +1 -1
- package/.docs/integrations/sandboxes/daytona.md +1 -1
- package/.docs/integrations/sandboxes/docker.md +1 -1
- package/.docs/integrations/sandboxes/e2b.md +1 -1
- package/.docs/integrations/sandboxes/modal.md +1 -1
- package/.docs/integrations/sandboxes/railway.md +1 -1
- package/.docs/integrations/sandboxes/vercel.md +3 -1
- package/.docs/integrations/tools/firecrawl.md +2 -2
- package/.docs/integrations/voice/livekit.md +3 -3
- package/.docs/integrations.md +108 -108
- package/.docs/models/environment-variables.md +2 -0
- package/.docs/models/gateways/openrouter.md +5 -1
- package/.docs/models/gateways/vercel.md +3 -2
- package/.docs/models/index.md +1 -1
- package/.docs/models/providers/aiand.md +3 -2
- package/.docs/models/providers/digitalocean.md +3 -2
- package/.docs/models/providers/edenai.md +88 -0
- package/.docs/models/providers/hyper.md +3 -3
- package/.docs/models/providers/inceptron.md +8 -9
- package/.docs/models/providers/kilo.md +11 -6
- package/.docs/models/providers/llmgateway.md +3 -1
- package/.docs/models/providers/merge-gateway.md +262 -0
- package/.docs/models/providers/nano-gpt.md +13 -37
- package/.docs/models/providers/opencode.md +2 -2
- package/.docs/models/providers/tinfoil.md +9 -8
- package/.docs/models/providers/xai.md +2 -1
- package/.docs/models/providers.md +2 -0
- package/.docs/reference/agents/getVoice.md +1 -1
- package/.docs/reference/configuration.md +1 -1
- package/.docs/reference/index.md +5 -1
- package/.docs/reference/manual-install.md +1 -1
- package/.docs/reference/migrations/network-to-supervisor.md +1 -1
- package/.docs/reference/migrations/upgrade-to-v1/tracing.md +1 -3
- package/.docs/reference/observability/tracing/exporters/cloud-exporter.md +0 -1
- package/.docs/reference/observability/tracing/exporters/console-exporter.md +0 -1
- package/.docs/reference/observability/tracing/exporters/default-exporter.md +0 -1
- package/.docs/reference/observability/tracing/exporters/mastra-platform-exporter.md +0 -1
- package/.docs/reference/observability/tracing/exporters/mastra-storage-exporter.md +0 -1
- package/.docs/reference/observability/tracing/processors/sensitive-data-filter.md +111 -99
- package/.docs/reference/observability/tracing/span-filtering.md +1 -1
- package/.docs/reference/storage/overview.md +1 -1
- package/.docs/reference/templates/overview.md +1 -1
- package/.docs/{guides → reference}/voice/overview.md +3 -3
- package/.docs/{guides → reference}/voice/speech-to-speech.md +1 -1
- package/.docs/{guides → reference}/voice/speech-to-text.md +1 -1
- package/.docs/{guides → reference}/voice/text-to-speech.md +2 -2
- package/CHANGELOG.md +14 -0
- package/package.json +4 -4
- package/.docs/docs/observability/integrations/exporters/mastra-platform.md +0 -201
- package/.docs/docs/observability/integrations/overview.md +0 -47
- package/.docs/docs/observability/integrations/processors/sensitive-data-filter.md +0 -302
- package/.docs/guides/deployment/mastra-workers.md +0 -578
- package/.docs/guides/getting-started/quickstart.md +0 -88
- package/.docs/guides/guide/ai-recruiter.md +0 -228
- package/.docs/guides/guide/code-review-bot.md +0 -228
- package/.docs/guides/guide/coding-agent.md +0 -392
- package/.docs/guides/guide/dev-assistant.md +0 -309
- package/.docs/guides/guide/docs-manager.md +0 -240
- package/.docs/guides/guide/github-actions-pr-description.md +0 -238
- package/.docs/guides/guide/notes-mcp-server.md +0 -418
- package/.docs/guides/guide/research-assistant.md +0 -350
- package/.docs/guides/guide/research-coordinator.md +0 -418
- package/.docs/guides/guide/signal-provider.md +0 -221
- package/.docs/guides/index.md +0 -24
- /package/.docs/{reference → docs}/mastra-platform/api.md +0 -0
- /package/.docs/{guides/agent-frameworks/ai-sdk.md → reference/ai-sdk/overview.md} +0 -0
|
@@ -1,418 +0,0 @@
|
|
|
1
|
-
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
-
|
|
3
|
-
# Building a notes MCP server
|
|
4
|
-
|
|
5
|
-
In this guide, you'll learn how to build a complete MCP (Model Context Protocol) server from scratch. This server will manage a collection of markdown notes and has these features:
|
|
6
|
-
|
|
7
|
-
1. **List and Read Notes**: Allow clients to browse and view markdown files stored on the server
|
|
8
|
-
2. **Write Notes**: Provide a tool for creating or updating notes
|
|
9
|
-
3. **Offer Smart Prompts**: Generate contextual prompts, like creating a daily note template or summarizing existing content
|
|
10
|
-
|
|
11
|
-
## Prerequisites
|
|
12
|
-
|
|
13
|
-
- Node.js `v22.13.0` or later installed
|
|
14
|
-
- An API key from a supported [Model Provider](https://mastra.ai/models)
|
|
15
|
-
- An existing Mastra project (Follow the [installation guide](https://mastra.ai/guides/getting-started/quickstart) to set up a new project)
|
|
16
|
-
|
|
17
|
-
## Adding necessary dependencies & files
|
|
18
|
-
|
|
19
|
-
Before you can create an MCP server you first need to install additional dependencies and set up a boilerplate folder structure.
|
|
20
|
-
|
|
21
|
-
1. Add `@mastra/mcp` to your project:
|
|
22
|
-
|
|
23
|
-
**npm**:
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm install @mastra/mcp@latest
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**pnpm**:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
pnpm add @mastra/mcp@latest
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
**Yarn**:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
yarn add @mastra/mcp@latest
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**Bun**:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
bun add @mastra/mcp@latest
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
2. After following the default [installation guide](https://mastra.ai/guides/getting-started/quickstart) your project will include files that are not relevant for this guide. You can safely remove them:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
rm -rf src/mastra/agents src/mastra/workflows src/mastra/tools/weather-tool.ts
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
You should also change the `src/mastra/index.ts` file like so:
|
|
54
|
-
|
|
55
|
-
```ts
|
|
56
|
-
import { Mastra } from '@mastra/core'
|
|
57
|
-
import { PinoLogger } from '@mastra/loggers'
|
|
58
|
-
import { LibSQLStore } from '@mastra/libsql'
|
|
59
|
-
|
|
60
|
-
export const mastra = new Mastra({
|
|
61
|
-
storage: new LibSQLStore({
|
|
62
|
-
id: 'mastra-storage',
|
|
63
|
-
// stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db
|
|
64
|
-
url: ':memory:',
|
|
65
|
-
}),
|
|
66
|
-
logger: new PinoLogger({
|
|
67
|
-
name: 'Mastra',
|
|
68
|
-
level: 'info',
|
|
69
|
-
}),
|
|
70
|
-
})
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
3. Create a dedicated directory for your MCP server's logic and a `notes` directory for your notes:
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
mkdir notes src/mastra/mcp
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
Create the following files:
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
touch src/mastra/mcp/{server,resources,prompts}.ts
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
- `server.ts`: Will contain the main MCP server configuration
|
|
86
|
-
- `resources.ts`: Will handle listing and reading note files
|
|
87
|
-
- `prompts.ts`: Will contain the logic for the smart prompts
|
|
88
|
-
|
|
89
|
-
The resulting directory structure should look like this:
|
|
90
|
-
|
|
91
|
-
```text
|
|
92
|
-
<your-project-name>/
|
|
93
|
-
├── notes/
|
|
94
|
-
└── src/
|
|
95
|
-
└── mastra/
|
|
96
|
-
├── index.ts
|
|
97
|
-
├── mcp/
|
|
98
|
-
│ ├── server.ts
|
|
99
|
-
│ ├── resources.ts
|
|
100
|
-
│ └── prompts.ts
|
|
101
|
-
└── tools/
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Creating the MCP server
|
|
105
|
-
|
|
106
|
-
Let's add the MCP server!
|
|
107
|
-
|
|
108
|
-
1. In `src/mastra/mcp/server.ts`, define the MCP server instance:
|
|
109
|
-
|
|
110
|
-
```typescript
|
|
111
|
-
import { MCPServer } from '@mastra/mcp'
|
|
112
|
-
|
|
113
|
-
export const notes = new MCPServer({
|
|
114
|
-
id: 'notes',
|
|
115
|
-
name: 'Notes Server',
|
|
116
|
-
version: '0.1.0',
|
|
117
|
-
tools: {},
|
|
118
|
-
})
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Register this MCP server in your Mastra instance at `src/mastra/index.ts`. The key `notes` is the public identifier for your MCP server:
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
import { Mastra } from '@mastra/core'
|
|
125
|
-
import { PinoLogger } from '@mastra/loggers'
|
|
126
|
-
import { LibSQLStore } from '@mastra/libsql'
|
|
127
|
-
import { notes } from './mcp/server'
|
|
128
|
-
|
|
129
|
-
export const mastra = new Mastra({
|
|
130
|
-
storage: new LibSQLStore({
|
|
131
|
-
id: 'mastra-storage',
|
|
132
|
-
// stores telemetry, evals, ... into memory storage, if it needs to persist, change to file:../mastra.db
|
|
133
|
-
url: ':memory:',
|
|
134
|
-
}),
|
|
135
|
-
logger: new PinoLogger({
|
|
136
|
-
name: 'Mastra',
|
|
137
|
-
level: 'info',
|
|
138
|
-
}),
|
|
139
|
-
mcpServers: {
|
|
140
|
-
notes,
|
|
141
|
-
},
|
|
142
|
-
})
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
2. Resource handlers allow clients to discover and read the content your server manages. Implement handlers to work with markdown files in the `notes` directory. Add to the `src/mastra/mcp/resources.ts` file:
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import fs from 'fs/promises'
|
|
149
|
-
import path from 'path'
|
|
150
|
-
import { fileURLToPath } from 'url'
|
|
151
|
-
import type { MCPServerResources, Resource } from '@mastra/mcp'
|
|
152
|
-
|
|
153
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
154
|
-
const __dirname = path.dirname(__filename)
|
|
155
|
-
const NOTES_DIR = path.resolve(__dirname, '../../notes') // relative to the default output directory
|
|
156
|
-
|
|
157
|
-
const listNoteFiles = async (): Promise<Resource[]> => {
|
|
158
|
-
try {
|
|
159
|
-
await fs.mkdir(NOTES_DIR, { recursive: true })
|
|
160
|
-
const files = await fs.readdir(NOTES_DIR)
|
|
161
|
-
return files
|
|
162
|
-
.filter(file => file.endsWith('.md'))
|
|
163
|
-
.map(file => {
|
|
164
|
-
const title = file.replace('.md', '')
|
|
165
|
-
return {
|
|
166
|
-
uri: `notes://${title}`,
|
|
167
|
-
name: title,
|
|
168
|
-
description: `A note about ${title}`,
|
|
169
|
-
mime_type: 'text/markdown',
|
|
170
|
-
}
|
|
171
|
-
})
|
|
172
|
-
} catch (error) {
|
|
173
|
-
console.error('Error listing note resources:', error)
|
|
174
|
-
return []
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const readNoteFile = async (uri: string): Promise<string | null> => {
|
|
179
|
-
const title = uri.replace('notes://', '')
|
|
180
|
-
const notePath = path.join(NOTES_DIR, `${title}.md`)
|
|
181
|
-
try {
|
|
182
|
-
return await fs.readFile(notePath, 'utf-8')
|
|
183
|
-
} catch (error) {
|
|
184
|
-
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
|
185
|
-
console.error(`Error reading resource ${uri}:`, error)
|
|
186
|
-
}
|
|
187
|
-
return null
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export const resourceHandlers: MCPServerResources = {
|
|
192
|
-
listResources: listNoteFiles,
|
|
193
|
-
getResourceContent: async ({ uri }: { uri: string }) => {
|
|
194
|
-
const content = await readNoteFile(uri)
|
|
195
|
-
if (content === null) return { text: '' }
|
|
196
|
-
return { text: content }
|
|
197
|
-
},
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Register these resource handlers in `src/mastra/mcp/server.ts`:
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
import { MCPServer } from '@mastra/mcp'
|
|
205
|
-
import { resourceHandlers } from './resources'
|
|
206
|
-
|
|
207
|
-
export const notes = new MCPServer({
|
|
208
|
-
id: 'notes',
|
|
209
|
-
name: 'Notes Server',
|
|
210
|
-
version: '0.1.0',
|
|
211
|
-
tools: {},
|
|
212
|
-
resources: resourceHandlers,
|
|
213
|
-
})
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
3. Tools are the actions your server can perform. Let's create a `write` tool. First, define the tool in `src/mastra/tools/write-note.ts`:
|
|
217
|
-
|
|
218
|
-
```typescript
|
|
219
|
-
import { createTool } from '@mastra/core/tools'
|
|
220
|
-
import { z } from 'zod'
|
|
221
|
-
import { fileURLToPath } from 'url'
|
|
222
|
-
import path from 'node:path'
|
|
223
|
-
import fs from 'fs/promises'
|
|
224
|
-
|
|
225
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
226
|
-
const __dirname = path.dirname(__filename)
|
|
227
|
-
const NOTES_DIR = path.resolve(__dirname, '../../../notes')
|
|
228
|
-
|
|
229
|
-
export const writeNoteTool = createTool({
|
|
230
|
-
id: 'write',
|
|
231
|
-
description: 'Write a new note or overwrite an existing one.',
|
|
232
|
-
inputSchema: z.object({
|
|
233
|
-
title: z.string().nonempty().describe('The title of the note. This will be the filename.'),
|
|
234
|
-
content: z.string().nonempty().describe('The markdown content of the note.'),
|
|
235
|
-
}),
|
|
236
|
-
outputSchema: z.string().nonempty(),
|
|
237
|
-
execute: async inputData => {
|
|
238
|
-
try {
|
|
239
|
-
const { title, content } = inputData
|
|
240
|
-
const filePath = path.join(NOTES_DIR, `${title}.md`)
|
|
241
|
-
await fs.mkdir(NOTES_DIR, { recursive: true })
|
|
242
|
-
await fs.writeFile(filePath, content, 'utf-8')
|
|
243
|
-
return `Successfully wrote to note \"${title}\".`
|
|
244
|
-
} catch (error: any) {
|
|
245
|
-
return `Error writing note: ${error.message}`
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
})
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
Register this tool in `src/mastra/mcp/server.ts`:
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
import { MCPServer } from '@mastra/mcp'
|
|
255
|
-
import { resourceHandlers } from './resources'
|
|
256
|
-
import { writeNoteTool } from '../tools/write-note'
|
|
257
|
-
|
|
258
|
-
export const notes = new MCPServer({
|
|
259
|
-
id: 'notes',
|
|
260
|
-
name: 'Notes Server',
|
|
261
|
-
version: '0.1.0',
|
|
262
|
-
resources: resourceHandlers,
|
|
263
|
-
tools: {
|
|
264
|
-
write: writeNoteTool,
|
|
265
|
-
},
|
|
266
|
-
})
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
4. Prompt handlers provide ready-to-use prompts for clients. You'll add these three:
|
|
270
|
-
|
|
271
|
-
- Daily note
|
|
272
|
-
- Summarize a note
|
|
273
|
-
- Brainstorm ideas
|
|
274
|
-
|
|
275
|
-
This requires a few markdown-parsing libraries you need to install:
|
|
276
|
-
|
|
277
|
-
```bash
|
|
278
|
-
npm install unified remark-parse gray-matter @types/unist
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
Implement the prompts in `src/mastra/mcp/prompts.ts`:
|
|
282
|
-
|
|
283
|
-
```typescript
|
|
284
|
-
import type { MCPServerPrompts } from '@mastra/mcp'
|
|
285
|
-
import { unified } from 'unified'
|
|
286
|
-
import remarkParse from 'remark-parse'
|
|
287
|
-
import matter from 'gray-matter'
|
|
288
|
-
import type { Node } from 'unist'
|
|
289
|
-
|
|
290
|
-
const prompts = [
|
|
291
|
-
{
|
|
292
|
-
name: 'new_daily_note',
|
|
293
|
-
description: 'Create a new daily note.',
|
|
294
|
-
version: '1.0.0',
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
name: 'summarize_note',
|
|
298
|
-
description: 'Give me a TL;DR of the note.',
|
|
299
|
-
version: '1.0.0',
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
name: 'brainstorm_ideas',
|
|
303
|
-
description: 'Brainstorm new ideas based on a note.',
|
|
304
|
-
version: '1.0.0',
|
|
305
|
-
},
|
|
306
|
-
]
|
|
307
|
-
|
|
308
|
-
function stringifyNode(node: Node): string {
|
|
309
|
-
if ('value' in node && typeof node.value === 'string') return node.value
|
|
310
|
-
if ('children' in node && Array.isArray(node.children))
|
|
311
|
-
return node.children.map(stringifyNode).join('')
|
|
312
|
-
return ''
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export async function analyzeMarkdown(md: string) {
|
|
316
|
-
const { content } = matter(md)
|
|
317
|
-
const tree = unified().use(remarkParse).parse(content)
|
|
318
|
-
const headings: string[] = []
|
|
319
|
-
const wordCounts: Record<string, number> = {}
|
|
320
|
-
let currentHeading = 'untitled'
|
|
321
|
-
wordCounts[currentHeading] = 0
|
|
322
|
-
tree.children.forEach(node => {
|
|
323
|
-
if (node.type === 'heading' && node.depth === 2) {
|
|
324
|
-
currentHeading = stringifyNode(node)
|
|
325
|
-
headings.push(currentHeading)
|
|
326
|
-
wordCounts[currentHeading] = 0
|
|
327
|
-
} else {
|
|
328
|
-
const textContent = stringifyNode(node)
|
|
329
|
-
if (textContent.trim()) {
|
|
330
|
-
wordCounts[currentHeading] =
|
|
331
|
-
(wordCounts[currentHeading] || 0) + textContent.split(/\\s+/).length
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
})
|
|
335
|
-
return { headings, wordCounts }
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
const getPromptMessages: MCPServerPrompts['getPromptMessages'] = async ({ name, args }) => {
|
|
339
|
-
switch (name) {
|
|
340
|
-
case 'new_daily_note':
|
|
341
|
-
const today = new Date().toISOString().split('T')[0]
|
|
342
|
-
return [
|
|
343
|
-
{
|
|
344
|
-
role: 'user',
|
|
345
|
-
content: {
|
|
346
|
-
type: 'text',
|
|
347
|
-
text: `Create a new note titled \"${today}\" with sections: \"## Tasks\", \"## Meetings\", \"## Notes\".`,
|
|
348
|
-
},
|
|
349
|
-
},
|
|
350
|
-
]
|
|
351
|
-
case 'summarize_note':
|
|
352
|
-
if (!args?.noteContent) throw new Error('No content provided')
|
|
353
|
-
const metaSum = await analyzeMarkdown(args.noteContent as string)
|
|
354
|
-
return [
|
|
355
|
-
{
|
|
356
|
-
role: 'user',
|
|
357
|
-
content: {
|
|
358
|
-
type: 'text',
|
|
359
|
-
text: `Summarize each section in ≤ 3 bullets.\\n\\n### Outline\\n${metaSum.headings.map(h => `- ${h} (${metaSum.wordCounts[h] || 0} words)`).join('\\n')}`.trim(),
|
|
360
|
-
},
|
|
361
|
-
},
|
|
362
|
-
]
|
|
363
|
-
case 'brainstorm_ideas':
|
|
364
|
-
if (!args?.noteContent) throw new Error('No content provided')
|
|
365
|
-
const metaBrain = await analyzeMarkdown(args.noteContent as string)
|
|
366
|
-
return [
|
|
367
|
-
{
|
|
368
|
-
role: 'user',
|
|
369
|
-
content: {
|
|
370
|
-
type: 'text',
|
|
371
|
-
text: `Brainstorm 3 ideas for underdeveloped sections below ${args?.topic ? `on ${args.topic}` : '.'}\\n\\nUnderdeveloped sections:\\n${metaBrain.headings.length ? metaBrain.headings.map(h => `- ${h}`).join('\\n') : '- (none, pick any)'}`,
|
|
372
|
-
},
|
|
373
|
-
},
|
|
374
|
-
]
|
|
375
|
-
default:
|
|
376
|
-
throw new Error(`Prompt \"${name}\" not found`)
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
export const promptHandlers: MCPServerPrompts = {
|
|
381
|
-
listPrompts: async () => prompts,
|
|
382
|
-
getPromptMessages,
|
|
383
|
-
}
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
Register these prompt handlers in `src/mastra/mcp/server.ts`:
|
|
387
|
-
|
|
388
|
-
```typescript
|
|
389
|
-
import { MCPServer } from '@mastra/mcp'
|
|
390
|
-
import { resourceHandlers } from './resources'
|
|
391
|
-
import { writeNoteTool } from '../tools/write-note'
|
|
392
|
-
import { promptHandlers } from './prompts'
|
|
393
|
-
|
|
394
|
-
export const notes = new MCPServer({
|
|
395
|
-
id: 'notes',
|
|
396
|
-
name: 'Notes Server',
|
|
397
|
-
version: '0.1.0',
|
|
398
|
-
resources: resourceHandlers,
|
|
399
|
-
prompts: promptHandlers,
|
|
400
|
-
tools: {
|
|
401
|
-
write: writeNoteTool,
|
|
402
|
-
},
|
|
403
|
-
})
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
## Run the server
|
|
407
|
-
|
|
408
|
-
Great, you've authored your first MCP server! Now you can try it out by starting the Mastra dev server and opening [Studio](https://mastra.ai/docs/studio/overview):
|
|
409
|
-
|
|
410
|
-
```bash
|
|
411
|
-
npm run dev
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
Open [`http://localhost:4111`](http://localhost:4111) in your browser. In the left sidebar, select **MCP Servers**. Select the **notes** MCP server.
|
|
415
|
-
|
|
416
|
-
You'll now be presented with instructions on how to add the MCP server to your IDE. You're able to use this MCP server with any MCP Client. On the right side under **Available Tools** you can also select the **write** tool.
|
|
417
|
-
|
|
418
|
-
Inside the **write** tool, try it out by providing `test` as a name and `this is a test` for the markdown content. After selecting **Submit** you'll have a new `test.md` file inside `notes`.
|