@happyvertical/smrt-app-mcp 0.53.2 → 0.53.4

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.
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-app-mcp",
5
- "packageVersion": "0.53.2",
5
+ "packageVersion": "0.53.4",
6
6
  "objects": {},
7
7
  "moduleType": "smrt",
8
8
  "smrtDependencies": [
package/dist/server.d.ts CHANGED
@@ -18,6 +18,7 @@
18
18
  import type { MCPConfig, MCPResponse, MCPTool } from '@happyvertical/smrt-core/generators/mcp';
19
19
  import { type McpTask } from '@happyvertical/smrt-jobs';
20
20
  import { type McpAppResource, type McpAppResourceContent, type McpAppResourceDefinition, type McpResourcePolicy } from './resources.js';
21
+ import { type McpToolEffect } from './tools.js';
21
22
  import { type McpWorkflowToolDefinition } from './workflow-tools.js';
22
23
  /**
23
24
  * Generic authenticated caller information available to app-MCP policy.
@@ -53,6 +54,15 @@ export interface McpToolPolicyContext {
53
54
  * boundary.
54
55
  */
55
56
  export type McpToolPolicy = (context: McpToolPolicyContext) => boolean | Promise<boolean>;
57
+ /**
58
+ * Principal-level predicate for durable task lifecycle calls (`tasks/get`,
59
+ * `tasks/update`, `tasks/cancel`). It receives the authenticated, bound
60
+ * principal (with effective scopes) and no tool: return `false` to answer
61
+ * the call as an unknown task. A thrown error is a denial.
62
+ */
63
+ export type McpTaskPrincipalPolicy = (context: {
64
+ principal: McpAppPrincipal;
65
+ }) => boolean | Promise<boolean>;
56
66
  /**
57
67
  * Workflow assertion hook signature. Throw `McpAccessError` to reject the
58
68
  * call. Implementations may mutate `args` in place to inject server-trusted
@@ -128,7 +138,25 @@ export interface CreateMcpAppServerOptions {
128
138
  * assertion gates before the handler runs.
129
139
  */
130
140
  workflowTools?: readonly McpWorkflowToolDefinition[];
141
+ /**
142
+ * Restrict the catalog to tools whose effect (see `mcpToolEffect`) is
143
+ * listed, for example `['read']` until per-operation authorization exists.
144
+ * Excluded tools are absent from discovery and a direct call receives the
145
+ * same not-found error as an unknown tool, so they cannot be enumerated.
146
+ * Omitted: every allow-listed tool, regardless of effect.
147
+ */
148
+ effects?: readonly McpToolEffect[];
131
149
  resources?: readonly McpAppResourceDefinition[];
150
+ /**
151
+ * Gate every task lifecycle call (`tasks/get`, `tasks/update`,
152
+ * `tasks/cancel`) on the calling principal before the task store is
153
+ * touched; a denial is answered as an unknown task. `toolPolicy` is not
154
+ * re-applied to lifecycle calls (a task does not yet record the tool that
155
+ * created it), so a server whose `toolPolicy` encodes principal-level
156
+ * requirements (scopes, roles, revocation) should restate them here.
157
+ * `createDefaultMcpAppServer` supplies its principal scope policy.
158
+ */
159
+ taskPrincipalPolicy?: McpTaskPrincipalPolicy;
132
160
  /** Required for private resources; rechecked on catalog/read, errors deny. */
133
161
  resourcePolicy?: McpResourcePolicy;
134
162
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,OAAO,EAER,MAAM,yCAAyC,CAAC;AAKjD,OAAO,EACL,KAAK,OAAO,EAGb,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EAEvB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,UAAW,SAAQ,eAAe;IACjD,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,kEAAkE;AAClE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,eAAe,GAAG,IAAI,CAAC;IAClC,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,oBAAoB,KAC1B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,EAAE,UAAU,GAAG,IAAI,KACpB,IAAI,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhE,mEAAmE;AACnE,MAAM,MAAM,0BAA0B,GAAG,MAAM,SAAS,MAAM,EAAE,CAAC;AAEjE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,GAAG,QAAQ,CAAC;CAClC;AAED,MAAM,WAAW,uBAAuB;IACtC,uFAAuF;IACvF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,UAAU,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAClC;;;OAGG;IACH,aAAa,CAAC,EAAE,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,mEAAmE;IACnE,WAAW,EAAE,mBAAmB,CAAC;IACjC,oDAAoD;IACpD,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GACvD,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACjC;;;;OAIG;IACH,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IAChD;;;;OAIG;IACH,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC;;;;OAIG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC1D;;;;;OAKG;IACH,aAAa,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IACrD,SAAS,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAC;IAChD,8EAA8E;IAC9E,cAAc,CAAC,EAAE,iBAAiB,CAAC;CACpC;AAED,2BAA2B;AAC3B,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAwB;AACxB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,4EAA4E;IAC5E,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACnC;;;OAGG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAC1B;AAED,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,aAAa,CAAC,CAAC,KAAK,EAAE;QACpB,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;KACpC,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9B,YAAY,CAAC,CAAC,KAAK,EAAE;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;KACpC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,0EAA0E;IAC1E,cAAc,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,yDAAyD;IACzD,UAAU,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5C,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACtD,kDAAkD;IAClD,OAAO,CAAC,CAAC,KAAK,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;KACpC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrB,UAAU,CAAC,CAAC,KAAK,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACxC,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;KACpC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,UAAU,CAAC,CAAC,KAAK,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;KACpC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,sDAAsD;IACtD,qBAAqB,CAAC,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACxD,wDAAwD;IACxD,QAAQ,CAAC,UAAU,EAAE,yBAAyB,CAAC,YAAY,CAAC,CAAC;CAC9D;AAmDD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAmad"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -3,13 +3,13 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-app-mcp",
6
- "packageVersion": "0.53.2",
6
+ "packageVersion": "0.53.4",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "abb32c79199aee969e19305b5728113a46c851dabc7d9d0ead3f558f897f8a1a",
11
- "packageJson": "494c6edd5988c8a166e8a781f848017b834c00b93a6a8b1d8d315804379852b4",
12
- "agents": "f249d4732daeb08f865b67237c0da2b166a96f749b1ec6b595f2bb17c24c2d30"
10
+ "manifest": "6120f0bf5cd17dac127eddd35008fe6e915e94497ea45468598192e57214c7da",
11
+ "packageJson": "d09f736bb447a05e0aacced0916f919636d75b08f989bd7e18a8fd3fbb316486",
12
+ "agents": "ff20746755dfba41c50728115c8f3d301d876bd3a9f560e51e17ee0dc759733e"
13
13
  },
