@ggui-ai/mcp-server 0.3.0-rc.0 → 0.5.0-rc.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.
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
12
  import { type ZodRawShape } from 'zod';
13
- import type { HandlerContext, SharedHandler } from '@ggui-ai/mcp-server-handlers';
13
+ import { type HandlerContext, type SharedHandler } from '@ggui-ai/mcp-server-handlers';
14
14
  import type { Logger } from './logger.js';
15
15
  import { type GguiRenderResourceTemplateOptions } from './mcp-apps-outbound.js';
16
16
  export interface ServerInfo {
@@ -1 +1 @@
1
- {"version":3,"file":"build-mcp.d.ts","sourceRoot":"","sources":["../src/build-mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAK,KAAK,WAAW,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACd,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAEL,KAAK,iCAAiC,EACvC,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iCAAiC,CAAC;IAC3D;;;;;;;;;OASG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IAElE;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC;CACtE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,EAChE,UAAU,EAAE,MAAM,cAAc,EAChC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,qBAA0B,GAC/B,SAAS,CAyJX"}
1
+ {"version":3,"file":"build-mcp.d.ts","sourceRoot":"","sources":["../src/build-mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAK,KAAK,WAAW,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAEL,KAAK,iCAAiC,EACvC,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iCAAiC,CAAC;IAC3D;;;;;;;;;OASG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IAElE;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,aAAa,CAAC,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC,CAAC;CACtE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,EAChE,UAAU,EAAE,MAAM,cAAc,EAChC,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,qBAA0B,GAC/B,SAAS,CAiLX"}
package/dist/build-mcp.js CHANGED
@@ -12,6 +12,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
12
  import { registerAppTool } from '@modelcontextprotocol/ext-apps/server';
13
13
  import { isRecord } from '@ggui-ai/protocol';
14
14
  import { z } from 'zod';
15
+ import { isHandlerFailure, } from '@ggui-ai/mcp-server-handlers';
15
16
  import { installMcpAppsOutbound, } from './mcp-apps-outbound.js';
16
17
  /**
17
18
  * Build a fresh MCP server with every handler registered.
@@ -87,6 +88,30 @@ export function buildMcpServer(info, handlers, getContext, logger, opts = {}) {
87
88
  const start = Date.now();
88
89
  try {
89
90
  const data = await handler.handler(input, ctx);
91
+ // First-class in-result failure channel. A handler that
92
+ // returns the `HandlerFailure` marker gets an `isError: true`
93
+ // TOOL RESULT (never a thrown/JSON-RPC error): the marker's
94
+ // `errorText` is the model-visible content, and its `data` is
95
+ // validated against the SAME outputSchema as a success — MCP
96
+ // SDK clients validate structuredContent against outputSchema
97
+ // even when isError is set, so the envelope stays
98
+ // schema-conformant. NO `_meta` on failures: `resultMeta` is
99
+ // not invoked, so no mount affordance / bootstrap slice is
100
+ // emitted for a failed call.
101
+ if (isHandlerFailure(data)) {
102
+ const validated = z.object(handler.outputSchema).parse(data.data);
103
+ logger.warn('tool_invoked', {
104
+ tool: handler.name,
105
+ appId: ctx.appId,
106
+ outcome: 'tool_error',
107
+ elapsedMs: Date.now() - start,
108
+ });
109
+ return {
110
+ isError: true,
111
+ structuredContent: validated,
112
+ content: [{ type: 'text', text: data.errorText }],
113
+ };
114
+ }
90
115
  const validated = z.object(handler.outputSchema).parse(data);
91
116
  // Per-result `_meta` — NOT merged into structuredContent, so
92
117
  // agents that typecheck against the tool signature never see
@@ -43,7 +43,7 @@
43
43
  * the exact Lane-1 chat-page spec assertion (`/OSS agent
44
44
  * generation/`) without a copy change.
45
45
  */
46
- import type { SharedHandler } from "@ggui-ai/mcp-server-handlers";
46
+ import { type SharedHandler } from "@ggui-ai/mcp-server-handlers";
47
47
  import type { Express } from "express";
48
48
  import type { ZodRawShape } from "zod";
49
49
  import type { Logger } from "./logger.js";
@@ -1 +1 @@
1
- {"version":3,"file":"console-chat-routes.d.ts","sourceRoot":"","sources":["../src/console-chat-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAIvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACjE,+DAA+D;IAC/D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACpE;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,yBAAyB;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAsJ/D"}
1
+ {"version":3,"file":"console-chat-routes.d.ts","sourceRoot":"","sources":["../src/console-chat-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAIvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACjE,+DAA+D;IAC/D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACpE;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,yBAAyB;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CA2K/D"}
@@ -43,6 +43,7 @@
43
43
  * the exact Lane-1 chat-page spec assertion (`/OSS agent
44
44
  * generation/`) without a copy change.
45
45
  */
46
+ import { isHandlerFailure, } from "@ggui-ai/mcp-server-handlers";
46
47
  import { randomUUID } from "node:crypto";
47
48
  import { DEFAULT_BUILDER_APP_ID } from "./auth.js";
48
49
  import { mintDevtoolCookie } from "./console-auth.js";
@@ -101,6 +102,27 @@ export function mountConsoleChatRoutes(opts) {
101
102
  });
102
103
  const handshakeId = hsRaw.handshakeId;
103
104
  const raw = await renderHandler.handler({ handshakeId, contract: {} }, { appId: DEFAULT_BUILDER_APP_ID, requestId });
105
+ if (isHandlerFailure(raw)) {
106
+ // In-result failure envelope (generation failed / rejected).
107
+ // The marker's errorText is the honest self-correction
108
+ // surface — reuse it verbatim; no ui payload (nothing
109
+ // mountable landed for this turn).
110
+ logger.warn?.("console_chat_render_failed", {
111
+ threadId,
112
+ error: raw.errorText,
113
+ });
114
+ res.status(200).json({
115
+ threadId,
116
+ userMessage,
117
+ agentMessage: {
118
+ id: `msg-${randomUUID()}`,
119
+ role: "agent",
120
+ text: raw.errorText,
121
+ createdAt: now + 1,
122
+ },
123
+ });
124
+ return;
125
+ }
104
126
  const result = raw;
105
127
  ui = {
106
128
  sessionId: result.sessionId,
@@ -0,0 +1,160 @@
1
+ /**
2
+ * `/control` — the control plane.
3
+ *
4
+ * ggui serves exactly TWO MCP surfaces:
5
+ *
6
+ * - **Data plane** — the agent routes (`universalMcpPath`, plus the
7
+ * per-tenant `${pathPrefix}/:appId` variant when configured). Carries
8
+ * the `agent` + `runtime` audiences: the tools an agent calls while a
9
+ * session is running.
10
+ * - **Control plane** — this service. Carries the `protocol` + `ops`
11
+ * audiences: design-time spec/discovery (anonymous) and operator-class
12
+ * account management (authenticated, state-changing calls
13
+ * confirm-gated).
14
+ *
15
+ * Audience TAGS stay normative — `audience` on a handler still declares
16
+ * its caller class, and the `ggui_protocol_*` / `ggui_ops_*` wire-name
17
+ * prefixes still encode it. What this module retires is one-HTTP-route-
18
+ * per-audience MOUNTING: `protocol` and `ops` land on the same path.
19
+ *
20
+ * WHY one route for two audiences: an HTTP route carries ONE auth
21
+ * posture. Design-time spec tools must answer bearer-less (an agent
22
+ * authoring a blueprint has no account yet); operator tools must not.
23
+ * Two routes forced a deployment to choose per route, which is why the
24
+ * two surfaces could never be pointed at by a single client config. A
25
+ * service mount is the seam that mixes both: the route is anonymous-
26
+ * capable, and each ops handler re-imposes auth for itself.
27
+ *
28
+ * The per-tool wrappers, in application order (innermost first):
29
+ *
30
+ * 1. {@link withConfirmGate} — state-changing ops only. Turns one
31
+ * call into a deliberate two-call sequence so an agent cannot
32
+ * silently mint credentials, spend credits, or delete resources.
33
+ * 2. {@link withAuthGate} — every ops tool. Rejects callers the auth
34
+ * adapter never authenticated (the anonymous synthetic), so an ops
35
+ * handler never runs against a phantom identity.
36
+ * 3. {@link stripAudience} — every tool. Service handlers MUST NOT
37
+ * carry an `audience` tag (the mount path IS the audience); the tag
38
+ * is consumed by the data-plane route filter and is meaningless
39
+ * inside a service, so dropping it is lossless.
40
+ *
41
+ * Ordering matters: the auth gate sits OUTSIDE the confirm gate, so an
42
+ * unauthenticated caller gets an auth error rather than a confirmation
43
+ * preview that leaks which operations exist against which account.
44
+ */
45
+ import { type SharedHandler } from "@ggui-ai/mcp-server-handlers";
46
+ import { type ZodRawShape } from "zod";
47
+ import type { McpService } from "./mcp-mounts.js";
48
+ type AnyHandler = SharedHandler<ZodRawShape, ZodRawShape>;
49
+ /** Every audience tag a handler may declare. */
50
+ export type AudienceTag = "agent" | "runtime" | "protocol" | "ops";
51
+ /** HTTP path the control plane mounts at. */
52
+ export declare const CONTROL_PATH = "/control";
53
+ /** Service name the control plane reports in validation errors + telemetry. */
54
+ export declare const CONTROL_SERVICE_NAME = "control";
55
+ /** Audiences the data plane (agent routes) serves. */
56
+ export declare const DATA_PLANE_AUDIENCES: ReadonlyArray<AudienceTag>;
57
+ /** Audiences the control plane serves. */
58
+ export declare const CONTROL_PLANE_AUDIENCES: ReadonlyArray<AudienceTag>;
59
+ /**
60
+ * Return the subset of `set` whose `audience` tag intersects `allowed`.
61
+ * The single projection from audience tags to mount surfaces — both
62
+ * planes read it, so a handler can never land on both or on neither.
63
+ *
64
+ * Handlers with `audience: undefined` default to `['agent']`: an
65
+ * untagged handler is agent-callable, which keeps zero-config OSS
66
+ * deployments (whose handlers rarely tag anything) on the data plane.
67
+ */
68
+ export declare function filterHandlersByAudience(set: ReadonlyArray<AnyHandler>, allowed: ReadonlyArray<AudienceTag>): ReadonlyArray<AnyHandler>;
69
+ /**
70
+ * Ops tools that answer in ONE call — reads, lists, and card-openers
71
+ * that change no state. Every other `ops`-tagged tool is treated as
72
+ * state-changing and confirm-gated.
73
+ *
74
+ * The classification is default-DENY on purpose. A curated
75
+ * "these ones are mutating" list has a silent failure mode: land a new
76
+ * state-changing ops tool, forget the list, and it ships un-gated with
77
+ * nothing to notice. Inverting it makes the forgotten case a visible
78
+ * annoyance (an extra confirmation round-trip on a read) instead of an
79
+ * invisible hole, which is the trade the Protocol and Contract Bar asks
80
+ * for — an unflagged gap is a failure in disguise.
81
+ *
82
+ * Deployments that register their own read-only ops tools extend this
83
+ * via `CreateGguiServerOptions.control.singleCallOps` rather than
84
+ * patching this set.
85
+ *
86
+ * `ggui_ops_setup_byok` is a deliberate entry: it LISTS provider-key
87
+ * status and returns the BYOK card — the set/remove tools are the real
88
+ * mutations. Confirm-gating it would break the card's inline render on
89
+ * the first call, because the confirmation preview does not carry the
90
+ * card's discriminant.
91
+ */
92
+ export declare const SINGLE_CALL_OPS: ReadonlySet<string>;
93
+ /**
94
+ * Return a copy of the handler with the `audience` tag removed.
95
+ * `validateMcpServices` rejects service handlers that carry one.
96
+ */
97
+ export declare function stripAudience<I extends ZodRawShape, O extends ZodRawShape, D>(h: SharedHandler<I, O, D>): SharedHandler<I, O, D>;
98
+ /**
99
+ * Require an authenticated caller.
100
+ *
101
+ * The control plane is anonymous-CAPABLE so design-time spec tools
102
+ * answer bearer-less. In that mode the transport synthesizes a builder
103
+ * identity (`authSource: 'anonymous'`) for requests that presented no
104
+ * credential — or presented one the adapter rejected. An un-gated ops
105
+ * handler would then run against that synthetic rather than refusing,
106
+ * which is how a caller with no account would read and write a phantom
107
+ * shared tenant.
108
+ *
109
+ * The gate is on `ctx.authSource`, not on which identity FIELDS are
110
+ * populated: every deployment tier proves identity differently
111
+ * (single-user builder, per-app key, per-user key, OIDC), and only the
112
+ * source distinguishes "the adapter authenticated this request" from
113
+ * "the transport let it through". Transports map
114
+ * {@link AuthRequiredError} to 401 so clients can prompt for sign-in.
115
+ */
116
+ export declare function withAuthGate<I extends ZodRawShape, O extends ZodRawShape, D>(h: SharedHandler<I, O, D>): SharedHandler<I, O, D>;
117
+ /**
118
+ * Wrap a state-changing handler in a stateless two-call confirmation
119
+ * gate. The first call (no `confirm: true`) returns a preview and runs
120
+ * nothing; a second call carrying `confirm: true` delegates to the
121
+ * inner handler.
122
+ *
123
+ * The `confirm` input field and the confirmation output fields live
124
+ * only on this wrapper — the underlying shared handler is untouched, so
125
+ * neither the field nor its `.describe()` text reaches any other
126
+ * caller of the same handler.
127
+ *
128
+ * The declared output schema is the inner schema with every field made
129
+ * optional, PLUS the confirmation fields, so both the preview (only
130
+ * confirmation fields) and a real commit response (inner fields)
131
+ * validate against it.
132
+ */
133
+ export declare function withConfirmGate<I extends ZodRawShape, O extends ZodRawShape, D>(h: SharedHandler<I, O, D>): SharedHandler<ZodRawShape, ZodRawShape>;
134
+ export interface BuildControlServiceArgs {
135
+ /**
136
+ * The server's fully composed handler list. The control plane filters
137
+ * it by audience itself, so callers hand over the same array the data
138
+ * plane reads — membership can never drift between the two.
139
+ */
140
+ readonly handlers: ReadonlyArray<AnyHandler>;
141
+ /**
142
+ * Additional ops tool names that answer in one call. Merged with
143
+ * {@link SINGLE_CALL_OPS}; use it for deployment-registered read-only
144
+ * ops tools that would otherwise be confirm-gated by the default-deny
145
+ * rule.
146
+ */
147
+ readonly singleCallOps?: ReadonlyArray<string>;
148
+ }
149
+ /**
150
+ * Assemble the control plane: every `protocol`-tagged handler served
151
+ * as-is (anonymous), every `ops`-tagged handler auth-gated and — unless
152
+ * it is a known single-call read — confirm-gated.
153
+ *
154
+ * Always `anonymous: true`: the route must answer bearer-less for the
155
+ * design-time tools, and the per-handler auth gate is what keeps the
156
+ * ops half closed.
157
+ */
158
+ export declare function buildControlService(args: BuildControlServiceArgs): McpService;
159
+ export {};
160
+ //# sourceMappingURL=control-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-service.d.ts","sourceRoot":"","sources":["../src/control-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAK,KAAK,WAAW,EAAmB,MAAM,KAAK,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,KAAK,UAAU,GAAG,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAE1D,gDAAgD;AAChD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;AAEnE,6CAA6C;AAC7C,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C,sDAAsD;AACtD,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC,WAAW,CAAwB,CAAC;AAErF,0CAA0C;AAC1C,eAAO,MAAM,uBAAuB,EAAE,aAAa,CAAC,WAAW,CAAuB,CAAC;AAEvF;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,aAAa,CAAC,UAAU,CAAC,EAC9B,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,GAClC,aAAa,CAAC,UAAU,CAAC,CAK3B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAa9C,CAAC;AAEH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,EAC3E,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GACxB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAGxB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,EAC1E,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GACxB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAYxB;AASD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,WAAW,EAAE,CAAC,EAC7E,CAAC,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GACxB,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CA+BzC;AAED,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,uBAAuB,GAAG,UAAU,CAmB7E"}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * `/control` — the control plane.
3
+ *
4
+ * ggui serves exactly TWO MCP surfaces:
5
+ *
6
+ * - **Data plane** — the agent routes (`universalMcpPath`, plus the
7
+ * per-tenant `${pathPrefix}/:appId` variant when configured). Carries
8
+ * the `agent` + `runtime` audiences: the tools an agent calls while a
9
+ * session is running.
10
+ * - **Control plane** — this service. Carries the `protocol` + `ops`
11
+ * audiences: design-time spec/discovery (anonymous) and operator-class
12
+ * account management (authenticated, state-changing calls
13
+ * confirm-gated).
14
+ *
15
+ * Audience TAGS stay normative — `audience` on a handler still declares
16
+ * its caller class, and the `ggui_protocol_*` / `ggui_ops_*` wire-name
17
+ * prefixes still encode it. What this module retires is one-HTTP-route-
18
+ * per-audience MOUNTING: `protocol` and `ops` land on the same path.
19
+ *
20
+ * WHY one route for two audiences: an HTTP route carries ONE auth
21
+ * posture. Design-time spec tools must answer bearer-less (an agent
22
+ * authoring a blueprint has no account yet); operator tools must not.
23
+ * Two routes forced a deployment to choose per route, which is why the
24
+ * two surfaces could never be pointed at by a single client config. A
25
+ * service mount is the seam that mixes both: the route is anonymous-
26
+ * capable, and each ops handler re-imposes auth for itself.
27
+ *
28
+ * The per-tool wrappers, in application order (innermost first):
29
+ *
30
+ * 1. {@link withConfirmGate} — state-changing ops only. Turns one
31
+ * call into a deliberate two-call sequence so an agent cannot
32
+ * silently mint credentials, spend credits, or delete resources.
33
+ * 2. {@link withAuthGate} — every ops tool. Rejects callers the auth
34
+ * adapter never authenticated (the anonymous synthetic), so an ops
35
+ * handler never runs against a phantom identity.
36
+ * 3. {@link stripAudience} — every tool. Service handlers MUST NOT
37
+ * carry an `audience` tag (the mount path IS the audience); the tag
38
+ * is consumed by the data-plane route filter and is meaningless
39
+ * inside a service, so dropping it is lossless.
40
+ *
41
+ * Ordering matters: the auth gate sits OUTSIDE the confirm gate, so an
42
+ * unauthenticated caller gets an auth error rather than a confirmation
43
+ * preview that leaks which operations exist against which account.
44
+ */
45
+ import { AuthRequiredError, } from "@ggui-ai/mcp-server-handlers";
46
+ import { z } from "zod";
47
+ /** HTTP path the control plane mounts at. */
48
+ export const CONTROL_PATH = "/control";
49
+ /** Service name the control plane reports in validation errors + telemetry. */
50
+ export const CONTROL_SERVICE_NAME = "control";
51
+ /** Audiences the data plane (agent routes) serves. */
52
+ export const DATA_PLANE_AUDIENCES = ["agent", "runtime"];
53
+ /** Audiences the control plane serves. */
54
+ export const CONTROL_PLANE_AUDIENCES = ["protocol", "ops"];
55
+ /**
56
+ * Return the subset of `set` whose `audience` tag intersects `allowed`.
57
+ * The single projection from audience tags to mount surfaces — both
58
+ * planes read it, so a handler can never land on both or on neither.
59
+ *
60
+ * Handlers with `audience: undefined` default to `['agent']`: an
61
+ * untagged handler is agent-callable, which keeps zero-config OSS
62
+ * deployments (whose handlers rarely tag anything) on the data plane.
63
+ */
64
+ export function filterHandlersByAudience(set, allowed) {
65
+ return set.filter((h) => {
66
+ const tags = h.audience ?? ["agent"];
67
+ return tags.some((t) => allowed.includes(t));
68
+ });
69
+ }
70
+ /**
71
+ * Ops tools that answer in ONE call — reads, lists, and card-openers
72
+ * that change no state. Every other `ops`-tagged tool is treated as
73
+ * state-changing and confirm-gated.
74
+ *
75
+ * The classification is default-DENY on purpose. A curated
76
+ * "these ones are mutating" list has a silent failure mode: land a new
77
+ * state-changing ops tool, forget the list, and it ships un-gated with
78
+ * nothing to notice. Inverting it makes the forgotten case a visible
79
+ * annoyance (an extra confirmation round-trip on a read) instead of an
80
+ * invisible hole, which is the trade the Protocol and Contract Bar asks
81
+ * for — an unflagged gap is a failure in disguise.
82
+ *
83
+ * Deployments that register their own read-only ops tools extend this
84
+ * via `CreateGguiServerOptions.control.singleCallOps` rather than
85
+ * patching this set.
86
+ *
87
+ * `ggui_ops_setup_byok` is a deliberate entry: it LISTS provider-key
88
+ * status and returns the BYOK card — the set/remove tools are the real
89
+ * mutations. Confirm-gating it would break the card's inline render on
90
+ * the first call, because the confirmation preview does not carry the
91
+ * card's discriminant.
92
+ */
93
+ export const SINGLE_CALL_OPS = new Set([
94
+ "ggui_ops_get_credit_balance",
95
+ "ggui_ops_get_my_blueprint_source",
96
+ "ggui_ops_get_org_balance",
97
+ "ggui_ops_list_apps",
98
+ "ggui_ops_list_blueprints",
99
+ "ggui_ops_list_connector_keys",
100
+ "ggui_ops_list_credit_transactions",
101
+ "ggui_ops_list_my_apps",
102
+ "ggui_ops_list_my_blueprints",
103
+ "ggui_ops_list_orgs",
104
+ "ggui_ops_list_provider_keys",
105
+ "ggui_ops_setup_byok",
106
+ ]);
107
+ /**
108
+ * Return a copy of the handler with the `audience` tag removed.
109
+ * `validateMcpServices` rejects service handlers that carry one.
110
+ */
111
+ export function stripAudience(h) {
112
+ const { audience: _omit, ...rest } = h;
113
+ return rest;
114
+ }
115
+ /**
116
+ * Require an authenticated caller.
117
+ *
118
+ * The control plane is anonymous-CAPABLE so design-time spec tools
119
+ * answer bearer-less. In that mode the transport synthesizes a builder
120
+ * identity (`authSource: 'anonymous'`) for requests that presented no
121
+ * credential — or presented one the adapter rejected. An un-gated ops
122
+ * handler would then run against that synthetic rather than refusing,
123
+ * which is how a caller with no account would read and write a phantom
124
+ * shared tenant.
125
+ *
126
+ * The gate is on `ctx.authSource`, not on which identity FIELDS are
127
+ * populated: every deployment tier proves identity differently
128
+ * (single-user builder, per-app key, per-user key, OIDC), and only the
129
+ * source distinguishes "the adapter authenticated this request" from
130
+ * "the transport let it through". Transports map
131
+ * {@link AuthRequiredError} to 401 so clients can prompt for sign-in.
132
+ */
133
+ export function withAuthGate(h) {
134
+ return {
135
+ ...h,
136
+ async handler(input, ctx) {
137
+ if (ctx.authSource === undefined || ctx.authSource === "anonymous") {
138
+ throw new AuthRequiredError(`${h.name} is an operator tool and needs an authenticated caller. Present a bearer token this deployment accepts.`);
139
+ }
140
+ return h.handler(input, ctx);
141
+ },
142
+ };
143
+ }
144
+ /** Map every field of a Zod raw-shape to its `.optional()` form. */
145
+ function optionalize(shape) {
146
+ return Object.fromEntries(Object.entries(shape).map(([key, value]) => [key, value.optional()]));
147
+ }
148
+ /**
149
+ * Wrap a state-changing handler in a stateless two-call confirmation
150
+ * gate. The first call (no `confirm: true`) returns a preview and runs
151
+ * nothing; a second call carrying `confirm: true` delegates to the
152
+ * inner handler.
153
+ *
154
+ * The `confirm` input field and the confirmation output fields live
155
+ * only on this wrapper — the underlying shared handler is untouched, so
156
+ * neither the field nor its `.describe()` text reaches any other
157
+ * caller of the same handler.
158
+ *
159
+ * The declared output schema is the inner schema with every field made
160
+ * optional, PLUS the confirmation fields, so both the preview (only
161
+ * confirmation fields) and a real commit response (inner fields)
162
+ * validate against it.
163
+ */
164
+ export function withConfirmGate(h) {
165
+ const inputSchema = {
166
+ ...h.inputSchema,
167
+ confirm: z
168
+ .boolean()
169
+ .optional()
170
+ .describe("Set true to actually perform this state-changing operation. Omitted/false returns a confirmation preview instead."),
171
+ };
172
+ const outputSchema = {
173
+ ...optionalize(h.outputSchema),
174
+ confirmationRequired: z.boolean().optional(),
175
+ confirmationPrompt: z.string().optional(),
176
+ };
177
+ return {
178
+ ...h,
179
+ description: `${h.description} (State-changing: the first call returns a confirmation prompt; re-call with confirm:true to proceed.)`,
180
+ inputSchema,
181
+ outputSchema,
182
+ async handler(input, ctx) {
183
+ if (input.confirm !== true) {
184
+ return {
185
+ confirmationRequired: true,
186
+ confirmationPrompt: `Calling ${h.name} will change account state. Show the human exactly what will happen and, only with their explicit approval, call ${h.name} again with confirm:true.`,
187
+ };
188
+ }
189
+ const { confirm: _confirm, ...rest } = input;
190
+ return h.handler(rest, ctx);
191
+ },
192
+ };
193
+ }
194
+ /**
195
+ * Assemble the control plane: every `protocol`-tagged handler served
196
+ * as-is (anonymous), every `ops`-tagged handler auth-gated and — unless
197
+ * it is a known single-call read — confirm-gated.
198
+ *
199
+ * Always `anonymous: true`: the route must answer bearer-less for the
200
+ * design-time tools, and the per-handler auth gate is what keeps the
201
+ * ops half closed.
202
+ */
203
+ export function buildControlService(args) {
204
+ const singleCall = new Set([...SINGLE_CALL_OPS, ...(args.singleCallOps ?? [])]);
205
+ const protocolTools = filterHandlersByAudience(args.handlers, ["protocol"]);
206
+ const opsTools = filterHandlersByAudience(args.handlers, ["ops"]);
207
+ const handlers = [
208
+ ...protocolTools.map((h) => stripAudience(h)),
209
+ ...opsTools.map((h) => {
210
+ const confirmed = singleCall.has(h.name) ? h : withConfirmGate(h);
211
+ return stripAudience(withAuthGate(confirmed));
212
+ }),
213
+ ];
214
+ return {
215
+ name: CONTROL_SERVICE_NAME,
216
+ path: CONTROL_PATH,
217
+ handlers,
218
+ anonymous: true,
219
+ };
220
+ }
package/dist/index.d.ts CHANGED
@@ -29,13 +29,15 @@ export type { HandlerContext, SharedHandler } from '@ggui-ai/mcp-server-handlers
29
29
  export type { GadgetDescriptor, McpUiDisplayMode, GguiSession, SystemGguiSession, } from '@ggui-ai/protocol';
30
30
  export type { GenerationDeps } from '@ggui-ai/mcp-server-handlers';
31
31
  export { buildNoCredentialsGguiSession } from '@ggui-ai/mcp-server-handlers';
32
- export { createGguiServer, defaultHandlers } from './server.js';
33
- export type { CreateGguiServerOptions, GguiServer, } from './server.js';
32
+ export { buildOpsBundleHandlers, createGguiServer, defaultHandlers } from './server.js';
33
+ export type { CreateGguiServerOptions, GguiServer, OpsBundleDeps, } from './server.js';
34
+ export { buildControlService, CONTROL_PATH, filterHandlersByAudience, SINGLE_CALL_OPS, } from './control-service.js';
35
+ export type { AudienceTag, BuildControlServiceArgs } from './control-service.js';
34
36
  export { FileSystemCodeStore } from './code-store-fs.js';
35
37
  export type { FileSystemCodeStoreOptions } from './code-store-fs.js';
36
38
  export type { McpServerMount } from './mcp-mounts.js';
37
39
  export type { McpService, ServicePath } from './mcp-mounts.js';
38
- export { validateMcpServices, validateServicePath } from './mcp-mounts.js';
40
+ export { validateMcpServices, validateServiceHandlers, validateServicePath, } from './mcp-mounts.js';
39
41
  export { composePreviewReservedValidator, mergeReservedValidators, } from './reserved-validators.js';
40
42
  export { checkRenderSchemaCompat, DEFAULT_SCHEMA_COMPAT_MODE, hasErrorFinding, SchemaCompatError, } from './schema-compat.js';
41
43
  export type { SchemaCompatFinding, SchemaCompatMode, SchemaCompatReport, GguiSessionContractShape, ToolSchemaRef, } from './schema-compat.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -30,12 +30,18 @@
30
30
  // `/settings` URL) without taking a direct `@ggui-ai/mcp-server-handlers`
31
31
  // dependency.
32
32
  export { buildNoCredentialsGguiSession } from '@ggui-ai/mcp-server-handlers';
33
- export { createGguiServer, defaultHandlers } from './server.js';
33
+ export { buildOpsBundleHandlers, createGguiServer, defaultHandlers } from './server.js';
34
+ // Control plane (`/control`) — the composition that projects every
35
+ // `protocol`- and `ops`-tagged handler onto one anonymous-capable
36
+ // route with per-tool auth + confirmation gates. `createGguiServer`
37
+ // mounts it automatically; the pieces are exported so deployments can
38
+ // assert their own control surface at boot.
39
+ export { buildControlService, CONTROL_PATH, filterHandlersByAudience, SINGLE_CALL_OPS, } from './control-service.js';
34
40
  // Content-addressable code delivery (2026-05-03). FileSystemCodeStore
35
41
  // is the OSS dev default; in-memory variant ships in
36
42
  // `@ggui-ai/mcp-server-core/in-memory` for tests + ephemeral runs.
37
43
  export { FileSystemCodeStore } from './code-store-fs.js';
38
- export { validateMcpServices, validateServicePath } from './mcp-mounts.js';
44
+ export { validateMcpServices, validateServiceHandlers, validateServicePath, } from './mcp-mounts.js';
39
45
  // Reserved-channel payload validator composition.
40
46
  // `composePreviewReservedValidator` binds the A2UI adapter
41
47
  // for `_ggui:preview`; `mergeReservedValidators` layers caller-provided
@@ -1,11 +1,13 @@
1
1
  /**
2
- * MCP wire endpoints — the audience-routed JSON-RPC surfaces.
2
+ * MCP wire endpoints — the JSON-RPC surfaces.
3
3
  *
4
- * POST <universalMcpPath> — agent+runtime tools (default `/mcp`)
5
- * POST <pathPrefix>/:appId — per-tenant variant (opt-in via
6
- * `perAppRouting`)
7
- * POST /protocol — design-time spec/discovery tools
8
- * POST /ops — operator-class management tools
4
+ * POST <universalMcpPath> — DATA PLANE: agent+runtime tools
5
+ * (default `/mcp`)
6
+ * POST <pathPrefix>/:appId — data plane, per-tenant variant
7
+ * (opt-in via `perAppRouting`)
8
+ * POST /control — CONTROL PLANE: design-time
9
+ * spec/discovery (anonymous) +
10
+ * operator management (authed)
9
11
  * POST <service.path> — isolated MCP services (path IS
10
12
  * the audience)
11
13
  * GET/DELETE on each — 405 (stateless server; no
@@ -13,13 +15,18 @@
13
15
  * session-terminate verbs)
14
16
  *
15
17
  * Every route shares ONE request pipeline (`makeMcpHandler`): resolve
16
- * identity via the AuthAdapter (anonymous services synthesize a
18
+ * identity via the AuthAdapter (anonymous surfaces synthesize a
17
19
  * builder identity on missing/invalid bearers), apply the per-app
18
20
  * authorize hook, build a fresh `McpServer` + Streamable HTTP
19
21
  * transport per request (stateless), and dispatch under the
20
22
  * AsyncLocalStorage-scoped `HandlerContext`. The difference between
21
23
  * routes is ONLY the handler set each exposes.
22
24
  *
25
+ * Audience TAGS remain the normative caller-class declaration; what
26
+ * they no longer do is mint one HTTP route each. `protocol` and `ops`
27
+ * both mount on `/control` — see `./control-service.ts` for why (one
28
+ * route carries one auth posture; the control plane needs two).
29
+ *
23
30
  * See `docs/development/audience-routes.md` for the audience taxonomy
24
31
  * (`agent` / `runtime` / `protocol` / `ops`) and the wire-name prefix
25
32
  * rules.
@@ -48,8 +55,15 @@ interface MountOptions {
48
55
  readonly auth: AuthAdapter;
49
56
  /** Server identity forwarded to every per-request `buildMcpServer`. */
50
57
  readonly info: ServerInfo;
51
- /** Full composed handler list (audience filtering happens here). */
58
+ /** Full composed handler list (data-plane audience filtering happens here). */
52
59
  readonly handlers: ReadonlyArray<SharedHandler<ZodRawShape, ZodRawShape>>;
60
+ /**
61
+ * Control-plane handler set — already projected + wrapped by
62
+ * `buildControlService`. Passed pre-built rather than filtered here
63
+ * because the per-tool auth/confirm wrappers are composition, not
64
+ * transport.
65
+ */
66
+ readonly controlHandlers: ReadonlyArray<SharedHandler<ZodRawShape, ZodRawShape>>;
53
67
  /** Validated isolated-service list (`validateMcpServices` output). */
54
68
  readonly mcpServices: ReadonlyArray<McpService>;
55
69
  /** Request-scoped HandlerContext storage shared with the handlers. */
@@ -79,9 +93,9 @@ interface MountOptions {
79
93
  readonly buildMcpOptions: BuildMcpServerOptions;
80
94
  }
81
95
  /**
82
- * Mount the universal / per-app / protocol / ops / service MCP
83
- * endpoints onto the express app. Returns nothing — the routes
84
- * self-register.
96
+ * Mount the data-plane (universal / per-app), control-plane, and
97
+ * service MCP endpoints onto the express app. Returns nothing — the
98
+ * routes self-register.
85
99
  */
86
100
  export declare function mountMcpEndpoints(opts: MountOptions): void;
87
101
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-endpoint-routes.d.ts","sourceRoot":"","sources":["../src/mcp-endpoint-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElF,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAEvC,OAAO,EAAkB,KAAK,qBAAqB,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,sFAAsF;AACtF,UAAU,aAAa;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChF;AAED,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IAC1E,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAChD,sEAAsE;IACtE,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAChD,qDAAqD;IACrD,QAAQ,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC;IAC3D,wEAAwE;IACxE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,CACrB,GAAG,EAAE,OAAO,KACT;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAC9F;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC;CACjD;AAyBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CA4V1D"}
1
+ {"version":3,"file":"mcp-endpoint-routes.d.ts","sourceRoot":"","sources":["../src/mcp-endpoint-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElF,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAEvC,OAAO,EAAkB,KAAK,qBAAqB,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAM7F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,sFAAsF;AACtF,UAAU,aAAa;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChF;AAED,UAAU,YAAY;IACpB,iCAAiC;IACjC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IAC1E;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,aAAa,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;IACjF,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAChD,sEAAsE;IACtE,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC;IAChD,qDAAqD;IACrD,QAAQ,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC;IAC3D,wEAAwE;IACxE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,CACrB,GAAG,EAAE,OAAO,KACT;QAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IAC9F;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAC;CACjD;AAyBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CA4U1D"}