@dbx-tools/appkit-mastra 0.1.5 → 0.1.10
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/README.md +394 -0
- package/index.ts +46 -37
- package/package.json +58 -47
- package/src/agents.ts +233 -62
- package/src/chart.ts +555 -285
- package/src/config.ts +282 -18
- package/src/filesystems.ts +1090 -0
- package/src/genie.ts +1004 -601
- package/src/history.ts +178 -79
- package/src/mcp.ts +105 -0
- package/src/memory.ts +129 -74
- package/src/mlflow.ts +149 -0
- package/src/model.ts +80 -408
- package/src/observability.ts +144 -0
- package/src/pagination.ts +34 -0
- package/src/plugin.ts +573 -59
- package/src/processors.ts +168 -0
- package/src/rest.ts +67 -0
- package/src/server.ts +243 -45
- package/src/serving-sanitize.ts +167 -0
- package/src/serving.ts +27 -224
- package/src/statement.ts +89 -0
- package/src/storage-schema.ts +41 -0
- package/src/summarize.ts +176 -0
- package/src/threads.ts +338 -0
- package/src/workspaces.ts +346 -0
- package/src/writer.ts +44 -0
- package/tsconfig.json +41 -0
- package/dist/index.d.ts +0 -19
- package/dist/index.js +0 -19
- package/dist/src/agents.d.ts +0 -306
- package/dist/src/agents.js +0 -393
- package/dist/src/chart.d.ts +0 -104
- package/dist/src/chart.js +0 -375
- package/dist/src/config.d.ts +0 -170
- package/dist/src/config.js +0 -12
- package/dist/src/genie.d.ts +0 -116
- package/dist/src/genie.js +0 -594
- package/dist/src/history.d.ts +0 -67
- package/dist/src/history.js +0 -158
- package/dist/src/memory.d.ts +0 -79
- package/dist/src/memory.js +0 -197
- package/dist/src/model.d.ts +0 -159
- package/dist/src/model.js +0 -423
- package/dist/src/plugin.d.ts +0 -130
- package/dist/src/plugin.js +0 -255
- package/dist/src/render-chart-route.d.ts +0 -33
- package/dist/src/render-chart-route.js +0 -120
- package/dist/src/server.d.ts +0 -46
- package/dist/src/server.js +0 -113
- package/dist/src/serving.d.ts +0 -156
- package/dist/src/serving.js +0 -214
- package/src/render-chart-route.ts +0 -141
package/src/history.ts
CHANGED
|
@@ -9,27 +9,29 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The route is registered through {@link historyRoute} as a Mastra
|
|
11
11
|
* `registerApiRoute` so it sits in the same dispatcher pipeline as
|
|
12
|
-
*
|
|
13
|
-
* `./server.ts`) has already populated `RequestContext` with
|
|
12
|
+
* the standard agent routes. That means the `MastraServer` auth
|
|
13
|
+
* middleware (in `./server.ts`) has already populated `RequestContext` with
|
|
14
14
|
* `MASTRA_THREAD_ID_KEY` and `MASTRA_RESOURCE_ID_KEY` by the time
|
|
15
15
|
* the handler runs - no cookie or user lookups happen here, and the
|
|
16
16
|
* session-cookie logic stays the single source of truth in `server.ts`.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { toAISdkV5Messages } from "@mastra/ai-sdk/ui";
|
|
20
|
-
import type { Agent } from "@mastra/core/agent";
|
|
21
|
-
import type {
|
|
22
|
-
MastraDBMessage,
|
|
23
|
-
} from "@mastra/core/agent/message-list";
|
|
24
|
-
import {
|
|
25
|
-
MASTRA_RESOURCE_ID_KEY,
|
|
26
|
-
MASTRA_THREAD_ID_KEY,
|
|
27
|
-
} from "@mastra/core/request-context";
|
|
28
|
-
import { registerApiRoute } from "@mastra/core/server";
|
|
29
19
|
import type {
|
|
20
|
+
MastraClearHistoryResponse,
|
|
30
21
|
MastraHistoryResponse,
|
|
31
22
|
MastraHistoryUIMessage,
|
|
32
|
-
} from "@dbx-tools/
|
|
23
|
+
} from "@dbx-tools/shared-mastra";
|
|
24
|
+
import { toAISdkV5Messages } from "@mastra/ai-sdk/ui";
|
|
25
|
+
import type { Agent } from "@mastra/core/agent";
|
|
26
|
+
import type { MastraDBMessage } from "@mastra/core/agent/message-list";
|
|
27
|
+
import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from "@mastra/core/request-context";
|
|
28
|
+
import type { ContextWithMastra } from "@mastra/core/server";
|
|
29
|
+
import { registerApiRoute } from "@mastra/core/server";
|
|
30
|
+
|
|
31
|
+
import { clampPerPage, parseIntParam } from "./pagination";
|
|
32
|
+
import { error, log } from "@dbx-tools/shared-core";
|
|
33
|
+
|
|
34
|
+
const logger = log.logger("mastra/history");
|
|
33
35
|
|
|
34
36
|
/** Default history page size; matches the Mastra storage default. */
|
|
35
37
|
const DEFAULT_PER_PAGE = 20;
|
|
@@ -62,15 +64,18 @@ export interface LoadHistoryOptions {
|
|
|
62
64
|
* so the client can prepend them above the existing transcript
|
|
63
65
|
* without sorting locally.
|
|
64
66
|
*/
|
|
65
|
-
export async function loadHistory(
|
|
66
|
-
opts
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
export async function loadHistory(opts: LoadHistoryOptions): Promise<MastraHistoryResponse> {
|
|
68
|
+
const perPage = clampPerPage(opts.perPage, {
|
|
69
|
+
fallback: DEFAULT_PER_PAGE,
|
|
70
|
+
max: MAX_PER_PAGE,
|
|
71
|
+
});
|
|
69
72
|
const page = Math.max(0, Math.trunc(opts.page ?? 0));
|
|
70
73
|
const memory = await opts.agent.getMemory();
|
|
71
74
|
if (!memory) {
|
|
75
|
+
logger.debug("recall:no-memory", { agentId: opts.agent.id, threadId: opts.threadId });
|
|
72
76
|
return { uiMessages: [], page, perPage, total: 0, hasMore: false };
|
|
73
77
|
}
|
|
78
|
+
const startedAt = Date.now();
|
|
74
79
|
const result = await memory.recall({
|
|
75
80
|
threadId: opts.threadId,
|
|
76
81
|
...(opts.resourceId ? { resourceId: opts.resourceId } : {}),
|
|
@@ -82,9 +87,17 @@ export async function loadHistory(
|
|
|
82
87
|
},
|
|
83
88
|
});
|
|
84
89
|
const chronological = sortChronological(result.messages);
|
|
85
|
-
const uiMessages = toAISdkV5Messages(
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
const uiMessages = toAISdkV5Messages(chronological) as unknown as MastraHistoryUIMessage[];
|
|
91
|
+
logger.debug("recall:done", {
|
|
92
|
+
agentId: opts.agent.id,
|
|
93
|
+
threadId: opts.threadId,
|
|
94
|
+
page,
|
|
95
|
+
perPage,
|
|
96
|
+
returned: uiMessages.length,
|
|
97
|
+
total: result.total,
|
|
98
|
+
hasMore: result.hasMore,
|
|
99
|
+
elapsedMs: Date.now() - startedAt,
|
|
100
|
+
});
|
|
88
101
|
return {
|
|
89
102
|
uiMessages,
|
|
90
103
|
page,
|
|
@@ -94,19 +107,95 @@ export async function loadHistory(
|
|
|
94
107
|
};
|
|
95
108
|
}
|
|
96
109
|
|
|
110
|
+
/** Inputs accepted by {@link clearHistory}. */
|
|
111
|
+
export interface ClearHistoryOptions {
|
|
112
|
+
agent: Agent;
|
|
113
|
+
threadId: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Wipe every persisted message tied to a thread. Returns the count
|
|
118
|
+
* of messages that were on the thread at delete time so the caller
|
|
119
|
+
* can render a "cleared N messages" affordance without an
|
|
120
|
+
* additional round-trip.
|
|
121
|
+
*
|
|
122
|
+
* Agents without a configured `Memory` resolve to a no-op (count
|
|
123
|
+
* 0), matching {@link loadHistory}'s "stateless agents return an
|
|
124
|
+
* empty page" stance so callers don't have to special-case them.
|
|
125
|
+
* Threads that don't exist yet are also a successful no-op - the
|
|
126
|
+
* operation is idempotent so the UI can fire-and-forget without
|
|
127
|
+
* tracking thread existence.
|
|
128
|
+
*/
|
|
129
|
+
export async function clearHistory(opts: ClearHistoryOptions): Promise<{ cleared: number }> {
|
|
130
|
+
const memory = await opts.agent.getMemory();
|
|
131
|
+
if (!memory) {
|
|
132
|
+
logger.debug("clear:no-memory", { agentId: opts.agent.id, threadId: opts.threadId });
|
|
133
|
+
return { cleared: 0 };
|
|
134
|
+
}
|
|
135
|
+
// Mastra's `deleteThread` cascades to the message table, so we
|
|
136
|
+
// can't ask for a count after the fact. Read it pre-delete with a
|
|
137
|
+
// one-page recall sized to fit common threads in a single round
|
|
138
|
+
// trip; the value is for telemetry / UI, not correctness.
|
|
139
|
+
let cleared = 0;
|
|
140
|
+
try {
|
|
141
|
+
const probe = await memory.recall({
|
|
142
|
+
threadId: opts.threadId,
|
|
143
|
+
page: 0,
|
|
144
|
+
perPage: 1,
|
|
145
|
+
});
|
|
146
|
+
cleared = probe.total;
|
|
147
|
+
} catch (err) {
|
|
148
|
+
// A missing-thread error is the happy-path "nothing to count";
|
|
149
|
+
// every other error is logged but doesn't block the delete.
|
|
150
|
+
logger.debug("clear:probe-failed", {
|
|
151
|
+
agentId: opts.agent.id,
|
|
152
|
+
threadId: opts.threadId,
|
|
153
|
+
error: error.errorMessage(err),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const startedAt = Date.now();
|
|
158
|
+
try {
|
|
159
|
+
await memory.deleteThread(opts.threadId);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
// Mastra's `deleteThread` raises when the thread row was never
|
|
162
|
+
// created (e.g. clearing an empty session). Surface as a soft
|
|
163
|
+
// warn and treat as success - the user-facing semantic is
|
|
164
|
+
// "history is now empty" which is already true.
|
|
165
|
+
logger.warn("clear:delete-soft-failed", {
|
|
166
|
+
agentId: opts.agent.id,
|
|
167
|
+
threadId: opts.threadId,
|
|
168
|
+
error: error.errorMessage(err),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
logger.info("clear:done", {
|
|
172
|
+
agentId: opts.agent.id,
|
|
173
|
+
threadId: opts.threadId,
|
|
174
|
+
cleared,
|
|
175
|
+
elapsedMs: Date.now() - startedAt,
|
|
176
|
+
});
|
|
177
|
+
return { cleared };
|
|
178
|
+
}
|
|
179
|
+
|
|
97
180
|
/** Options accepted by {@link historyRoute}. */
|
|
98
181
|
export type HistoryRouteOptions =
|
|
99
|
-
|
|
100
|
-
| { path: string; agent: string };
|
|
182
|
+
{ path: `${string}:agentId${string}`; agent?: never } | { path: string; agent: string };
|
|
101
183
|
|
|
102
184
|
/**
|
|
103
|
-
* Register
|
|
104
|
-
*
|
|
185
|
+
* Register the `<path>` Mastra custom API route. Handles two
|
|
186
|
+
* methods on the same mount:
|
|
187
|
+
*
|
|
188
|
+
* - `GET`: return a page of AI SDK V5 `UIMessage`s for the
|
|
189
|
+
* caller's current thread ({@link loadHistory}).
|
|
190
|
+
* - `DELETE`: wipe every persisted message on the caller's
|
|
191
|
+
* thread ({@link clearHistory}). The session cookie that
|
|
192
|
+
* anchors the thread id is left alone so the user keeps the
|
|
193
|
+
* same thread - only the contents go away.
|
|
105
194
|
*
|
|
106
|
-
*
|
|
107
|
-
* fixed-agent mount, or include
|
|
108
|
-
*
|
|
109
|
-
*
|
|
195
|
+
* Follows the `@mastra/ai-sdk` `chatRoute` convention for agent
|
|
196
|
+
* binding: pass `agent` for a fixed-agent mount, or include
|
|
197
|
+
* `:agentId` in the path for dynamic routing. The plugin registers
|
|
198
|
+
* both `/route/history` (default agent) and `/route/history/:agentId`.
|
|
110
199
|
*
|
|
111
200
|
* The handler reads `threadId` and `resourceId` from `RequestContext`
|
|
112
201
|
* (populated upstream by `MastraServer.registerAuthMiddleware`), so
|
|
@@ -120,46 +209,68 @@ export function historyRoute(options: HistoryRouteOptions) {
|
|
|
120
209
|
"historyRoute path must include `:agentId` or `agent` must be passed explicitly",
|
|
121
210
|
);
|
|
122
211
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
page: parseIntParam(c.req.query("page")),
|
|
150
|
-
perPage: parseIntParam(c.req.query("perPage")),
|
|
151
|
-
});
|
|
152
|
-
return c.json(payload);
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
}
|
|
212
|
+
// Tiny resolver shared by GET / DELETE: derive the active agent
|
|
213
|
+
// and thread id, returning a JSON error response when either is
|
|
214
|
+
// missing. Keeps both handlers thin and gives them identical
|
|
215
|
+
// validation behaviour.
|
|
216
|
+
const resolveContext = (c: ContextWithMastra) => {
|
|
217
|
+
const mastra = c.get("mastra");
|
|
218
|
+
const requestContext = c.get("requestContext");
|
|
219
|
+
const agentId = fixedAgent ?? c.req.param("agentId");
|
|
220
|
+
if (!agentId) {
|
|
221
|
+
return { error: c.json({ error: "agentId is required" }, 400) } as const;
|
|
222
|
+
}
|
|
223
|
+
const agent = mastra.getAgentById(agentId);
|
|
224
|
+
if (!agent) {
|
|
225
|
+
return {
|
|
226
|
+
error: c.json({ error: `Unknown agent "${agentId}"` }, 404),
|
|
227
|
+
} as const;
|
|
228
|
+
}
|
|
229
|
+
const threadId = requestContext.get(MASTRA_THREAD_ID_KEY) as string | undefined;
|
|
230
|
+
if (!threadId) {
|
|
231
|
+
return {
|
|
232
|
+
error: c.json({ error: "thread id missing from request context" }, 400),
|
|
233
|
+
} as const;
|
|
234
|
+
}
|
|
235
|
+
const resourceId = requestContext.get(MASTRA_RESOURCE_ID_KEY) as string | undefined;
|
|
236
|
+
return { agentId, agent, threadId, resourceId } as const;
|
|
237
|
+
};
|
|
156
238
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
239
|
+
return [
|
|
240
|
+
registerApiRoute(path, {
|
|
241
|
+
method: "GET",
|
|
242
|
+
handler: async (c: ContextWithMastra) => {
|
|
243
|
+
const ctx = resolveContext(c);
|
|
244
|
+
if ("error" in ctx) return ctx.error;
|
|
245
|
+
const payload = await loadHistory({
|
|
246
|
+
agent: ctx.agent,
|
|
247
|
+
threadId: ctx.threadId,
|
|
248
|
+
...(ctx.resourceId ? { resourceId: ctx.resourceId } : {}),
|
|
249
|
+
page: parseIntParam(c.req.query("page")),
|
|
250
|
+
perPage: parseIntParam(c.req.query("perPage")),
|
|
251
|
+
});
|
|
252
|
+
return c.json(payload);
|
|
253
|
+
},
|
|
254
|
+
}),
|
|
255
|
+
registerApiRoute(path, {
|
|
256
|
+
method: "DELETE",
|
|
257
|
+
handler: async (c: ContextWithMastra) => {
|
|
258
|
+
const ctx = resolveContext(c);
|
|
259
|
+
if ("error" in ctx) return ctx.error;
|
|
260
|
+
const { cleared } = await clearHistory({
|
|
261
|
+
agent: ctx.agent,
|
|
262
|
+
threadId: ctx.threadId,
|
|
263
|
+
});
|
|
264
|
+
const payload: MastraClearHistoryResponse = {
|
|
265
|
+
ok: true,
|
|
266
|
+
agentId: ctx.agentId,
|
|
267
|
+
threadId: ctx.threadId,
|
|
268
|
+
cleared,
|
|
269
|
+
};
|
|
270
|
+
return c.json(payload);
|
|
271
|
+
},
|
|
272
|
+
}),
|
|
273
|
+
];
|
|
163
274
|
}
|
|
164
275
|
|
|
165
276
|
/**
|
|
@@ -184,15 +295,3 @@ function toEpoch(value: unknown): number {
|
|
|
184
295
|
}
|
|
185
296
|
return 0;
|
|
186
297
|
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Coerce a Hono query value into a non-negative integer. Returns
|
|
190
|
-
* `undefined` for empty / non-numeric / negative inputs so
|
|
191
|
-
* {@link loadHistory} can apply its built-in defaults.
|
|
192
|
-
*/
|
|
193
|
-
function parseIntParam(value: string | undefined): number | undefined {
|
|
194
|
-
if (!value) return undefined;
|
|
195
|
-
const n = Number(value);
|
|
196
|
-
if (!Number.isFinite(n) || n < 0) return undefined;
|
|
197
|
-
return Math.trunc(n);
|
|
198
|
-
}
|
package/src/mcp.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional Mastra MCP server exposure for the AppKit Mastra plugin.
|
|
3
|
+
*
|
|
4
|
+
* Turns the plugin's registered agents (and, opt-in, its ambient tools)
|
|
5
|
+
* into a Mastra `MCPServer` so external MCP clients - Claude Desktop,
|
|
6
|
+
* Cursor, the Mastra playground, or another agent - can call them over
|
|
7
|
+
* the standard MCP transports. The resulting server is handed to the
|
|
8
|
+
* `Mastra` instance via `mcpServers`, which makes `@mastra/express`
|
|
9
|
+
* serve the stock MCP routes under the plugin's base path; the plugin
|
|
10
|
+
* never registers a bespoke MCP route of its own.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Agent } from "@mastra/core/agent";
|
|
14
|
+
import { MCPServer } from "@mastra/mcp";
|
|
15
|
+
|
|
16
|
+
import type { MastraTools } from "./agents";
|
|
17
|
+
import type { MastraMcpConfig, MastraPluginConfig } from "./config";
|
|
18
|
+
|
|
19
|
+
/** MCP server version advertised when the caller doesn't pin one. */
|
|
20
|
+
const DEFAULT_MCP_VERSION = "1.0.0";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A built MCP server plus the request paths it answers on, relative to
|
|
24
|
+
* the plugin's base path (`/api/<plugin>`).
|
|
25
|
+
*
|
|
26
|
+
* The paths are the **clean public aliases** (`/mcp`, `/sse`,
|
|
27
|
+
* `/messages`) the plugin exposes. `@mastra/express` actually mounts the
|
|
28
|
+
* transports under `/mcp/<serverId>/<transport>` off the `Mastra`
|
|
29
|
+
* instance's `mcpServers`; the plugin rewrites the alias to that route
|
|
30
|
+
* before dispatch (see {@link ResolvedMcp.serverId}), so a client never
|
|
31
|
+
* sees the doubled `/mcp/<serverId>/mcp` segment.
|
|
32
|
+
*/
|
|
33
|
+
export interface ResolvedMcp {
|
|
34
|
+
/**
|
|
35
|
+
* Registry id, used in the underlying `@mastra/express` route
|
|
36
|
+
* (`/mcp/<serverId>/...`) the plugin rewrites the clean alias to.
|
|
37
|
+
*/
|
|
38
|
+
serverId: string;
|
|
39
|
+
/** The Mastra MCP server to hand to `new Mastra({ mcpServers })`. */
|
|
40
|
+
server: MCPServer;
|
|
41
|
+
/** Streamable-HTTP transport path, relative to the plugin base path. */
|
|
42
|
+
httpPath: string;
|
|
43
|
+
/** SSE transport path, relative to the plugin base path. */
|
|
44
|
+
ssePath: string;
|
|
45
|
+
/** SSE message path, relative to the plugin base path. */
|
|
46
|
+
messagePath: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Build the plugin's MCP server, or `null` only when `config.mcp` is
|
|
51
|
+
* explicitly `false`.
|
|
52
|
+
*
|
|
53
|
+
* Agent exposure is on by default because it's cheap: the already-
|
|
54
|
+
* registered agents are wrapped as `ask_<agentId>` tools and handed to
|
|
55
|
+
* `@mastra/express` (already mounted for the chat routes) - no extra
|
|
56
|
+
* process, dependency, or network cost, and requests run under the same
|
|
57
|
+
* OBO scope. So `undefined` (the default) and `true` both expose every
|
|
58
|
+
* registered agent under a server id equal to the plugin name; only
|
|
59
|
+
* `false` turns MCP off. The object form ({@link MastraMcpConfig}) tunes
|
|
60
|
+
* the id / advertised metadata and can additionally expose the plugin's
|
|
61
|
+
* ambient tools or a set of extra MCP-only tools. Ambient tools stay off
|
|
62
|
+
* unless explicitly enabled - they assume an in-process chat turn, so
|
|
63
|
+
* they aren't cheap / safe to expose to a standalone MCP client.
|
|
64
|
+
*/
|
|
65
|
+
export function buildMcpServer(opts: {
|
|
66
|
+
config: MastraPluginConfig;
|
|
67
|
+
pluginName: string;
|
|
68
|
+
displayName: string;
|
|
69
|
+
agents: Record<string, Agent>;
|
|
70
|
+
ambientTools: MastraTools;
|
|
71
|
+
}): ResolvedMcp | null {
|
|
72
|
+
const { config, pluginName, displayName, agents, ambientTools } = opts;
|
|
73
|
+
if (config.mcp === false) return null;
|
|
74
|
+
const settings: MastraMcpConfig = typeof config.mcp === "object" ? config.mcp : {};
|
|
75
|
+
|
|
76
|
+
const serverId = settings.serverId ?? pluginName;
|
|
77
|
+
const exposeAgents = settings.agents !== false;
|
|
78
|
+
const exposeTools = settings.tools === true;
|
|
79
|
+
|
|
80
|
+
// MCPServerConfig.tools is required, so always pass a record (empty
|
|
81
|
+
// when the caller exposes only agents).
|
|
82
|
+
const tools: MastraTools = {
|
|
83
|
+
...(exposeTools ? ambientTools : {}),
|
|
84
|
+
...(settings.extraTools ?? {}),
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const server = new MCPServer({
|
|
88
|
+
id: serverId,
|
|
89
|
+
name: settings.name ?? `${displayName} MCP`,
|
|
90
|
+
version: settings.version ?? DEFAULT_MCP_VERSION,
|
|
91
|
+
...(settings.description ? { description: settings.description } : {}),
|
|
92
|
+
...(exposeAgents ? { agents } : {}),
|
|
93
|
+
tools,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Advertise the clean aliases; the plugin rewrites these to the stock
|
|
97
|
+
// `/mcp/<serverId>/<transport>` routes `@mastra/express` mounts.
|
|
98
|
+
return {
|
|
99
|
+
serverId,
|
|
100
|
+
server,
|
|
101
|
+
httpPath: "/mcp",
|
|
102
|
+
ssePath: "/sse",
|
|
103
|
+
messagePath: "/messages",
|
|
104
|
+
};
|
|
105
|
+
}
|