14
14
  "exports": [
15
15
  ".",
@@ -59,5 +59,5 @@
59
59
  "polymorphicAssociations": 0,
60
60
  "uuidColumns": 0
61
61
  },
62
- "agentDoc": "# @happyvertical/smrt-app-mcp\n\nApplication-scoped MCP server wrapper for SMRT apps. The core owns generated\ntool policy; `./sveltekit` owns the stateless Streamable HTTP transport.\n\n## Purpose\n\n- Wraps `@happyvertical/smrt-core` MCP generation with app-level tool allow-lists.\n- Filters unauthenticated tool visibility to public read-only tools.\n- Applies an optional principal-aware policy consistently to discovery and calls.\n- Provides workflow assertions so app servers can reject unsafe or incomplete tool calls before dispatch.\n- Exposes an opt-in durable Tasks extension through `@happyvertical/smrt-jobs`.\n\n## Patterns\n\n- Generate tools from core, then filter by allowed class-name prefixes.\n- Treat list/get tools as read-only; mutating tools require authentication unless the app deliberately wraps them with stronger policy.\n- Keep app policy outside generated tool schemas. The wrapper owns auth, allow-list, and workflow assertion behavior.\n- Return 404 for tools outside the app allow-list so private generated tools are not enumerated by mistake.\n- Trust only a principal supplied by the application adapter. This package\n does not implement an OAuth authorization server. The opt-in `./auth` entry\n validates JWT access tokens and requires an application-owned principal mapper.\n- Mount `mountMcpRoute` as one modern `POST` endpoint. It creates a fresh\n protocol server per request, emits no session id, and refuses subscriptions.\n- Keep tool catalogs private by default. Public caching requires an explicit\n attestation and a global, unauthenticated, read-only, non-tenant catalog with\n no principal-aware policy.\n\n## Gotchas\n\n- Public tool patterns are still constrained by read-only detection.\n- Policy errors fail closed and expose only the shared safe denial envelope.\n- Workflow assertions run before generated tool dispatch and should be deterministic.\n- Tasks require a stable authenticated principal id, preserve its tenant boundary,\n and require the deployment to run a `TaskRunner` for the `mcp-tasks` queue.\n- This package ships no stdio executable. Use `@happyvertical/smrt-app-cli` to\n bridge a deployed app endpoint to a local MCP client.\n- `mountMcpToolsRoute` and `mountMcpCallRoute` are deprecated REST-shaped\n compatibility aliases, not MCP transports.\n- This package is runtime app infrastructure, not the development MCP. Use `@happyvertical/smrt-dev-mcp` for agentic development knowledge, review, and architecture tooling.\n"
62
+ "agentDoc": "# @happyvertical/smrt-app-mcp\n\nApplication-scoped MCP server wrapper for SMRT apps. The core owns generated\ntool policy; `./sveltekit` owns the stateless Streamable HTTP transport.\n\n## Purpose\n\n- Wraps `@happyvertical/smrt-core` MCP generation with app-level tool allow-lists.\n- Filters unauthenticated tool visibility to public read-only tools.\n- Applies an optional principal-aware policy consistently to discovery and calls.\n- Provides workflow assertions so app servers can reject unsafe or incomplete tool calls before dispatch.\n- Exposes an opt-in durable Tasks extension through `@happyvertical/smrt-jobs`.\n\n## Patterns\n\n- Generate tools from core, then filter by allowed class-name prefixes.\n- Treat list/get tools as read-only; mutating tools require authentication unless the app deliberately wraps them with stronger policy.\n- Keep app policy outside generated tool schemas. The wrapper owns auth, allow-list, and workflow assertion behavior.\n- Return 404 for tools outside the app allow-list so private generated tools are not enumerated by mistake.\n- Trust only a principal supplied by the application adapter. This package\n does not implement an OAuth authorization server. The opt-in `./auth` entry\n validates JWT access tokens and requires an application-owned principal mapper.\n- Mount `mountMcpRoute` as one modern `POST` endpoint. It creates a fresh\n protocol server per request, emits no session id, and refuses subscriptions.\n- `mountMcpAppRoute` (`src/defaults.ts` + `./sveltekit`) is the one-call app\n route: explicit `models` allow-list, required `requiredScopes`, principal from\n session locals (`principalFromSessionLocals`). App policies compose with the\n default and may only narrow it. Its `Origin` check (default on; opt-in on\n `mountMcpRoute`) runs before auth and dispatch; no-`Origin` clients pass.\n `effects` filters the catalog by `mcpToolEffect` (excluded tools 404).\n `auth` swaps in bearer principals; `bindPrincipal` runs their dispatch in\n the app's principal context (RLS transaction), failing closed, and\n authorizes with the binder's narrowed (live) scopes; task lifecycle calls\n re-check the originating action against the allow-list and `effects`,\n after a principal-level `taskPrincipalPolicy` (defaults: scope policy);\n `mountMcpProtectedResourceMetadataRoute` serves only the advertised path.\n- Keep tool catalogs private by default. Public caching requires an explicit\n attestation and a global, unauthenticated, read-only, non-tenant catalog with\n no principal-aware policy.\n\n## Gotchas\n\n- Public tool patterns are still constrained by read-only detection.\n- Policy errors fail closed and expose only the shared safe denial envelope.\n- Workflow assertions run before generated tool dispatch and should be deterministic.\n- Tasks require a stable authenticated principal id, preserve its tenant boundary,\n and require the deployment to run a `TaskRunner` for the `mcp-tasks` queue.\n- This package ships no stdio executable. Use `@happyvertical/smrt-app-cli` to\n bridge a deployed app endpoint to a local MCP client.\n- `mountMcpToolsRoute` and `mountMcpCallRoute` are deprecated REST-shaped\n compatibility aliases, not MCP transports.\n- This package is runtime app infrastructure, not the development MCP. Use `@happyvertical/smrt-dev-mcp` for agentic development knowledge, review, and architecture tooling.\n"
63
63
  }
