@questpie/mcp 3.16.0 → 3.17.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.
@@ -1,168 +0,0 @@
1
- import { t as createMcpServer } from "./create-server-DIvtVlma.mjs";
2
- import { t as mcpPlugin } from "./plugin-BJ6gELRj.mjs";
3
- import { route } from "questpie";
4
- import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
5
-
6
- //#region src/server/mcp-http.ts
7
- /**
8
- * Shared MCP Streamable-HTTP handler.
9
- *
10
- * `route()` is single-method, so the MCP endpoint's four verbs (POST = JSON-RPC
11
- * messages, GET = SSE stream, DELETE = session end, OPTIONS = CORS preflight)
12
- * are registered as separate method-suffixed route files under `routes/`
13
- * (`mcp.ts` = POST, `mcp.get.ts`, `mcp.delete.ts`, `mcp.options.ts`) per the
14
- * codegen file convention — NOT method chaining and NOT a hand-written
15
- * `module.ts`. All four share THIS handler, which dispatches on
16
- * `request.method` internally because the transport needs one object for every
17
- * verb on the path.
18
- */
19
- const mcpMeta = {
20
- title: "MCP endpoint",
21
- description: "Model Context Protocol endpoint for QUESTPIE."
22
- };
23
- function appFromRouteContext(ctx) {
24
- return ctx.app;
25
- }
26
- function executionContextFromRouteContext(ctx) {
27
- const routeCtx = { ...ctx };
28
- delete routeCtx.app;
29
- delete routeCtx.request;
30
- return routeCtx;
31
- }
32
- function withCors(response, request) {
33
- const headers = new Headers(response.headers);
34
- const origin = request.headers.get("origin");
35
- if (origin) {
36
- headers.set("Access-Control-Allow-Origin", origin);
37
- headers.set("Vary", "Origin");
38
- }
39
- headers.set("Access-Control-Allow-Methods", "POST, GET, DELETE, OPTIONS");
40
- headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key, Mcp-Session-Id, Last-Event-ID");
41
- return new Response(response.body, {
42
- status: response.status,
43
- statusText: response.statusText,
44
- headers
45
- });
46
- }
47
- /**
48
- * Build the `WWW-Authenticate` challenge value for an unauthenticated HTTP MCP
49
- * request. `resource_metadata` points at this app's Protected Resource metadata
50
- * document (RFC 9728), served beside the MCP route by the core
51
- * `oauth-protected-resource` route (MO4). An MCP client reads it to discover
52
- * the authorization server and start the OAuth 2.1 flow.
53
- *
54
- * The public origin comes from `app.config.app.url`, while the mount path comes
55
- * from the actual MCP request. This keeps the canonical external host used for
56
- * token audience binding, and also preserves adapter base paths such as `/api`.
57
- */
58
- function protectedResourceChallenge(appUrl, requestUrl) {
59
- const request = new URL(requestUrl);
60
- request.pathname = request.pathname.replace(/\/+$/, "");
61
- const metadataPath = new URL(".well-known/oauth-protected-resource", request).pathname;
62
- const metadataUrl = new URL(appUrl);
63
- metadataUrl.pathname = metadataPath;
64
- metadataUrl.search = "";
65
- metadataUrl.hash = "";
66
- return `Bearer resource_metadata="${metadataUrl.href}"`;
67
- }
68
- /**
69
- * A verified principal is required to reach MCP tool execution over HTTP. The
70
- * request context resolves one for a cookie/bearer session (`kind: "user"`) or a
71
- * valid OAuth access token (`kind: "oauth"`); an unauthenticated request has
72
- * none. Read it structurally — the handler-args type does not surface it.
73
- */
74
- function hasVerifiedPrincipal(ctx) {
75
- return Boolean(ctx.principal);
76
- }
77
- async function mcpHandler(ctx) {
78
- const { request } = ctx;
79
- const app = appFromRouteContext(ctx);
80
- if (request.method === "OPTIONS") return withCors(new Response(null, { status: 204 }), request);
81
- if (!hasVerifiedPrincipal(ctx)) return withCors(new Response(null, {
82
- status: 401,
83
- headers: { "WWW-Authenticate": protectedResourceChallenge(app.config.app.url, request.url) }
84
- }), request);
85
- const config = app.state?.config?.mcp ?? {};
86
- const server = await createMcpServer(app, {
87
- transport: "http",
88
- accessMode: "user",
89
- request,
90
- ctx: executionContextFromRouteContext(ctx)
91
- });
92
- const transport = new WebStandardStreamableHTTPServerTransport({
93
- sessionIdGenerator: void 0,
94
- allowedOrigins: config.http?.allowedOrigins,
95
- allowedHosts: config.http?.allowedHosts,
96
- enableJsonResponse: config.http?.enableJsonResponse ?? true
97
- });
98
- await server.connect(transport);
99
- return withCors(await transport.handleRequest(request), request);
100
- }
101
-
102
- //#endregion
103
- //#region src/server/modules/mcp/routes/mcp.ts
104
- var mcp_default$1 = route().post().raw().meta(mcpMeta).handler(mcpHandler);
105
-
106
- //#endregion
107
- //#region src/server/modules/mcp/routes/mcp.delete.ts
108
- var mcp_delete_default = route().delete().raw().meta(mcpMeta).handler(mcpHandler);
109
-
110
- //#endregion
111
- //#region src/server/modules/mcp/routes/mcp.get.ts
112
- var mcp_get_default = route().get().raw().meta(mcpMeta).handler(mcpHandler);
113
-
114
- //#endregion
115
- //#region src/server/modules/mcp/routes/mcp.options.ts
116
- var mcp_options_default = route().options().raw().meta(mcpMeta).handler(mcpHandler);
117
-
118
- //#endregion
119
- //#region src/server/modules/mcp/plugin.ts
120
- /**
121
- * MCP module plugin — re-exports the MCP codegen plugin so that module
122
- * codegen discovers it and embeds it in the generated module definition.
123
- * This allows `extractPluginsFromModules` to pick it up automatically at
124
- * root-app codegen time (so consuming apps get the `mcp-tools` category,
125
- * `config/mcp.ts` discover, and scaffolds).
126
- */
127
- var plugin_default = mcpPlugin();
128
-
129
- //#endregion
130
- //#region src/server/modules/mcp/.generated/module.ts
131
- const _module = {
132
- name: "questpie-mcp",
133
- routes: {
134
- mcp: mcp_default$1,
135
- "mcp:DELETE": mcp_delete_default,
136
- "mcp:GET": mcp_get_default,
137
- "mcp:OPTIONS": mcp_options_default
138
- },
139
- collections: {},
140
- globals: {},
141
- jobs: {},
142
- messages: {},
143
- services: {},
144
- emails: {},
145
- migrations: [],
146
- seeds: [],
147
- fieldTypes: {},
148
- mcpTools: {},
149
- plugin: plugin_default
150
- };
151
- var module_default = _module;
152
-
153
- //#endregion
154
- //#region src/server/modules/mcp/index.ts
155
- /**
156
- * MCP Module
157
- *
158
- * Backend module for the QUESTPIE Model Context Protocol endpoint.
159
- *
160
- * Exports:
161
- * - `mcpModule` — static module definition (generated by codegen from file convention)
162
- * - `McpModule` — type of the static module
163
- */
164
- const mcpModule = module_default;
165
- var mcp_default = mcpModule;
166
-
167
- //#endregion
168
- export { mcp_default as n, mcpModule as t };
@@ -1,154 +0,0 @@
1
- import { AppContext, RequestContext, createContextFactory } from "questpie";
2
- import { z } from "zod";
3
- import { CallToolResult, ToolAnnotations } from "@modelcontextprotocol/sdk/types.js";
4
- import * as _modelcontextprotocol_sdk_server_mcp0 from "@modelcontextprotocol/sdk/server/mcp";
5
-
6
- //#region src/server/types.d.ts
7
- type McpTransportKind = "http" | "stdio";
8
- type McpAccessMode = "user" | "system";
9
- interface McpAccessRuleContext {
10
- transport: McpTransportKind;
11
- accessMode: McpAccessMode;
12
- session?: RequestContext["session"];
13
- /**
14
- * The consented OAuth scopes carried by the caller, when the request was
15
- * authenticated by an OAuth access token (`ctx.principal.kind === "oauth"`).
16
- * `undefined` for the `user` (first-party) and `system` (stdio/trusted)
17
- * principals, which carry no scopes. This is the model input the scope gate
18
- * (`scopeGateAllows`) reads when deciding whether a tool is visible/callable.
19
- */
20
- scopes?: string[];
21
- ctx: AppContext & Partial<RequestContext>;
22
- }
23
- type McpAccessRule = boolean | ((ctx: McpAccessRuleContext) => boolean | Promise<boolean>);
24
- /**
25
- * OAuth scope requirement declaration. A single scope string, a list (all
26
- * required — AND), or `false` to explicitly require no scope (public even to
27
- * scoped OAuth callers). `undefined` means "fall back to the default mapping".
28
- */
29
- type McpRequiredScopes = string | string[] | false;
30
- type McpEntityPolicy = boolean | {
31
- expose?: boolean;
32
- read?: boolean | McpAccessRule;
33
- write?: boolean | McpAccessRule;
34
- delete?: boolean | McpAccessRule;
35
- operations?: Record<string, boolean | McpAccessRule>;
36
- /**
37
- * Scopes an OAuth caller must hold to reach this entity. Declarable at
38
- * the entity level (applies to every operation) and/or per operation via
39
- * {@link McpEntityPolicy.operationScopes}. When omitted, the default
40
- * operation→scope mapping is derived from the operation kind (e.g.
41
- * `collections:<name>:read`). Resolved by `requiredScopesForOperation`
42
- * and enforced by the scope gate (`scopeGateAllows`) at both
43
- * `tools/list` and `tools/call`.
44
- */
45
- requiredScopes?: McpRequiredScopes;
46
- /**
47
- * Per-operation scope requirements, keyed by operation name
48
- * (`list`/`get`/`create`/`update`/`delete`/`invoke`/…). Overrides both
49
- * {@link McpEntityPolicy.requiredScopes} and the default mapping for the
50
- * named operation.
51
- */
52
- operationScopes?: Record<string, McpRequiredScopes>;
53
- fields?: {
54
- include?: string[];
55
- exclude?: string[];
56
- };
57
- description?: string;
58
- };
59
- interface McpCrudDefaults {
60
- collections?: {
61
- read?: boolean | McpAccessRule;
62
- write?: boolean | McpAccessRule;
63
- delete?: boolean | McpAccessRule;
64
- };
65
- globals?: {
66
- read?: boolean | McpAccessRule;
67
- write?: boolean | McpAccessRule;
68
- };
69
- }
70
- interface McpCrudConfig {
71
- defaults?: McpCrudDefaults;
72
- collections?: Record<string, McpEntityPolicy>;
73
- globals?: Record<string, McpEntityPolicy>;
74
- maxLimit?: number;
75
- }
76
- interface McpRoutesConfig {
77
- exposeAnnotated?: boolean;
78
- routes?: Record<string, McpEntityPolicy>;
79
- }
80
- interface McpResourcesConfig {
81
- schemas?: boolean;
82
- routes?: boolean;
83
- }
84
- interface McpTransportConfig {
85
- accessMode?: McpAccessMode;
86
- }
87
- interface McpHttpConfig extends McpTransportConfig {
88
- allowedOrigins?: string[];
89
- allowedHosts?: string[];
90
- enableJsonResponse?: boolean;
91
- }
92
- interface McpStdioConfig extends McpTransportConfig {}
93
- interface McpConfig {
94
- name?: string;
95
- version?: string;
96
- crud?: McpCrudConfig;
97
- routes?: McpRoutesConfig;
98
- resources?: McpResourcesConfig;
99
- http?: McpHttpConfig;
100
- stdio?: McpStdioConfig;
101
- }
102
- interface McpExecutionOptions {
103
- transport?: McpTransportKind;
104
- accessMode?: McpAccessMode;
105
- ctx?: AppContext & Partial<RequestContext>;
106
- request?: Request;
107
- config?: McpConfig;
108
- }
109
- interface McpToolHandlerArgs<TInput = unknown> {
110
- input: TInput;
111
- ctx: AppContext & Partial<RequestContext>;
112
- transport: McpTransportKind;
113
- accessMode: McpAccessMode;
114
- request?: Request;
115
- }
116
- interface McpToolConfig<TInputSchema extends z.ZodTypeAny = z.ZodTypeAny, TOutputSchema extends z.ZodTypeAny = z.ZodTypeAny> {
117
- title?: string;
118
- description?: string;
119
- inputSchema?: TInputSchema;
120
- outputSchema?: TOutputSchema;
121
- annotations?: ToolAnnotations;
122
- access?: McpAccessRule;
123
- /**
124
- * Scopes an OAuth caller must hold to reach this custom tool (all required —
125
- * AND). Custom tools have no default mapping (there is no resource/operation
126
- * to derive one from), so an omitted value requires no scope. Enforced by the
127
- * scope gate (`scopeGateAllows`) at both `tools/list` (hidden) and
128
- * `tools/call` (denied); `system`/`user` callers carry no scopes and skip it.
129
- */
130
- scopes?: McpRequiredScopes;
131
- _meta?: Record<string, unknown>;
132
- }
133
- interface McpToolDefinition<TInputSchema extends z.ZodTypeAny = z.ZodTypeAny, TOutputSchema extends z.ZodTypeAny = z.ZodTypeAny> {
134
- readonly __brand: "mcpTool";
135
- readonly name: string;
136
- readonly config: McpToolConfig<TInputSchema, TOutputSchema>;
137
- readonly handler: (args: McpToolHandlerArgs<z.infer<TInputSchema>>) => CallToolResult | Promise<CallToolResult>;
138
- }
139
- declare module "questpie" {
140
- interface AppStateConfig {
141
- mcp?: McpConfig;
142
- }
143
- interface ModuleDefinition {
144
- mcpTools?: Record<string, McpToolDefinition>;
145
- }
146
- }
147
- //#endregion
148
- //#region src/server/runtime.d.ts
149
- type QuestpieApp = Parameters<typeof createContextFactory>[0];
150
- //#endregion
151
- //#region src/server/stdio.d.ts
152
- declare function startStdioServer(app: QuestpieApp, options?: Omit<McpExecutionOptions, "transport">): Promise<_modelcontextprotocol_sdk_server_mcp0.McpServer>;
153
- //#endregion
154
- export { McpToolDefinition as _, McpAccessRuleContext as a, McpCrudDefaults as c, McpHttpConfig as d, McpRequiredScopes as f, McpToolConfig as g, McpStdioConfig as h, McpAccessRule as i, McpEntityPolicy as l, McpRoutesConfig as m, QuestpieApp as n, McpConfig as o, McpResourcesConfig as p, McpAccessMode as r, McpCrudConfig as s, startStdioServer as t, McpExecutionOptions as u, McpToolHandlerArgs as v, McpTransportKind as y };