@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.
- package/AGENTS.md +12 -0
- package/README.md +135 -0
- package/dist/auth.d.ts +39 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +34 -1
- package/dist/auth.js.map +1 -1
- package/dist/chunks/protocol-BlbEg3jn.js +7647 -0
- package/dist/chunks/protocol-BlbEg3jn.js.map +1 -0
- package/dist/defaults.d.ts +87 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -7351
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +5 -5
- package/dist/sveltekit.d.ts +150 -1
- package/dist/sveltekit.d.ts.map +1 -1
- package/dist/sveltekit.js +157 -3
- package/dist/sveltekit.js.map +1 -1
- package/dist/tools.d.ts +18 -0
- package/dist/tools.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/chunks/protocol-Ce0U_XSp.js +0 -184
- package/dist/chunks/protocol-Ce0U_XSp.js.map +0 -1
package/dist/manifest.json
CHANGED
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
|
}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -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.
|
|
6
|
+
"packageVersion": "0.53.4",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
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
|
}
|
package/dist/sveltekit.d.ts
CHANGED
|
@@ -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
|
package/dist/sveltekit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sveltekit.d.ts","sourceRoot":"","sources":["../src/sveltekit.ts"],"names":[],"mappings":"AAAA
|
|
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 {
|
|
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
|
-
|
|
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
|