@@ -7,12 +7,26 @@
7
7
  *
8
8
  * @example
9
9
  * ```ts
10
- * // src/routes/api/mcp/+server.ts
10
+ * // src/routes/api/mcp/+server.ts — one call with the app defaults
11
+ * import { mountMcpAppRoute } from '@happyvertical/smrt-app-mcp/sveltekit';
12
+ * import { Item } from '$lib/objects/Item';
13
+ * export const POST = mountMcpAppRoute({
14
+ * models: [Item],
15
+ * requiredScopes: ['items.read'],
16
+ * smrtOptions: () => ({ db: getDatabaseConfig() }),
17
+ * });
18
+ * ```
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // src/routes/api/mcp/+server.ts — a custom server core
11
23
  * import { mountMcpRoute } from '@happyvertical/smrt-app-mcp/sveltekit';
12
24
  * import { mcpServer } from '$lib/server/mcp';
13
25
  * export const POST = mountMcpRoute(mcpServer);
14
26
  * ```
15
27
  */
28
+ import type { McpResourceAuth } from './auth.js';
29
+ import { type CreateDefaultMcpAppServerOptions } from './defaults.js';
16
30
  import { type McpProtocolRequestOptions } from './protocol.js';
17
31
  import type { McpAppPrincipal, McpAppServer } from './server.js';
18
32
  /** Minimal subset of a SvelteKit RequestEvent we actually touch. */
@@ -27,8 +41,94 @@ export type McpSvelteKitHandler = (event: SvelteKitRequestEvent) => Promise<Resp
27
41
  export type McpPrincipalResolver = (event: SvelteKitRequestEvent) => McpAppPrincipal | null | undefined;
28
42
  /** Backwards-compatible alias for callers that name the principal a user. */
29
43
  export type McpUserResolver = McpPrincipalResolver;
44
+ /**
45
+ * The bearer-authentication surface `mountMcpRoute` and the metadata route
46
+ * need from `createMcpResourceAuth` (`./auth`). Typed structurally so this
47
+ * entry does not load the JWT verifier.
48
+ */
49
+ export type McpRouteResourceAuth = Pick<McpResourceAuth, 'metadataUrl' | 'metadataResponse' | 'authenticate'>;
50
+ /**
51
+ * A protected-resource adapter, or a thunk read on every request. A `null` or
52
+ * `undefined` result (for example the `local` profile) means the route uses
53
+ * its session principal resolver instead.
54
+ */
55
+ export type McpRouteResourceAuthSource = McpRouteResourceAuth | null | undefined | (() => McpRouteResourceAuth | null | undefined);
56
+ /**
57
+ * Project the session hook's request-local result onto an MCP principal.
58
+ *
59
+ * Reads only `locals.user.id`, the session-authorized `locals.tenantId`, and
60
+ * `locals.permissions` as populated by `createSessionHandler` from
61
+ * `@happyvertical/smrt-users/sveltekit`. Headers, URL-selected tenants
62
+ * (`locals.selectedTenantId`), request bodies and route arguments are never
63
+ * identity inputs. Any missing or malformed field yields `null`
64
+ * (unauthenticated), which fails closed for every non-public tool.
65
+ */
66
+ export declare function principalFromSessionLocals(event: {
67
+ locals?: Record<string, unknown>;
68
+ }): McpAppPrincipal | null;
69
+ /**
70
+ * Run MCP dispatch for a bearer-authenticated principal inside an
71
+ * application-owned context bound to that principal (for example
72
+ * `runtime.runAsPrincipal` from `@happyvertical/smrt-app-runtime/sveltekit`,
73
+ * which opens the principal's permission context and, under `database-rls`,
74
+ * its RLS transaction). Must call `run` exactly once and return its result;
75
+ * throwing before `run` (an unbindable principal) is a denial.
76
+ *
77
+ * Pass `run` the bound principal carrying its *effective* `scopes` (for
78
+ * example the token scopes still granted by live membership permissions).
79
+ * Dispatch then authorizes with those scopes, intersected with the token's:
80
+ * a binder can only narrow authority, and changing the principal's `id` or
81
+ * `tenantId` is a denial. Calling `run()` with no argument keeps the token
82
+ * scopes.
83
+ */
84
+ export type McpPrincipalBinder = <T>(principal: McpAppPrincipal & {
85
+ id: string;
86
+ }, run: (bound?: McpAppPrincipal & {
87
+ id: string;
88
+ }) => Promise<T>) => Promise<T>;
30
89
  /** Options shared by both route mounts. */
31
90
  export interface MountMcpRouteOptions {
91
+ /**
92
+ * Bind a bearer-authenticated principal around dispatch (see
93
+ * {@link McpPrincipalBinder}). The `smrtOptions` database thunk, task
94
+ * handling and tool execution all run inside the binding, and the response
95
+ * is fully materialized before it returns. A binder that throws before
96
+ * running dispatch, or returns without running it, yields HTTP 403 with the
97
+ * safe `mcp_tool_access_denied` JSON-RPC error. Scopes the binder hands
98
+ * back become the effective authority for the tool policy, so live
99
+ * revocation applies even without a database-enforced policy. Used only when `auth`
100
+ * authenticated the request; the session-locals path is unchanged.
101
+ */
102
+ bindPrincipal?: McpPrincipalBinder;
103
+ /**
104
+ * Refuse a modern-endpoint request whose `Origin` header is present but is
105
+ * neither the request URL's own origin nor in `trustedOrigins` (and, when
106
+ * `Origin` is absent, one whose `Sec-Fetch-Site` is `cross-site` or
107
+ * `same-site`). The check runs before bearer authentication, principal
108
+ * resolution and any task or tool dispatch, and answers 403 with the safe
109
+ * `mcp_origin_denied` JSON-RPC error. Requests without browser origin
110
+ * signals (server-side MCP clients, the `smrt-app-cli` stdio bridge) are
111
+ * unaffected. Off unless set for `mountMcpRoute`; on by default for
112
+ * `mountMcpAppRoute`. Ignored by the deprecated REST-shaped mounts.
113
+ */
114
+ checkOrigin?: boolean;
115
+ /**
116
+ * Additional exact origins (`scheme://host[:port]`) accepted by the origin
117
+ * check, e.g. a browser-hosted MCP client, or the public origin when a
118
+ * proxy makes `event.url` differ from what browsers send. `null`, wildcards,
119
+ * paths and credentials are rejected at mount time.
120
+ */
121
+ trustedOrigins?: readonly string[];
122
+ /**
123
+ * Optional bearer authentication for the modern `mountMcpRoute` endpoint.
124
+ * When the source yields an adapter, every request must carry a valid
125
+ * bearer token: a failed check returns the adapter's challenge response
126
+ * before any dispatch, and the adapter's mapped principal replaces the
127
+ * session principal (`resolvePrincipal` is not consulted). When it yields
128
+ * `null`, the route resolves its principal from the request as usual.
129
+ * Ignored by the deprecated REST-shaped mounts.
130
+ */
131
+ auth?: McpRouteResourceAuthSource;
32
132
  /** Optional extension discovery projected from the request-authorized tool catalog. */
