@mastra/mcp-apps-components 0.0.0-deploy-mcp-apps-20261104202056

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/LICENSE.md ADDED
@@ -0,0 +1,32 @@
1
+ Portions of this software are licensed as follows:
2
+
3
+ - All content that resides under any directory named `ee/` within this
4
+ repository, including but not limited to:
5
+ - `@mastra/core/auth/ee`
6
+ - `@mastra/core/agent-builder/ee`
7
+ - `@mastra/editor/ee`
8
+
9
+ is licensed under the license defined in [`ee/LICENSE`](https://github.com/mastra-ai/mastra/blob/main/ee/LICENSE).
10
+
11
+ - All third-party components incorporated into the Mastra Software are
12
+ licensed under the original license provided by the owner of the
13
+ applicable component.
14
+
15
+ - Content outside of the above-mentioned directories or restrictions is
16
+ available under the "Apache License 2.0" as defined below.
17
+
18
+ # Apache License 2.0
19
+
20
+ Copyright (c) 2025 Kepler Software, Inc.
21
+
22
+ Licensed under the Apache License, Version 2.0 (the "License");
23
+ you may not use this file except in compliance with the License.
24
+ You may obtain a copy of the License at
25
+
26
+ http://www.apache.org/licenses/LICENSE-2.0
27
+
28
+ Unless required by applicable law or agreed to in writing, software
29
+ distributed under the License is distributed on an "AS IS" BASIS,
30
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31
+ See the License for the specific language governing permissions and
32
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # @mastra/mcp-apps-components
2
+
3
+ Prebuilt [MCP Apps](https://mastra.ai/docs/connections/mcp) that render Mastra UI components inside any MCP App host, such as Mastra Studio. Each app ships as a self-contained HTML resource you register on an `MCPServer`, plus a server-side helper to link it to your tools.
4
+
5
+ The apps never reach the network from their iframe. They read data by calling app-only observability tools on the same server, which agents don't see.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @mastra/mcp-apps-components
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Register the dashboard renderer and `observabilityAppTools` on an `MCPServer`, then return a dashboard definition from a tool linked to the app's `ui://` URI.
16
+
17
+ ```typescript
18
+ import type { DashboardDefinition } from '@mastra/core/storage/dashboards';
19
+ import { createTool } from '@mastra/core/tools';
20
+ import { MCPServer } from '@mastra/mcp';
21
+ import { dashboardRendererApp, dashboardRendererInputSchema } from '@mastra/mcp-apps-components/dashboard-renderer';
22
+ import { observabilityAppTools } from '@mastra/mcp-apps-components/observability-tools';
23
+ import { z } from 'zod';
24
+
25
+ const DASHBOARD_APP_URI = 'ui://mastra/dashboard';
26
+
27
+ const agentRuns: DashboardDefinition = {
28
+ schemaVersion: 1,
29
+ defaults: { datePreset: '7d' },
30
+ rows: [
31
+ {
32
+ widgets: [
33
+ {
34
+ id: 'runs',
35
+ span: 12,
36
+ kind: 'kpis',
37
+ views: [
38
+ {
39
+ queries: [
40
+ {
41
+ id: 'runs',
42
+ source: 'metrics',
43
+ request: 'aggregate',
44
+ name: ['mastra_agent_duration_ms'],
45
+ aggregation: 'count',
46
+ },
47
+ ],
48
+ options: { items: [{ label: 'Agent runs', format: 'count', value: { query: 'runs' } }] },
49
+ },
50
+ ],
51
+ },
52
+ ],
53
+ },
54
+ ],
55
+ };
56
+
57
+ const showAgentRuns = createTool({
58
+ id: 'showAgentRuns',
59
+ description: 'Shows how many agent runs happened in the last 7 days',
60
+ inputSchema: z.object({}),
61
+ outputSchema: dashboardRendererInputSchema,
62
+ mcp: { _meta: { ui: { resourceUri: DASHBOARD_APP_URI } } },
63
+ execute: async () => ({ definition: agentRuns, scope: 'project' as const }),
64
+ });
65
+
66
+ export const dashboardServer = new MCPServer({
67
+ id: 'dashboard-server',
68
+ name: 'Dashboard Server',
69
+ version: '1.0.0',
70
+ appResources: { [DASHBOARD_APP_URI]: dashboardRendererApp() },
71
+ tools: { showAgentRuns, ...observabilityAppTools },
72
+ });
73
+ ```
74
+
75
+ Each tool runs its read-only observability route in-process as the caller, with the route's own validation, authentication, permission and FGA checks, so the app sees the same data the signed-in user can.
76
+
77
+ ### Pinning widgets
78
+
79
+ Each widget shows a pin button when the host says it can pin. The host owns the pinned widgets; the app only asks it to change them.
80
+
81
+ 1. The host sets `mastra.ai/dashboard-pinned-widgets` in its host context to the ids of the widgets it has pinned (`[]` for none). Without it, no pin buttons show.
82
+ 2. When the user clicks a widget's button, the app sends a `mastra.ai/dashboard-widget-pin` notification with `{ widget, scope, defaults, isPinned }`: the widget definition, the dashboard's scope, the date range and filters the user had on, and the state the user wants. Together, `widget`, `scope`, and `defaults` render the pinned widget on its own as the user saw it.
83
+ 3. The host stores the change and sends the new list of ids back in its host context. Each button follows the host, not the click.
84
+
85
+ The params come from the app's iframe, so parse them with `dashboardWidgetPinNotificationParamsSchema` before storing or rendering anything.
86
+
87
+ ```typescript
88
+ import { AppBridge } from '@modelcontextprotocol/ext-apps/app-bridge';
89
+ import {
90
+ DASHBOARD_PINNED_WIDGETS_CONTEXT_KEY,
91
+ DASHBOARD_WIDGET_PIN_NOTIFICATION,
92
+ dashboardWidgetPinNotificationParamsSchema,
93
+ } from '@mastra/mcp-apps-components/dashboard-renderer';
94
+
95
+ let hostContext = { theme: 'dark' as const, [DASHBOARD_PINNED_WIDGETS_CONTEXT_KEY]: [] as string[] };
96
+ const bridge = new AppBridge(client, hostInfo, capabilities, { hostContext });
97
+
98
+ bridge.fallbackNotificationHandler = async ({ method, params }) => {
99
+ if (method !== DASHBOARD_WIDGET_PIN_NOTIFICATION) return;
100
+ const parsed = dashboardWidgetPinNotificationParamsSchema.safeParse(params);
101
+ if (!parsed.success) return;
102
+ const { widget, scope, defaults, isPinned } = parsed.data;
103
+
104
+ const pinned = hostContext[DASHBOARD_PINNED_WIDGETS_CONTEXT_KEY];
105
+ if (isPinned === pinned.includes(widget.id)) return;
106
+ await (isPinned ? savePinnedWidget({ widget, scope, defaults }) : deletePinnedWidget(widget.id));
107
+
108
+ const ids = isPinned ? [...pinned, widget.id] : pinned.filter(id => id !== widget.id);
109
+ // setHostContext replaces the whole context, so keep the other fields
110
+ hostContext = { ...hostContext, [DASHBOARD_PINNED_WIDGETS_CONTEXT_KEY]: ids };
111
+ bridge.setHostContext(hostContext);
112
+ };
113
+ ```
114
+
115
+ Keep in mind:
116
+
117
+ - To turn pinning off, set the key to a non-array value such as `null`. Deleting the key does nothing, because `AppBridge` only sends the fields that changed, so the app keeps the last ids it got.
118
+ - Widget ids are only unique within one dashboard definition. Keep pinned ids per bridge (one tool call), not across dashboards.
119
+ - A widget that no longer parses shows no pin button, so the host owns unpinning it.
120
+
121
+ ## Documentation
122
+
123
+ - [Build MCP Apps](https://mastra.ai/docs/connections/mcp)
124
+ - [`MCPServer` reference](https://mastra.ai/reference/tools/mcp-server)
125
+
126
+ ## Changelog
127
+
128
+ See the [package changelog](https://github.com/mastra-ai/mastra/blob/main/packages/mcp-apps-components/CHANGELOG.md) for version history and release notes.
129
+
130
+ ## Support
131
+
132
+ We have an [open community Discord](https://discord.gg/mastra-ai). Come and say hello and let us know if you have any questions or need any help getting things running.