@mastra/mcp-apps-components 0.0.0 → 0.1.0-alpha.0

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.
@@ -0,0 +1,16 @@
1
+ import type { McpAppResource } from './types.js';
2
+ export type McpAppResourceOptions = {
3
+ name?: string;
4
+ description?: string;
5
+ };
6
+ /**
7
+ * Declares the server side of an app built from `src/apps/<app>`: a function returning the
8
+ * resource to register under a `ui://` URI in `MCPServer`'s `appResources`.
9
+ *
10
+ * The page is passed inline rather than as a file path: deployers bundle this package into the
11
+ * server output, where no sibling HTML file exists (and Cloudflare has no filesystem at all).
12
+ * Apps reach Mastra through their server's tools, never the network, so the resource keeps
13
+ * hosts' default CSP.
14
+ */
15
+ export declare function defineMcpAppResource(html: string, defaults: Required<McpAppResourceOptions>): ({ name, description, }?: McpAppResourceOptions) => McpAppResource;
16
+ //# sourceMappingURL=define-mcp-app-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-mcp-app-resource.d.ts","sourceRoot":"","sources":["../src/define-mcp-app-resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,qBAAqB,CAAC,6BAIvF,qBAAqB,KAAQ,cAAc,CAK/C"}
@@ -0,0 +1,62 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * The app-only tools apps read observability data through, with the server route each one runs.
4
+ * Apps run in a sandboxed iframe that hosts may forbid from reaching the server, so their requests
5
+ * travel as calls to these tools over the host's existing MCP connection instead.
6
+ */
7
+ export declare const OBSERVABILITY_APP_TOOLS: {
8
+ readonly observabilityAggregateTraces: {
9
+ readonly method: 'POST';
10
+ readonly path: '/observability/traces/aggregate';
11
+ };
12
+ readonly observabilityAggregateSpans: {
13
+ readonly method: 'POST';
14
+ readonly path: '/observability/spans/aggregate';
15
+ };
16
+ readonly observabilityMetricAggregate: {
17
+ readonly method: 'POST';
18
+ readonly path: '/observability/metrics/aggregate';
19
+ };
20
+ readonly observabilityMetricBreakdown: {
21
+ readonly method: 'POST';
22
+ readonly path: '/observability/metrics/breakdown';
23
+ };
24
+ readonly observabilityMetricTimeSeries: {
25
+ readonly method: 'POST';
26
+ readonly path: '/observability/metrics/timeseries';
27
+ };
28
+ readonly observabilityMetricPercentiles: {
29
+ readonly method: 'POST';
30
+ readonly path: '/observability/metrics/percentiles';
31
+ };
32
+ readonly observabilityListScores: {
33
+ readonly method: 'GET';
34
+ readonly path: '/observability/scores';
35
+ };
36
+ readonly observabilityScoreAggregate: {
37
+ readonly method: 'POST';
38
+ readonly path: '/observability/scores/aggregate';
39
+ };
40
+ readonly observabilityScoreBreakdown: {
41
+ readonly method: 'POST';
42
+ readonly path: '/observability/scores/breakdown';
43
+ };
44
+ readonly observabilityScoreTimeSeries: {
45
+ readonly method: 'POST';
46
+ readonly path: '/observability/scores/timeseries';
47
+ };
48
+ readonly observabilityScorePercentiles: {
49
+ readonly method: 'POST';
50
+ readonly path: '/observability/scores/percentiles';
51
+ };
52
+ };
53
+ export type ObservabilityAppToolName = keyof typeof OBSERVABILITY_APP_TOOLS;
54
+ /** A GET route's query string, one entry per key; repeated keys become arrays. */
55
+ export declare const routeQuerySchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
56
+ /** What each tool answers: the route's own status and body, as it would over HTTP. */
57
+ export declare const routeResponseSchema: z.ZodObject<{
58
+ status: z.ZodNumber;
59
+ body: z.ZodUnknown;
60
+ }, z.core.$strip>;
61
+ export type RouteResponse = z.output<typeof routeResponseSchema>;
62
+ //# sourceMappingURL=observability-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability-protocol.d.ts","sourceRoot":"","sources":["../src/observability-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;iBACF,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,iCAAiC;;;iBACxD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,gCAAgC;;;iBACrD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,kCAAkC;;;iBACxD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,kCAAkC;;;iBACvD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,mCAAmC;;;iBACxD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,oCAAoC;;;iBACjE,MAAM,EAAE,KAAK;iBAAE,IAAI,EAAE,uBAAuB;;;iBACxC,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,iCAAiC;;;iBACvD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,iCAAiC;;;iBACtD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,kCAAkC;;;iBACvD,MAAM,EAAE,MAAM;iBAAE,IAAI,EAAE,mCAAmC;;CACf,CAAC;AAE9E,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,uBAAuB,CAAC;AAE5E,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,uFAAmE,CAAC;AAEjG,sFAAsF;AACtF,eAAO,MAAM,mBAAmB;;;iBAG9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
@@ -0,0 +1,118 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let zod = require("zod");
3
+ let _mastra_core_request_context = require("@mastra/core/request-context");
4
+ let _mastra_core_tools = require("@mastra/core/tools");
5
+ let _mastra_server_handlers_observability = require("@mastra/server/handlers/observability");
6
+ let _mastra_server_server_adapter = require("@mastra/server/server-adapter");
7
+ // src/observability-protocol.ts
8
+ /**
9
+ * The app-only tools apps read observability data through, with the server route each one runs.
10
+ * Apps run in a sandboxed iframe that hosts may forbid from reaching the server, so their requests
11
+ * travel as calls to these tools over the host's existing MCP connection instead.
12
+ */
13
+ const OBSERVABILITY_APP_TOOLS = {
14
+ observabilityAggregateTraces: {
15
+ method: "POST",
16
+ path: "/observability/traces/aggregate"
17
+ },
18
+ observabilityAggregateSpans: {
19
+ method: "POST",
20
+ path: "/observability/spans/aggregate"
21
+ },
22
+ observabilityMetricAggregate: {
23
+ method: "POST",
24
+ path: "/observability/metrics/aggregate"
25
+ },
26
+ observabilityMetricBreakdown: {
27
+ method: "POST",
28
+ path: "/observability/metrics/breakdown"
29
+ },
30
+ observabilityMetricTimeSeries: {
31
+ method: "POST",
32
+ path: "/observability/metrics/timeseries"
33
+ },
34
+ observabilityMetricPercentiles: {
35
+ method: "POST",
36
+ path: "/observability/metrics/percentiles"
37
+ },
38
+ observabilityListScores: {
39
+ method: "GET",
40
+ path: "/observability/scores"
41
+ },
42
+ observabilityScoreAggregate: {
43
+ method: "POST",
44
+ path: "/observability/scores/aggregate"
45
+ },
46
+ observabilityScoreBreakdown: {
47
+ method: "POST",
48
+ path: "/observability/scores/breakdown"
49
+ },
50
+ observabilityScoreTimeSeries: {
51
+ method: "POST",
52
+ path: "/observability/scores/timeseries"
53
+ },
54
+ observabilityScorePercentiles: {
55
+ method: "POST",
56
+ path: "/observability/scores/percentiles"
57
+ }
58
+ };
59
+ /** A GET route's query string, one entry per key; repeated keys become arrays. */
60
+ const routeQuerySchema = zod.z.record(zod.z.string(), zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]));
61
+ /** What each tool answers: the route's own status and body, as it would over HTTP. */
62
+ const routeResponseSchema = zod.z.object({
63
+ status: zod.z.number().int(),
64
+ body: zod.z.unknown()
65
+ });
66
+ // src/observability-tools.ts
67
+ /** The server route behind each tool. */
68
+ const OBSERVABILITY_APP_TOOL_ROUTES = {
69
+ observabilityAggregateTraces: _mastra_server_handlers_observability.AGGREGATE_TRACES,
70
+ observabilityAggregateSpans: _mastra_server_handlers_observability.AGGREGATE_SPANS,
71
+ observabilityMetricAggregate: _mastra_server_handlers_observability.GET_METRIC_AGGREGATE,
72
+ observabilityMetricBreakdown: _mastra_server_handlers_observability.GET_METRIC_BREAKDOWN,
73
+ observabilityMetricTimeSeries: _mastra_server_handlers_observability.GET_METRIC_TIME_SERIES,
74
+ observabilityMetricPercentiles: _mastra_server_handlers_observability.GET_METRIC_PERCENTILES,
75
+ observabilityListScores: _mastra_server_handlers_observability.LIST_SCORES,
76
+ observabilityScoreAggregate: _mastra_server_handlers_observability.GET_SCORE_AGGREGATE,
77
+ observabilityScoreBreakdown: _mastra_server_handlers_observability.GET_SCORE_BREAKDOWN,
78
+ observabilityScoreTimeSeries: _mastra_server_handlers_observability.GET_SCORE_TIME_SERIES,
79
+ observabilityScorePercentiles: _mastra_server_handlers_observability.GET_SCORE_PERCENTILES
80
+ };
81
+ function isMastra(value) {
82
+ return typeof value?.getServer === "function";
83
+ }
84
+ function routeTool(id) {
85
+ const route = OBSERVABILITY_APP_TOOL_ROUTES[id];
86
+ const readsQuery = OBSERVABILITY_APP_TOOLS[id].method === "GET";
87
+ return (0, _mastra_core_tools.createTool)({
88
+ id,
89
+ description: route.openapi?.summary ?? `${route.method} ${route.path}`,
90
+ inputSchema: readsQuery ? routeQuerySchema : route.bodySchema,
91
+ outputSchema: routeResponseSchema,
92
+ mcp: { _meta: { ui: { visibility: ["app"] } } },
93
+ execute: async (input, { mastra, requestContext, abortSignal }) => {
94
+ if (!isMastra(mastra)) return {
95
+ status: 503,
96
+ body: { error: `${id} needs a Mastra instance.` }
97
+ };
98
+ return (0, _mastra_server_server_adapter.invokeRoute)(route, {
99
+ mastra,
100
+ requestContext: requestContext ?? new _mastra_core_request_context.RequestContext(),
101
+ ...readsQuery ? { query: routeQuerySchema.parse(input) } : { body: input },
102
+ abortSignal
103
+ });
104
+ }
105
+ });
106
+ }
107
+ /**
108
+ * The app-only tools apps from this package read observability data through. Register them on
109
+ * the MCP server that serves the apps. Each runs its Mastra route in-process as the caller, with
110
+ * the route's own input validation, authentication, RBAC permission and FGA checks, so an app
111
+ * sees exactly the data the signed-in user can read over HTTP.
112
+ */
113
+ const observabilityAppTools = Object.fromEntries(Object.keys(OBSERVABILITY_APP_TOOLS).map((id) => [id, routeTool(id)]));
114
+ exports.OBSERVABILITY_APP_TOOLS = OBSERVABILITY_APP_TOOLS;
115
+ exports.OBSERVABILITY_APP_TOOL_ROUTES = OBSERVABILITY_APP_TOOL_ROUTES;
116
+ exports.observabilityAppTools = observabilityAppTools;
117
+
118
+ //# sourceMappingURL=observability-tools.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability-tools.cjs","names":["z","AGGREGATE_TRACES","AGGREGATE_SPANS","GET_METRIC_AGGREGATE","GET_METRIC_BREAKDOWN","GET_METRIC_TIME_SERIES","GET_METRIC_PERCENTILES","LIST_SCORES","GET_SCORE_AGGREGATE","GET_SCORE_BREAKDOWN","GET_SCORE_TIME_SERIES","GET_SCORE_PERCENTILES","createTool","invokeRoute","RequestContext"],"sources":["../src/observability-protocol.ts","../src/observability-tools.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * The app-only tools apps read observability data through, with the server route each one runs.\n * Apps run in a sandboxed iframe that hosts may forbid from reaching the server, so their requests\n * travel as calls to these tools over the host's existing MCP connection instead.\n */\nexport const OBSERVABILITY_APP_TOOLS = {\n observabilityAggregateTraces: { method: 'POST', path: '/observability/traces/aggregate' },\n observabilityAggregateSpans: { method: 'POST', path: '/observability/spans/aggregate' },\n observabilityMetricAggregate: { method: 'POST', path: '/observability/metrics/aggregate' },\n observabilityMetricBreakdown: { method: 'POST', path: '/observability/metrics/breakdown' },\n observabilityMetricTimeSeries: { method: 'POST', path: '/observability/metrics/timeseries' },\n observabilityMetricPercentiles: { method: 'POST', path: '/observability/metrics/percentiles' },\n observabilityListScores: { method: 'GET', path: '/observability/scores' },\n observabilityScoreAggregate: { method: 'POST', path: '/observability/scores/aggregate' },\n observabilityScoreBreakdown: { method: 'POST', path: '/observability/scores/breakdown' },\n observabilityScoreTimeSeries: { method: 'POST', path: '/observability/scores/timeseries' },\n observabilityScorePercentiles: { method: 'POST', path: '/observability/scores/percentiles' },\n} as const satisfies Record<string, { method: 'GET' | 'POST'; path: string }>;\n\nexport type ObservabilityAppToolName = keyof typeof OBSERVABILITY_APP_TOOLS;\n\n/** A GET route's query string, one entry per key; repeated keys become arrays. */\nexport const routeQuerySchema = z.record(z.string(), z.union([z.string(), z.array(z.string())]));\n\n/** What each tool answers: the route's own status and body, as it would over HTTP. */\nexport const routeResponseSchema = z.object({\n status: z.number().int(),\n body: z.unknown(),\n});\n\nexport type RouteResponse = z.output<typeof routeResponseSchema>;\n","import type { Mastra } from '@mastra/core/mastra';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { createTool } from '@mastra/core/tools';\nimport {\n AGGREGATE_SPANS,\n AGGREGATE_TRACES,\n GET_METRIC_AGGREGATE,\n GET_METRIC_BREAKDOWN,\n GET_METRIC_PERCENTILES,\n GET_METRIC_TIME_SERIES,\n GET_SCORE_AGGREGATE,\n GET_SCORE_BREAKDOWN,\n GET_SCORE_PERCENTILES,\n GET_SCORE_TIME_SERIES,\n LIST_SCORES,\n} from '@mastra/server/handlers/observability';\nimport { invokeRoute } from '@mastra/server/server-adapter';\nimport type { ServerRoute } from '@mastra/server/server-adapter';\nimport { OBSERVABILITY_APP_TOOLS, routeQuerySchema, routeResponseSchema } from './observability-protocol';\nimport type { ObservabilityAppToolName, RouteResponse } from './observability-protocol';\n\nexport { OBSERVABILITY_APP_TOOLS } from './observability-protocol';\nexport type { ObservabilityAppToolName, RouteResponse } from './observability-protocol';\n\n/** The server route behind each tool. */\nexport const OBSERVABILITY_APP_TOOL_ROUTES: Record<ObservabilityAppToolName, ServerRoute> = {\n observabilityAggregateTraces: AGGREGATE_TRACES,\n observabilityAggregateSpans: AGGREGATE_SPANS,\n observabilityMetricAggregate: GET_METRIC_AGGREGATE,\n observabilityMetricBreakdown: GET_METRIC_BREAKDOWN,\n observabilityMetricTimeSeries: GET_METRIC_TIME_SERIES,\n observabilityMetricPercentiles: GET_METRIC_PERCENTILES,\n observabilityListScores: LIST_SCORES,\n observabilityScoreAggregate: GET_SCORE_AGGREGATE,\n observabilityScoreBreakdown: GET_SCORE_BREAKDOWN,\n observabilityScoreTimeSeries: GET_SCORE_TIME_SERIES,\n observabilityScorePercentiles: GET_SCORE_PERCENTILES,\n};\n\n// Structural, not `instanceof`: a second installed copy of @mastra/core has its own Mastra class.\nfunction isMastra(value: unknown): value is Mastra {\n return typeof (value as Partial<Mastra> | undefined)?.getServer === 'function';\n}\n\nfunction routeTool(id: ObservabilityAppToolName) {\n const route = OBSERVABILITY_APP_TOOL_ROUTES[id];\n const readsQuery = OBSERVABILITY_APP_TOOLS[id].method === 'GET';\n\n return createTool({\n id,\n description: route.openapi?.summary ?? `${route.method} ${route.path}`,\n inputSchema: readsQuery ? routeQuerySchema : route.bodySchema,\n outputSchema: routeResponseSchema,\n // Apps call it; hosts keep it away from the model.\n mcp: { _meta: { ui: { visibility: ['app'] } } },\n execute: async (input, { mastra, requestContext, abortSignal }): Promise<RouteResponse> => {\n if (!isMastra(mastra)) return { status: 503, body: { error: `${id} needs a Mastra instance.` } };\n return invokeRoute(route, {\n mastra,\n // Without the caller's context, a server with auth refuses the call.\n requestContext: requestContext ?? new RequestContext(),\n ...(readsQuery ? { query: routeQuerySchema.parse(input) } : { body: input }),\n abortSignal,\n });\n },\n });\n}\n\n/**\n * The app-only tools apps from this package read observability data through. Register them on\n * the MCP server that serves the apps. Each runs its Mastra route in-process as the caller, with\n * the route's own input validation, authentication, RBAC permission and FGA checks, so an app\n * sees exactly the data the signed-in user can read over HTTP.\n */\nexport const observabilityAppTools = Object.fromEntries(\n (Object.keys(OBSERVABILITY_APP_TOOLS) as ObservabilityAppToolName[]).map(id => [id, routeTool(id)]),\n) as Record<ObservabilityAppToolName, ReturnType<typeof routeTool>>;\n"],"mappings":";;;;;;;;;;;;AAOA,MAAa,0BAA0B;CACrC,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAkC;CACxF,6BAA6B;EAAE,QAAQ;EAAQ,MAAM;CAAiC;CACtF,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAmC;CACzF,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAmC;CACzF,+BAA+B;EAAE,QAAQ;EAAQ,MAAM;CAAoC;CAC3F,gCAAgC;EAAE,QAAQ;EAAQ,MAAM;CAAqC;CAC7F,yBAAyB;EAAE,QAAQ;EAAO,MAAM;CAAwB;CACxE,6BAA6B;EAAE,QAAQ;EAAQ,MAAM;CAAkC;CACvF,6BAA6B;EAAE,QAAQ;EAAQ,MAAM;CAAkC;CACvF,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAmC;CACzF,+BAA+B;EAAE,QAAQ;EAAQ,MAAM;CAAoC;AAC7F;;AAKA,MAAa,mBAAmBA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,MAAM,CAACA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;;AAG/F,MAAa,sBAAsBA,IAAAA,EAAE,OAAO;CAC1C,QAAQA,IAAAA,EAAE,OAAO,CAAC,CAAC,IAAI;CACvB,MAAMA,IAAAA,EAAE,QAAQ;AAClB,CAAC;;;ACLD,MAAa,gCAA+E;CAC1F,8BAA8BC,sCAAAA;CAC9B,6BAA6BC,sCAAAA;CAC7B,8BAA8BC,sCAAAA;CAC9B,8BAA8BC,sCAAAA;CAC9B,+BAA+BC,sCAAAA;CAC/B,gCAAgCC,sCAAAA;CAChC,yBAAyBC,sCAAAA;CACzB,6BAA6BC,sCAAAA;CAC7B,6BAA6BC,sCAAAA;CAC7B,8BAA8BC,sCAAAA;CAC9B,+BAA+BC,sCAAAA;AACjC;AAGA,SAAS,SAAS,OAAiC;CACjD,OAAO,OAAQ,OAAuC,cAAc;AACtE;AAEA,SAAS,UAAU,IAA8B;CAC/C,MAAM,QAAQ,8BAA8B;CAC5C,MAAM,aAAa,wBAAwB,GAAG,CAAC,WAAW;CAE1D,QAAA,GAAOC,mBAAAA,WAAAA,CAAW;EAChB;EACA,aAAa,MAAM,SAAS,WAAW,GAAG,MAAM,OAAO,GAAG,MAAM;EAChE,aAAa,aAAa,mBAAmB,MAAM;EACnD,cAAc;EAEd,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE;EAC9C,SAAS,OAAO,OAAO,EAAE,QAAQ,gBAAgB,kBAA0C;GACzF,IAAI,CAAC,SAAS,MAAM,GAAG,OAAO;IAAE,QAAQ;IAAK,MAAM,EAAE,OAAO,GAAG,GAAG,2BAA2B;GAAE;GAC/F,QAAA,GAAOC,8BAAAA,YAAAA,CAAY,OAAO;IACxB;IAEA,gBAAgB,kBAAkB,IAAIC,6BAAAA,eAAe;IACrD,GAAI,aAAa,EAAE,OAAO,iBAAiB,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM;IAC1E;GACF,CAAC;EACH;CACF,CAAC;AACH;;;;;;;AAQA,MAAa,wBAAwB,OAAO,YACzC,OAAO,KAAK,uBAAuB,CAAC,CAAgC,KAAI,OAAM,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CACpG"}
@@ -0,0 +1,18 @@
1
+ import type { ServerRoute } from '@mastra/server/server-adapter';
2
+ import type { ObservabilityAppToolName } from './observability-protocol.js';
3
+ export { OBSERVABILITY_APP_TOOLS } from './observability-protocol.js';
4
+ export type { ObservabilityAppToolName, RouteResponse } from './observability-protocol.js';
5
+ /** The server route behind each tool. */
6
+ export declare const OBSERVABILITY_APP_TOOL_ROUTES: Record<ObservabilityAppToolName, ServerRoute>;
7
+ declare function routeTool(id: ObservabilityAppToolName): import("@mastra/core/tools").Tool<unknown, {
8
+ status: number;
9
+ body: unknown;
10
+ }, unknown, unknown, import("@mastra/core/tools").ToolExecutionContext<unknown, unknown, unknown>, "observabilityAggregateSpans" | "observabilityAggregateTraces" | "observabilityListScores" | "observabilityMetricAggregate" | "observabilityMetricBreakdown" | "observabilityMetricPercentiles" | "observabilityMetricTimeSeries" | "observabilityScoreAggregate" | "observabilityScoreBreakdown" | "observabilityScorePercentiles" | "observabilityScoreTimeSeries", unknown>;
11
+ /**
12
+ * The app-only tools apps from this package read observability data through. Register them on
13
+ * the MCP server that serves the apps. Each runs its Mastra route in-process as the caller, with
14
+ * the route's own input validation, authentication, RBAC permission and FGA checks, so an app
15
+ * sees exactly the data the signed-in user can read over HTTP.
16
+ */
17
+ export declare const observabilityAppTools: Record<ObservabilityAppToolName, ReturnType<typeof routeTool>>;
18
+ //# sourceMappingURL=observability-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability-tools.d.ts","sourceRoot":"","sources":["../src/observability-tools.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAEjE,OAAO,KAAK,EAAE,wBAAwB,EAAiB,MAAM,0BAA0B,CAAC;AAExF,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,YAAY,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAExF,yCAAyC;AACzC,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,wBAAwB,EAAE,WAAW,CAYvF,CAAC;AAOF,iBAAS,SAAS,CAAC,EAAE,EAAE,wBAAwB;;;kdAsB9C;AAED;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAE7B,MAAM,CAAC,wBAAwB,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC"}
@@ -0,0 +1,115 @@
1
+ import { z } from "zod";
2
+ import { RequestContext } from "@mastra/core/request-context";
3
+ import { createTool } from "@mastra/core/tools";
4
+ import { AGGREGATE_SPANS, AGGREGATE_TRACES, GET_METRIC_AGGREGATE, GET_METRIC_BREAKDOWN, GET_METRIC_PERCENTILES, GET_METRIC_TIME_SERIES, GET_SCORE_AGGREGATE, GET_SCORE_BREAKDOWN, GET_SCORE_PERCENTILES, GET_SCORE_TIME_SERIES, LIST_SCORES } from "@mastra/server/handlers/observability";
5
+ import { invokeRoute } from "@mastra/server/server-adapter";
6
+ // src/observability-protocol.ts
7
+ /**
8
+ * The app-only tools apps read observability data through, with the server route each one runs.
9
+ * Apps run in a sandboxed iframe that hosts may forbid from reaching the server, so their requests
10
+ * travel as calls to these tools over the host's existing MCP connection instead.
11
+ */
12
+ const OBSERVABILITY_APP_TOOLS = {
13
+ observabilityAggregateTraces: {
14
+ method: "POST",
15
+ path: "/observability/traces/aggregate"
16
+ },
17
+ observabilityAggregateSpans: {
18
+ method: "POST",
19
+ path: "/observability/spans/aggregate"
20
+ },
21
+ observabilityMetricAggregate: {
22
+ method: "POST",
23
+ path: "/observability/metrics/aggregate"
24
+ },
25
+ observabilityMetricBreakdown: {
26
+ method: "POST",
27
+ path: "/observability/metrics/breakdown"
28
+ },
29
+ observabilityMetricTimeSeries: {
30
+ method: "POST",
31
+ path: "/observability/metrics/timeseries"
32
+ },
33
+ observabilityMetricPercentiles: {
34
+ method: "POST",
35
+ path: "/observability/metrics/percentiles"
36
+ },
37
+ observabilityListScores: {
38
+ method: "GET",
39
+ path: "/observability/scores"
40
+ },
41
+ observabilityScoreAggregate: {
42
+ method: "POST",
43
+ path: "/observability/scores/aggregate"
44
+ },
45
+ observabilityScoreBreakdown: {
46
+ method: "POST",
47
+ path: "/observability/scores/breakdown"
48
+ },
49
+ observabilityScoreTimeSeries: {
50
+ method: "POST",
51
+ path: "/observability/scores/timeseries"
52
+ },
53
+ observabilityScorePercentiles: {
54
+ method: "POST",
55
+ path: "/observability/scores/percentiles"
56
+ }
57
+ };
58
+ /** A GET route's query string, one entry per key; repeated keys become arrays. */
59
+ const routeQuerySchema = z.record(z.string(), z.union([z.string(), z.array(z.string())]));
60
+ /** What each tool answers: the route's own status and body, as it would over HTTP. */
61
+ const routeResponseSchema = z.object({
62
+ status: z.number().int(),
63
+ body: z.unknown()
64
+ });
65
+ // src/observability-tools.ts
66
+ /** The server route behind each tool. */
67
+ const OBSERVABILITY_APP_TOOL_ROUTES = {
68
+ observabilityAggregateTraces: AGGREGATE_TRACES,
69
+ observabilityAggregateSpans: AGGREGATE_SPANS,
70
+ observabilityMetricAggregate: GET_METRIC_AGGREGATE,
71
+ observabilityMetricBreakdown: GET_METRIC_BREAKDOWN,
72
+ observabilityMetricTimeSeries: GET_METRIC_TIME_SERIES,
73
+ observabilityMetricPercentiles: GET_METRIC_PERCENTILES,
74
+ observabilityListScores: LIST_SCORES,
75
+ observabilityScoreAggregate: GET_SCORE_AGGREGATE,
76
+ observabilityScoreBreakdown: GET_SCORE_BREAKDOWN,
77
+ observabilityScoreTimeSeries: GET_SCORE_TIME_SERIES,
78
+ observabilityScorePercentiles: GET_SCORE_PERCENTILES
79
+ };
80
+ function isMastra(value) {
81
+ return typeof value?.getServer === "function";
82
+ }
83
+ function routeTool(id) {
84
+ const route = OBSERVABILITY_APP_TOOL_ROUTES[id];
85
+ const readsQuery = OBSERVABILITY_APP_TOOLS[id].method === "GET";
86
+ return createTool({
87
+ id,
88
+ description: route.openapi?.summary ?? `${route.method} ${route.path}`,
89
+ inputSchema: readsQuery ? routeQuerySchema : route.bodySchema,
90
+ outputSchema: routeResponseSchema,
91
+ mcp: { _meta: { ui: { visibility: ["app"] } } },
92
+ execute: async (input, { mastra, requestContext, abortSignal }) => {
93
+ if (!isMastra(mastra)) return {
94
+ status: 503,
95
+ body: { error: `${id} needs a Mastra instance.` }
96
+ };
97
+ return invokeRoute(route, {
98
+ mastra,
99
+ requestContext: requestContext ?? new RequestContext(),
100
+ ...readsQuery ? { query: routeQuerySchema.parse(input) } : { body: input },
101
+ abortSignal
102
+ });
103
+ }
104
+ });
105
+ }
106
+ /**
107
+ * The app-only tools apps from this package read observability data through. Register them on
108
+ * the MCP server that serves the apps. Each runs its Mastra route in-process as the caller, with
109
+ * the route's own input validation, authentication, RBAC permission and FGA checks, so an app
110
+ * sees exactly the data the signed-in user can read over HTTP.
111
+ */
112
+ const observabilityAppTools = Object.fromEntries(Object.keys(OBSERVABILITY_APP_TOOLS).map((id) => [id, routeTool(id)]));
113
+ export { OBSERVABILITY_APP_TOOLS, OBSERVABILITY_APP_TOOL_ROUTES, observabilityAppTools };
114
+
115
+ //# sourceMappingURL=observability-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability-tools.js","names":[],"sources":["../src/observability-protocol.ts","../src/observability-tools.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * The app-only tools apps read observability data through, with the server route each one runs.\n * Apps run in a sandboxed iframe that hosts may forbid from reaching the server, so their requests\n * travel as calls to these tools over the host's existing MCP connection instead.\n */\nexport const OBSERVABILITY_APP_TOOLS = {\n observabilityAggregateTraces: { method: 'POST', path: '/observability/traces/aggregate' },\n observabilityAggregateSpans: { method: 'POST', path: '/observability/spans/aggregate' },\n observabilityMetricAggregate: { method: 'POST', path: '/observability/metrics/aggregate' },\n observabilityMetricBreakdown: { method: 'POST', path: '/observability/metrics/breakdown' },\n observabilityMetricTimeSeries: { method: 'POST', path: '/observability/metrics/timeseries' },\n observabilityMetricPercentiles: { method: 'POST', path: '/observability/metrics/percentiles' },\n observabilityListScores: { method: 'GET', path: '/observability/scores' },\n observabilityScoreAggregate: { method: 'POST', path: '/observability/scores/aggregate' },\n observabilityScoreBreakdown: { method: 'POST', path: '/observability/scores/breakdown' },\n observabilityScoreTimeSeries: { method: 'POST', path: '/observability/scores/timeseries' },\n observabilityScorePercentiles: { method: 'POST', path: '/observability/scores/percentiles' },\n} as const satisfies Record<string, { method: 'GET' | 'POST'; path: string }>;\n\nexport type ObservabilityAppToolName = keyof typeof OBSERVABILITY_APP_TOOLS;\n\n/** A GET route's query string, one entry per key; repeated keys become arrays. */\nexport const routeQuerySchema = z.record(z.string(), z.union([z.string(), z.array(z.string())]));\n\n/** What each tool answers: the route's own status and body, as it would over HTTP. */\nexport const routeResponseSchema = z.object({\n status: z.number().int(),\n body: z.unknown(),\n});\n\nexport type RouteResponse = z.output<typeof routeResponseSchema>;\n","import type { Mastra } from '@mastra/core/mastra';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { createTool } from '@mastra/core/tools';\nimport {\n AGGREGATE_SPANS,\n AGGREGATE_TRACES,\n GET_METRIC_AGGREGATE,\n GET_METRIC_BREAKDOWN,\n GET_METRIC_PERCENTILES,\n GET_METRIC_TIME_SERIES,\n GET_SCORE_AGGREGATE,\n GET_SCORE_BREAKDOWN,\n GET_SCORE_PERCENTILES,\n GET_SCORE_TIME_SERIES,\n LIST_SCORES,\n} from '@mastra/server/handlers/observability';\nimport { invokeRoute } from '@mastra/server/server-adapter';\nimport type { ServerRoute } from '@mastra/server/server-adapter';\nimport { OBSERVABILITY_APP_TOOLS, routeQuerySchema, routeResponseSchema } from './observability-protocol';\nimport type { ObservabilityAppToolName, RouteResponse } from './observability-protocol';\n\nexport { OBSERVABILITY_APP_TOOLS } from './observability-protocol';\nexport type { ObservabilityAppToolName, RouteResponse } from './observability-protocol';\n\n/** The server route behind each tool. */\nexport const OBSERVABILITY_APP_TOOL_ROUTES: Record<ObservabilityAppToolName, ServerRoute> = {\n observabilityAggregateTraces: AGGREGATE_TRACES,\n observabilityAggregateSpans: AGGREGATE_SPANS,\n observabilityMetricAggregate: GET_METRIC_AGGREGATE,\n observabilityMetricBreakdown: GET_METRIC_BREAKDOWN,\n observabilityMetricTimeSeries: GET_METRIC_TIME_SERIES,\n observabilityMetricPercentiles: GET_METRIC_PERCENTILES,\n observabilityListScores: LIST_SCORES,\n observabilityScoreAggregate: GET_SCORE_AGGREGATE,\n observabilityScoreBreakdown: GET_SCORE_BREAKDOWN,\n observabilityScoreTimeSeries: GET_SCORE_TIME_SERIES,\n observabilityScorePercentiles: GET_SCORE_PERCENTILES,\n};\n\n// Structural, not `instanceof`: a second installed copy of @mastra/core has its own Mastra class.\nfunction isMastra(value: unknown): value is Mastra {\n return typeof (value as Partial<Mastra> | undefined)?.getServer === 'function';\n}\n\nfunction routeTool(id: ObservabilityAppToolName) {\n const route = OBSERVABILITY_APP_TOOL_ROUTES[id];\n const readsQuery = OBSERVABILITY_APP_TOOLS[id].method === 'GET';\n\n return createTool({\n id,\n description: route.openapi?.summary ?? `${route.method} ${route.path}`,\n inputSchema: readsQuery ? routeQuerySchema : route.bodySchema,\n outputSchema: routeResponseSchema,\n // Apps call it; hosts keep it away from the model.\n mcp: { _meta: { ui: { visibility: ['app'] } } },\n execute: async (input, { mastra, requestContext, abortSignal }): Promise<RouteResponse> => {\n if (!isMastra(mastra)) return { status: 503, body: { error: `${id} needs a Mastra instance.` } };\n return invokeRoute(route, {\n mastra,\n // Without the caller's context, a server with auth refuses the call.\n requestContext: requestContext ?? new RequestContext(),\n ...(readsQuery ? { query: routeQuerySchema.parse(input) } : { body: input }),\n abortSignal,\n });\n },\n });\n}\n\n/**\n * The app-only tools apps from this package read observability data through. Register them on\n * the MCP server that serves the apps. Each runs its Mastra route in-process as the caller, with\n * the route's own input validation, authentication, RBAC permission and FGA checks, so an app\n * sees exactly the data the signed-in user can read over HTTP.\n */\nexport const observabilityAppTools = Object.fromEntries(\n (Object.keys(OBSERVABILITY_APP_TOOLS) as ObservabilityAppToolName[]).map(id => [id, routeTool(id)]),\n) as Record<ObservabilityAppToolName, ReturnType<typeof routeTool>>;\n"],"mappings":";;;;;;;;;;;AAOA,MAAa,0BAA0B;CACrC,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAkC;CACxF,6BAA6B;EAAE,QAAQ;EAAQ,MAAM;CAAiC;CACtF,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAmC;CACzF,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAmC;CACzF,+BAA+B;EAAE,QAAQ;EAAQ,MAAM;CAAoC;CAC3F,gCAAgC;EAAE,QAAQ;EAAQ,MAAM;CAAqC;CAC7F,yBAAyB;EAAE,QAAQ;EAAO,MAAM;CAAwB;CACxE,6BAA6B;EAAE,QAAQ;EAAQ,MAAM;CAAkC;CACvF,6BAA6B;EAAE,QAAQ;EAAQ,MAAM;CAAkC;CACvF,8BAA8B;EAAE,QAAQ;EAAQ,MAAM;CAAmC;CACzF,+BAA+B;EAAE,QAAQ;EAAQ,MAAM;CAAoC;AAC7F;;AAKA,MAAa,mBAAmB,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;;AAG/F,MAAa,sBAAsB,EAAE,OAAO;CAC1C,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI;CACvB,MAAM,EAAE,QAAQ;AAClB,CAAC;;;ACLD,MAAa,gCAA+E;CAC1F,8BAA8B;CAC9B,6BAA6B;CAC7B,8BAA8B;CAC9B,8BAA8B;CAC9B,+BAA+B;CAC/B,gCAAgC;CAChC,yBAAyB;CACzB,6BAA6B;CAC7B,6BAA6B;CAC7B,8BAA8B;CAC9B,+BAA+B;AACjC;AAGA,SAAS,SAAS,OAAiC;CACjD,OAAO,OAAQ,OAAuC,cAAc;AACtE;AAEA,SAAS,UAAU,IAA8B;CAC/C,MAAM,QAAQ,8BAA8B;CAC5C,MAAM,aAAa,wBAAwB,GAAG,CAAC,WAAW;CAE1D,OAAO,WAAW;EAChB;EACA,aAAa,MAAM,SAAS,WAAW,GAAG,MAAM,OAAO,GAAG,MAAM;EAChE,aAAa,aAAa,mBAAmB,MAAM;EACnD,cAAc;EAEd,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE;EAC9C,SAAS,OAAO,OAAO,EAAE,QAAQ,gBAAgB,kBAA0C;GACzF,IAAI,CAAC,SAAS,MAAM,GAAG,OAAO;IAAE,QAAQ;IAAK,MAAM,EAAE,OAAO,GAAG,GAAG,2BAA2B;GAAE;GAC/F,OAAO,YAAY,OAAO;IACxB;IAEA,gBAAgB,kBAAkB,IAAI,eAAe;IACrD,GAAI,aAAa,EAAE,OAAO,iBAAiB,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM;IAC1E;GACF,CAAC;EACH;CACF,CAAC;AACH;;;;;;;AAQA,MAAa,wBAAwB,OAAO,YACzC,OAAO,KAAK,uBAAuB,CAAC,CAAgC,KAAI,OAAM,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CACpG"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Structurally an `AppResource` from `@mastra/mcp`, so it drops into `MCPServer`'s `appResources`.
3
+ */
4
+ export type McpAppResource = {
5
+ name: string;
6
+ description: string;
7
+ html: string;
8
+ };
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,94 @@
1
1
  {
2
2
  "name": "@mastra/mcp-apps-components",
3
- "version": "0.0.0",
4
- "description": "Empty placeholder reserving @mastra/mcp-apps-components on npm. Until its first stable release, install @mastra/mcp-apps-components@alpha.",
3
+ "version": "0.1.0-alpha.0",
4
+ "description": "Prebuilt MCP Apps that render Mastra UI components, ready to register as MCP server app resources",
5
5
  "license": "Apache-2.0",
6
+ "type": "module",
7
+ "exports": {
8
+ "./dashboard-renderer": {
9
+ "import": {
10
+ "types": "./dist/dashboard-renderer.d.ts",
11
+ "default": "./dist/dashboard-renderer.js"
12
+ },
13
+ "require": {
14
+ "types": "./dist/dashboard-renderer.d.ts",
15
+ "default": "./dist/dashboard-renderer.cjs"
16
+ }
17
+ },
18
+ "./observability-tools": {
19
+ "import": {
20
+ "types": "./dist/observability-tools.d.ts",
21
+ "default": "./dist/observability-tools.js"
22
+ },
23
+ "require": {
24
+ "types": "./dist/observability-tools.d.ts",
25
+ "default": "./dist/observability-tools.cjs"
26
+ }
27
+ },
28
+ "./package.json": "./package.json"
29
+ },
30
+ "files": [
31
+ "dist"
32
+ ],
33
+ "homepage": "https://mastra.ai",
6
34
  "repository": {
7
35
  "type": "git",
8
36
  "url": "git+https://github.com/mastra-ai/mastra.git",
9
37
  "directory": "packages/mcp-apps-components"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/mastra-ai/mastra/issues"
41
+ },
42
+ "peerDependencies": {
43
+ "@mastra/core": ">=1.81.0-0 <2.0.0-0",
44
+ "@mastra/mcp": ">=2.9.0-0 <3.0.0-0",
45
+ "@mastra/server": ">=1.83.0-0 <2.0.0-0",
46
+ "zod": "^4.2.0"
47
+ },
48
+ "devDependencies": {
49
+ "@hono/node-server": "^2.1.3",
50
+ "@modelcontextprotocol/client": "2.4.0",
51
+ "@modelcontextprotocol/core": "2.4.0",
52
+ "@modelcontextprotocol/ext-apps": "^2.0.3",
53
+ "@modelcontextprotocol/server": "2.4.0",
54
+ "@tailwindcss/vite": "4.3.3",
55
+ "@tanstack/react-query": "^5.104.5",
56
+ "@testing-library/react": "^16.3.3",
57
+ "@types/node": "22.19.15",
58
+ "@types/react": "^19.3.0",
59
+ "@types/react-dom": "^19.3.0",
60
+ "@vitejs/plugin-react": "^6.1.2",
61
+ "hono": "^4.13.13",
62
+ "jsdom": "^30.1.3",
63
+ "msw": "^2.15.0",
64
+ "react": "^19.3.1",
65
+ "react-dom": "^19.3.1",
66
+ "tailwindcss": "4.3.3",
67
+ "tsdown": "0.23.1",
68
+ "tsx": "^4.23.15",
69
+ "typescript": "^7.0.2",
70
+ "vite": "^8.3.5",
71
+ "vite-plugin-singlefile": "^2.3.4",
72
+ "vitest": "5.1.0",
73
+ "zod": "^4.6.7",
74
+ "@internal/lint": "0.0.148",
75
+ "@mastra/client-js": "1.60.0-alpha.0",
76
+ "@mastra/core": "1.83.0-alpha.0",
77
+ "@mastra/hono": "1.7.25-alpha.0",
78
+ "@internal/types-builder": "0.0.123",
79
+ "@mastra/playground-ui": "69.0.0-alpha.0",
80
+ "@mastra/react": "1.15.0-alpha.0",
81
+ "@mastra/mcp": "2.9.0-alpha.0",
82
+ "@mastra/server": "1.83.0-alpha.0"
83
+ },
84
+ "engines": {
85
+ "node": ">=22.13.0"
86
+ },
87
+ "scripts": {
88
+ "build": "tsx scripts/build-apps.ts && tsdown --silent --config tsdown.config.ts",
89
+ "test": "vitest run --project 'unit:packages/mcp-apps-components'",
90
+ "typecheck": "tsc --noEmit",
91
+ "lint": "oxlint --type-aware .",
92
+ "lint:fix": "oxlint --type-aware --fix ."
10
93
  }
11
- }
94
+ }