33
133
  extensions?: McpProtocolRequestOptions['extensions'];
34
134
  /**
@@ -54,6 +154,54 @@ export interface MountMcpRouteOptions {
54
154
  * route holds neither MCP sessions nor request principal state between nodes.
55
155
  */
56
156
  export declare function mountMcpRoute(server: McpAppServer, options?: MountMcpRouteOptions): McpSvelteKitHandler;
157
+ /** Options for {@link mountMcpAppRoute}. */
158
+ export interface MountMcpAppRouteOptions extends CreateDefaultMcpAppServerOptions, Pick<MountMcpRouteOptions, 'auth' | 'bindPrincipal' | 'extensions' | 'checkOrigin' | 'trustedOrigins'> {
159
+ /**
160
+ * Resolve the request principal when no bearer adapter is active. Defaults
161
+ * to {@link principalFromSessionLocals}.
162
+ */
163
+ resolvePrincipal?: McpPrincipalResolver;
164
+ }
165
+ /** A mounted app route; `server` is the policy core it serves. */
166
+ export type McpAppSvelteKitHandler = McpSvelteKitHandler & {
167
+ readonly server: McpAppServer;
168
+ };
169
+ /**
170
+ * One-call application MCP endpoint: the app's declared `models`, the default
171
+ * principal scope policy (see `createDefaultMcpAppServer`), principals from
172
+ * the SvelteKit session locals, and optional bearer authentication, mounted
173
+ * as the stateless {@link mountMcpRoute} `POST` endpoint. The origin check
174
+ * (`checkOrigin`) is on by default because the default principal is an
175
+ * ambient session cookie; set `trustedOrigins` for extra browser origins or
176
+ * `checkOrigin: false` to opt out.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * // src/routes/api/mcp/+server.ts
181
+ * import { mountMcpAppRoute } from '@happyvertical/smrt-app-mcp/sveltekit';
182
+ * import { Item } from '$lib/objects/Item';
183
+ * import { getDatabaseConfig } from '$lib/server/db';
184
+ *
185
+ * export const POST = mountMcpAppRoute({
186
+ * models: [Item],
187
+ * requiredScopes: ['items.read'],
188
+ * smrtOptions: () => ({ db: getDatabaseConfig() }),
189
+ * });
190
+ * ```
191
+ */
192
+ export declare function mountMcpAppRoute(options: MountMcpAppRouteOptions): McpAppSvelteKitHandler;
193
+ /**
194
+ * Mount the RFC 9728 protected-resource metadata document as a SvelteKit
195
+ * `GET` handler, at the exact `metadataUrl` path the bearer challenge
196
+ * advertises (for `/api/mcp`:
197
+ * `src/routes/.well-known/oauth-protected-resource/api/mcp/+server.ts`).
198
+ *
199
+ * Returns 404 when the source yields no adapter (the `local` profile) or when
200
+ * the request path is not the advertised metadata path. This handler does
201
+ * not implement an OAuth authorization server; the metadata names the
202
+ * operator-owned issuer.
203
+ */
204
+ export declare function mountMcpProtectedResourceMetadataRoute(auth: McpRouteResourceAuthSource): McpSvelteKitHandler;
57
205
  /**
58
206
  * Mount `server.listTools` as a `GET` handler. Returns the tool list shape
59
207
  * `{ tools }` for compatibility with the stock MCP bridge.
@@ -70,6 +218,7 @@ export declare function mountMcpToolsRoute(server: McpAppServer, options?: Mount
70
218
  * this compatibility alias while migrating without a coordinated cutover.
71
219
  */
