Skip to content

Commit 3bd4c22

Browse files
committed
feat: add mcp apps
1 parent c7822ed commit 3bd4c22

2 files changed

Lines changed: 85 additions & 1 deletion

File tree

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,27 @@
11
import { Agent } from '@mastra/core/agent';
22
import { Memory } from '@mastra/memory';
33

4+
import { initMcpServer } from '../../../../libs/ag-ui-server/index.js';
45
import { bookFlightTool } from '../tools/book-flight.js';
56
import { cancelFlightTool } from '../tools/cancel-flight.js';
67
import { findBookedFlightsTool } from '../tools/find-booked-flights.js';
78
import { ticketingAgentPrompt } from './ticketing-agent.prompt.js';
89

10+
const hotelsMcpTools = await initMcpServer({
11+
serverId: 'hotels',
12+
url: new URL('http://127.0.0.1:3002/mcp'),
13+
});
14+
915
export const ticketingAgent = new Agent({
1016
id: 'ticketingAgent',
1117
name: 'Flight42 Ticketing Assistant',
1218
instructions: ticketingAgentPrompt,
1319
model: 'openai/gpt-5.3-chat-latest',
14-
tools: { findBookedFlightsTool, bookFlightTool, cancelFlightTool },
20+
tools: {
21+
findBookedFlightsTool,
22+
bookFlightTool,
23+
cancelFlightTool,
24+
...hotelsMcpTools,
25+
},
1526
memory: new Memory(),
1627
});

libs/ag-ui-server/extended-mastra-agent.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import { CoreMessage } from '@mastra/core/llm';
66
import { RequestContext } from '@mastra/core/request-context';
77
import { Observable } from 'rxjs';
88

9+
import {
10+
getMcpAppToolMetadata,
11+
type McpAppToolMetadata,
12+
} from './mcp-apps-registry.js';
913
import { Store } from './memory-store.js';
1014
import { defaultStore } from './memory-store.js';
1115

@@ -56,6 +60,36 @@ function createToolCallCacheKey(
5660
return `${agentId}:${threadId}:${toolCallId}`;
5761
}
5862

63+
function buildMcpAppsActivityContent(
64+
metadata: McpAppToolMetadata,
65+
toolInput: unknown,
66+
result: unknown,
67+
): Record<string, unknown> {
68+
const input = asRecord(toolInput) ?? {};
69+
const resultRecord = asRecord(result);
70+
const hasContentArray =
71+
resultRecord !== undefined && Array.isArray(resultRecord['content']);
72+
73+
const shapedResult: Record<string, unknown> = hasContentArray
74+
? (resultRecord as Record<string, unknown>)
75+
: {
76+
content: [
77+
{
78+
type: 'text',
79+
text: JSON.stringify(result ?? null),
80+
},
81+
],
82+
structuredContent: resultRecord ?? result,
83+
};
84+
85+
return {
86+
serverId: metadata.serverId,
87+
resourceUri: metadata.resourceUri,
88+
toolInput: input,
89+
result: shapedResult,
90+
};
91+
}
92+
5993
function readThoughtSignature(value: unknown): string | undefined {
6094
const record = asRecord(value);
6195
const googleMetadata = getNestedRecord(
@@ -344,6 +378,15 @@ export class ExtendedMastraAgent extends AbstractAgent {
344378
};
345379
observer.next(resultEvent);
346380
},
381+
onActivitySnapshot: ({ messageId, activityType, content }) => {
382+
const activityEvent: BaseEvent = {
383+
type: EventType.ACTIVITY_SNAPSHOT,
384+
messageId,
385+
activityType,
386+
content,
387+
} as BaseEvent;
388+
observer.next(activityEvent);
389+
},
347390
onRunFinished: () => {
348391
const finishedEvent: BaseEvent = {
349392
type: EventType.RUN_FINISHED,
@@ -374,10 +417,19 @@ export class ExtendedMastraAgent extends AbstractAgent {
374417
toolCallId: string;
375418
result: unknown;
376419
}) => void;
420+
onActivitySnapshot: (value: {
421+
messageId: string;
422+
activityType: string;
423+
content: Record<string, unknown>;
424+
}) => void;
377425
onRunFinished: () => void;
378426
onError: (error: unknown) => void;
379427
},
380428
): Promise<void> {
429+
const pendingToolCalls = new Map<
430+
string,
431+
{ toolName: string; args: unknown }
432+
>();
381433
const mastraMessages = convertAGUIMessagesToMastra(input.messages as never);
382434
const rehydratedToolResultNames = rehydrateToolResultNames(
383435
this.store,
@@ -433,6 +485,10 @@ export class ExtendedMastraAgent extends AbstractAgent {
433485
input.threadId,
434486
payload.payload,
435487
);
488+
pendingToolCalls.set(payload.payload.toolCallId, {
489+
toolName: payload.payload.toolName,
490+
args: payload.payload.args,
491+
});
436492
handlers.onToolCallPart(payload.payload);
437493
break;
438494
}
@@ -444,6 +500,23 @@ export class ExtendedMastraAgent extends AbstractAgent {
444500
};
445501
};
446502
handlers.onToolResultPart(payload.payload);
503+
504+
const pending = pendingToolCalls.get(payload.payload.toolCallId);
505+
if (pending) {
506+
const metadata = getMcpAppToolMetadata(pending.toolName);
507+
if (metadata) {
508+
handlers.onActivitySnapshot({
509+
messageId: assistantMessageId,
510+
activityType: 'mcp-apps',
511+
content: buildMcpAppsActivityContent(
512+
metadata,
513+
pending.args,
514+
payload.payload.result,
515+
),
516+
});
517+
}
518+
pendingToolCalls.delete(payload.payload.toolCallId);
519+
}
447520
break;
448521
}
449522
case 'error': {

0 commit comments

Comments
 (0)