72
220
  export declare function mountMcpCallRoute(server: McpAppServer, options?: MountMcpRouteOptions): McpSvelteKitHandler;
221
+ export type { CreateDefaultMcpAppServerOptions, McpAppModel, } from './defaults.js';
73
222
  export { McpAccessError } from './errors.js';
74
223
  export type { McpAppPrincipal, McpAppServer } from './server.js';
75
224
  //# sourceMappingURL=sveltekit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sveltekit.d.ts","sourceRoot":"","sources":["../src/sveltekit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAiB,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhF,oEAAoE;AACpE,KAAK,qBAAqB,GAAG;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;CACV,CAAC;AAEF,6EAA6E;AAC7E,MAAM,MAAM,mBAAmB,GAAG,CAChC,KAAK,EAAE,qBAAqB,KACzB,OAAO,CAAC,QAAQ,CAAC,CAAC;AAQvB,8EAA8E;AAC9E,MAAM,MAAM,oBAAoB,GAAG,CACjC,KAAK,EAAE,qBAAqB,KACzB,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC;AAExC,6EAA6E;AAC7E,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAwCnD,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,uFAAuF;IACvF,UAAU,CAAC,EAAE,yBAAyB,CAAC,YAAY,CAAC,CAAC;IACrD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC;;OAEG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAAC;CAClE;AAkBD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA8BrB;AA6OD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CAcrB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA0BrB;AAyBD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"sveltekit.d.ts","sourceRoot":"","sources":["../src/sveltekit.ts"],"names":[],"mappings":"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"}
package/dist/sveltekit.js CHANGED
@@ -1,4 +1,4 @@
1
- import { f as McpAccessError, r as createMcpProtocolServerForRequest, t as MCP_TASKS_EXTENSION } from "./chunks/protocol-Ce0U_XSp.js";
1
+ import { C as McpAccessError, S as MCP_TOOL_ACCESS_DENIED_CODE, a as createDefaultMcpAppServer, r as createMcpProtocolServerForRequest, t as MCP_TASKS_EXTENSION, x as MCP_ORIGIN_DENIED_CODE } from "./chunks/protocol-BlbEg3jn.js";
2
2
  import { classifyInboundRequest, createMcpHandler, isJsonContentType } from "@modelcontextprotocol/server";
3
3
  //#region src/sveltekit.ts
4
4
  var defaultResolvePrincipal = (event) => event.locals?.user ?? null;
@@ -17,6 +17,87 @@ function listToolsInput(resolved) {
17
17
  if (!resolved.principal && resolved.legacyAuthenticated) return { authenticated: true };
18
18
  return { principal: resolved.principal };
19
19
  }
20
+ function currentResourceAuth(source) {
21
+ return (typeof source === "function" ? source() : source) ?? null;
22
+ }
23
+ function canonicalOrigin(value) {
24
+ if (value === "null") return void 0;
25
+ let url;
26
+ try {
27
+ url = new URL(value);
28
+ } catch {
29
+ return;
30
+ }
31
+ if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
32
+ if (url.username || url.password || url.search || url.hash) return void 0;
33
+ if (url.pathname !== "/") return void 0;
34
+ return url.origin;
35
+ }
36
+ function normalizeTrustedOrigins(values) {
37
+ if (!Array.isArray(values)) throw new TypeError("MCP trustedOrigins must be an array of origins.");
38
+ const origins = /* @__PURE__ */ new Set();
39
+ for (const value of values) {
40
+ const origin = typeof value === "string" ? canonicalOrigin(value) : void 0;
41
+ if (!origin) throw new TypeError("Invalid MCP trusted origin.");
42
+ origins.add(origin);
43
+ }
44
+ return origins;
45
+ }
46
+ function originPermitted(event, trusted) {
47
+ const header = event.request.headers.get("origin");
48
+ if (header !== null) {
49
+ const origin = canonicalOrigin(header.trim());
50
+ return origin !== void 0 && (origin === event.url.origin || trusted.has(origin));
51
+ }
52
+ const site = event.request.headers.get("sec-fetch-site")?.trim().toLowerCase();
53
+ return site !== "cross-site" && site !== "same-site";
54
+ }
55
+ function originDeniedResponse() {
56
+ return new Response(JSON.stringify({
57
+ jsonrpc: "2.0",
58
+ id: null,
59
+ error: {
60
+ code: -32600,
61
+ message: "MCP request origin is not permitted.",
62
+ data: {
63
+ code: MCP_ORIGIN_DENIED_CODE,
64
+ retryable: false
65
+ }
66
+ }
67
+ }), {
68
+ status: 403,
69
+ headers: {
70
+ "content-type": "application/json",
71
+ "cache-control": "no-store"
72
+ }
73
+ });
74
+ }
75
+ function principalFromSessionLocals(event) {
76
+ const locals = event.locals;
77
+ if (!locals || typeof locals !== "object") return null;
78
+ const user = locals.user;
79
+ const tenantId = locals.tenantId;
80
+ const permissions = locals.permissions;
81
+ if (!user || typeof user !== "object") return null;
82
+ if (typeof user.id !== "string" || user.id.length === 0) return null;
83
+ if (typeof tenantId !== "string" || tenantId.length === 0) return null;
84
+ if (!Array.isArray(permissions) || !permissions.every((value) => typeof value === "string")) return null;
85
+ return {
86
+ id: user.id,
87
+ tenantId,
88
+ kind: "human",
89
+ scopes: [...permissions].sort()
90
+ };
91
+ }
92
+ function effectiveBoundPrincipal(authenticated, bound) {
93
+ if (bound === void 0) return authenticated;
94
+ if (!bound || typeof bound !== "object" || bound.id !== authenticated.id || (bound.tenantId ?? null) !== (authenticated.tenantId ?? null) || !Array.isArray(bound.scopes) || !bound.scopes.every((scope) => typeof scope === "string")) return;
95
+ const granted = new Set(bound.scopes);
96
+ return {
97
+ ...authenticated,
98
+ scopes: (authenticated.scopes ?? []).filter((scope) => granted.has(scope))
99
+ };
100
+ }
20
101
  function protocolServerForRequest(server, resolved) {
21
102
  if (!resolved.legacyAuthenticated || resolved.principal) return server;
22
103
  return {
@@ -27,8 +108,35 @@ function protocolServerForRequest(server, resolved) {
27
108
  };
28
109
  }
29
110
  function mountMcpRoute(server, options = {}) {
111
+ const trustedOrigins = options.checkOrigin ? normalizeTrustedOrigins(options.trustedOrigins ?? []) : void 0;
30
112
  return async (event) => {
31
- const resolved = resolveRequestPrincipal(event, options);
113
+ if (trustedOrigins && !originPermitted(event, trustedOrigins)) return originDeniedResponse();
114
+ const auth = currentResourceAuth(options.auth);
115
+ if (!auth) return dispatch(event, resolveRequestPrincipal(event, options));
116
+ const checked = await auth.authenticate(event.request);
117
+ if (!checked.ok) return checked.response;
118
+ if (!options.bindPrincipal) return dispatch(event, { principal: checked.principal });
119
+ let entered = false;
120
+ let response;
121
+ try {
122
+ response = await options.bindPrincipal(checked.principal, async (bound) => {
123
+ entered = true;
124
+ const principal = effectiveBoundPrincipal(checked.principal, bound);
125
+ if (!principal) return principalUnboundResponse();
126
+ const dispatched = await dispatch(event, { principal });
127
+ return new Response(await dispatched.arrayBuffer(), {
128
+ status: dispatched.status,
129
+ statusText: dispatched.statusText,
130
+ headers: dispatched.headers
131
+ });
132
+ });
133
+ } catch (error) {
134
+ if (entered) throw error;
135
+ return principalUnboundResponse();
136
+ }
137
+ return entered ? response : principalUnboundResponse();
138
+ };
139
+ async function dispatch(event, resolved) {
32
140
  const taskResponse = await maybeHandleTaskRequest(server, resolved.principal, event.request);
33
141
  if (taskResponse) return taskResponse;
34
142
  return createMcpHandler(() => createMcpProtocolServerForRequest(protocolServerForRequest(server, resolved), {
@@ -38,6 +146,52 @@ function mountMcpRoute(server, options = {}) {
38
146
  legacy: "reject",
39
147
  maxSubscriptions: 0
40
148
  }).fetch(event.request);
149
+ }
150
+ }
151
+ function principalUnboundResponse() {
152
+ return new Response(JSON.stringify({
153
+ jsonrpc: "2.0",
154
+ id: null,
155
+ error: {
156
+ code: -32600,
157
+ message: "MCP tool access is not permitted.",
158
+ data: {
159
+ code: MCP_TOOL_ACCESS_DENIED_CODE,
160
+ retryable: false
161
+ }
162
+ }
163
+ }), {
164
+ status: 403,
165
+ headers: {
166
+ "content-type": "application/json",
167
+ "cache-control": "no-store"
168
+ }
169
+ });
170
+ }
171
+ function mountMcpAppRoute(options) {
172
+ const { auth, bindPrincipal, extensions, resolvePrincipal, checkOrigin, trustedOrigins, ...serverOptions } = options;
173
+ const server = createDefaultMcpAppServer(serverOptions);
174
+ const handler = mountMcpRoute(server, {
175
+ auth,
176
+ bindPrincipal,
177
+ extensions,
178
+ checkOrigin: checkOrigin ?? true,
179
+ trustedOrigins,
180
+ resolvePrincipal: resolvePrincipal ?? principalFromSessionLocals
181
+ });
182
+ return Object.defineProperty(handler, "server", {
183
+ value: server,
184
+ enumerable: true
185
+ });
186
+ }
187
+ function mountMcpProtectedResourceMetadataRoute(auth) {
188
+ return async (event) => {
189
+ const current = currentResourceAuth(auth);
190
+ if (!current || event.url.pathname !== new URL(current.metadataUrl).pathname) return new Response(null, {
191
+ status: 404,
192
+ headers: { "Cache-Control": "no-store" }
193
+ });
194
+ return current.metadataResponse();
41
195
  };
42
196
  }
43
197
  async function maybeHandleTaskRequest(server, principal, request) {
@@ -215,6 +369,6 @@ function jsonResponse(body, status = 200) {
215
369
  });
216
370
  }
217
371
  //#endregion
218
- export { McpAccessError, mountMcpCallRoute, mountMcpRoute, mountMcpToolsRoute };
372
+ export { McpAccessError, mountMcpAppRoute, mountMcpCallRoute, mountMcpProtectedResourceMetadataRoute, mountMcpRoute, mountMcpToolsRoute, principalFromSessionLocals };
219
373
 
220
374
  //# sourceMappingURL=sveltekit.js.map