@questpie/mcp 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,58 @@
1
+ import * as questpie0 from "questpie";
2
+ import { RouteDefinition, RouteParamsFromKey } from "questpie/types";
3
+
4
+ //#region src/server/modules/mcp/routes/mcp.d.ts
5
+ declare const _default$4: questpie0.RawRouteDefinition<questpie0.JsonRouteParams>;
6
+ //#endregion
7
+ //#region src/server/modules/mcp/routes/mcp.delete.d.ts
8
+ declare const _default$3: questpie0.RawRouteDefinition<questpie0.JsonRouteParams>;
9
+ //#endregion
10
+ //#region src/server/modules/mcp/routes/mcp.get.d.ts
11
+ declare const _default$2: questpie0.RawRouteDefinition<questpie0.JsonRouteParams>;
12
+ //#endregion
13
+ //#region src/server/modules/mcp/routes/mcp.options.d.ts
14
+ declare const _default$1: questpie0.RawRouteDefinition<questpie0.JsonRouteParams>;
15
+ //#endregion
16
+ //#region src/server/modules/mcp/plugin.d.ts
17
+ declare const _default: questpie0.CodegenPlugin;
18
+ //#endregion
19
+ //#region src/server/modules/mcp/.generated/module.d.ts
20
+ type McpCollections = Record<never, never>;
21
+ type McpGlobals = Record<never, never>;
22
+ type McpJobs = Record<never, never>;
23
+ type McpRoutes = {
24
+ mcp: typeof _default$4 extends {
25
+ __brand: "route";
26
+ } ? RouteDefinition<unknown, unknown, RouteParamsFromKey<"mcp">> : typeof _default$4;
27
+ "mcp:DELETE": typeof _default$3 extends {
28
+ __brand: "route";
29
+ } ? RouteDefinition<unknown, unknown, RouteParamsFromKey<"mcp:DELETE">> : typeof _default$3;
30
+ "mcp:GET": typeof _default$2 extends {
31
+ __brand: "route";
32
+ } ? RouteDefinition<unknown, unknown, RouteParamsFromKey<"mcp:GET">> : typeof _default$2;
33
+ "mcp:OPTIONS": typeof _default$1 extends {
34
+ __brand: "route";
35
+ } ? RouteDefinition<unknown, unknown, RouteParamsFromKey<"mcp:OPTIONS">> : typeof _default$1;
36
+ };
37
+ type McpFieldTypes = Record<never, never>;
38
+ type McpMcpTools = Record<never, never>;
39
+ type McpModule = {
40
+ name: "questpie-mcp";
41
+ routes: McpRoutes;
42
+ collections: McpCollections;
43
+ globals: McpGlobals;
44
+ jobs: McpJobs;
45
+ fieldTypes: McpFieldTypes;
46
+ mcpTools: McpMcpTools;
47
+ messages: Record<never, never>;
48
+ services: Record<never, never>;
49
+ emails: Record<never, never>;
50
+ migrations: readonly unknown[];
51
+ seeds: readonly unknown[];
52
+ plugin: typeof _default;
53
+ };
54
+ //#endregion
55
+ //#region src/server/modules/mcp/index.d.ts
56
+ declare const mcpModule: McpModule;
57
+ //#endregion
58
+ export { McpModule as n, mcpModule as t };
@@ -0,0 +1,122 @@
1
+ import { t as mcpModule } from "./index-Cxta5KOn.mjs";
2
+ import { _ as McpToolDefinition, a as McpAccessRuleContext, c as McpCrudDefaults, d as McpHttpConfig, f as McpRequiredScopes, g as McpToolConfig, h as McpStdioConfig, i as McpAccessRule, l as McpEntityPolicy, m as McpRoutesConfig, n as QuestpieApp, o as McpConfig, p as McpResourcesConfig, r as McpAccessMode, s as McpCrudConfig, t as startStdioServer, u as McpExecutionOptions, v as McpToolHandlerArgs, y as McpTransportKind } from "./stdio-t_9rKayH.mjs";
3
+ import { t as mcpPlugin } from "./plugin-CMR-wkeP.mjs";
4
+ import { AppContext, RequestContext, ScopeOperationKind, defaultOperationScope } from "questpie";
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { z } from "zod";
7
+
8
+ //#region src/server/create-server.d.ts
9
+ declare function createMcpServer(app: QuestpieApp, options?: McpExecutionOptions): Promise<McpServer>;
10
+ //#endregion
11
+ //#region src/server/config.d.ts
12
+ declare function mcpConfig<TConfig extends McpConfig>(config: TConfig): TConfig;
13
+ //#endregion
14
+ //#region src/server/mcp-tool.d.ts
15
+ declare class McpToolBuilder<TInputSchema extends z.ZodTypeAny, TOutputSchema extends z.ZodTypeAny> {
16
+ private readonly name;
17
+ private readonly config;
18
+ constructor(name: string, config: McpToolConfig<TInputSchema, TOutputSchema>);
19
+ handler(handler: (args: McpToolHandlerArgs<z.infer<TInputSchema>>) => ReturnType<McpToolDefinition<TInputSchema, TOutputSchema>["handler"]>): McpToolDefinition<TInputSchema, TOutputSchema>;
20
+ }
21
+ /**
22
+ * Define a custom MCP tool, contributed by a module the same way collections and
23
+ * routes are (via `ModuleDefinition.mcpTools`). `mcpTool(name, config).handler(fn)`
24
+ * returns a frozen, branded {@link McpToolDefinition}; the CRUD/route tools the
25
+ * framework auto-generates are the same shape.
26
+ *
27
+ * `config` mirrors the MCP tool contract: `inputSchema`/`outputSchema` (Zod),
28
+ * `title`/`description`/`annotations` for discovery, plus the two QUESTPIE
29
+ * authorization hooks that compose exactly like the built-in tools:
30
+ * - `access` — an {@link McpAccessRule} run against the caller's transport /
31
+ * accessMode / session (and, for an OAuth caller, its scopes). Same RBAC-style
32
+ * gate the CRUD tools use.
33
+ * - `scopes` — the OAuth scopes an `oauth` caller must hold ({@link McpToolConfig.scopes}).
34
+ * Custom tools have no default scope mapping (unlike CRUD, there is no
35
+ * resource/operation to derive one from), so an omitted value requires no
36
+ * scope. The shipped scope gate ({@link scopeGateAllows}) enforces this at both
37
+ * `tools/list` (hidden) and `tools/call` (denied); `system`/`user` callers
38
+ * carry no scopes and skip it, so the effective bound is always `scopes ∩ RBAC`.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * export const ping = mcpTool("ops.ping", {
43
+ * description: "Health probe",
44
+ * inputSchema: z.object({}),
45
+ * scopes: "routes:ops/ping:invoke", // only OAuth callers holding this scope
46
+ * }).handler(async () => ({ content: [{ type: "text", text: "pong" }] }));
47
+ * ```
48
+ */
49
+ declare function mcpTool<TInputSchema extends z.ZodTypeAny = z.ZodTypeAny, TOutputSchema extends z.ZodTypeAny = z.ZodTypeAny>(name: string, config?: McpToolConfig<TInputSchema, TOutputSchema>): McpToolBuilder<TInputSchema, TOutputSchema>;
50
+ //#endregion
51
+ //#region src/server/policy.d.ts
52
+ type EntityKind = "collection" | "global" | "route";
53
+ interface ResolvedMcpPolicy {
54
+ expose: boolean;
55
+ read?: boolean | McpAccessRule;
56
+ write?: boolean | McpAccessRule;
57
+ delete?: boolean | McpAccessRule;
58
+ operations: Record<string, boolean | McpAccessRule>;
59
+ requiredScopes?: McpRequiredScopes;
60
+ operationScopes: Record<string, McpRequiredScopes>;
61
+ fields?: {
62
+ include?: string[];
63
+ exclude?: string[];
64
+ };
65
+ description?: string;
66
+ }
67
+ /** Normalize an {@link McpRequiredScopes} declaration to a scope list. */
68
+ declare function normalizeRequiredScopes(required: McpRequiredScopes | undefined): string[];
69
+ /**
70
+ * Resolve the scopes an OAuth caller must hold for a given entity operation.
71
+ *
72
+ * Precedence (most specific wins), each level is declarative data:
73
+ * 1. `policy.operationScopes[operationName]` — per-operation override.
74
+ * 2. `policy.requiredScopes` — entity-level requirement (all operations).
75
+ * 3. the default `<resource>:<name>:<verb>` mapping derived from the kind.
76
+ *
77
+ * A level set to `false` explicitly requires no scope (stops the fallback).
78
+ * Returns a (possibly empty) scope list; empty means "no scope required". This
79
+ * resolves the requirement; the deny/register decision that consumes it is
80
+ * {@link scopeGateAllows}.
81
+ */
82
+ declare function requiredScopesForOperation(policy: ResolvedMcpPolicy, kind: EntityKind, name: string, operationName: string, operationKind: ScopeOperationKind): string[];
83
+ /**
84
+ * The consented scopes carried by the request, or `undefined` when the caller
85
+ * is not OAuth-authenticated. Reads `ctx.principal` (populated by MO6): only the
86
+ * `oauth` principal carries `scopes`; `user` and `system` do not.
87
+ */
88
+ declare function scopesFromContext(ctx: AppContext & Partial<RequestContext>): string[] | undefined;
89
+ /**
90
+ * The OAuth scope gate (MO8, extended by the umbrella model — LOCKED #2).
91
+ *
92
+ * Given the scopes the caller holds (from {@link scopesFromContext}) and the
93
+ * scopes an operation requires (from {@link requiredScopesForOperation} or a
94
+ * custom tool's `config.scopes`), decide whether the scope gate passes.
95
+ *
96
+ * Semantics:
97
+ * - `heldScopes === undefined` → the caller is not OAuth-authenticated (`user`,
98
+ * `system`, or unauthenticated). The scope gate does not apply and PASSES;
99
+ * authorization is left entirely to RBAC / MCP rules. This is what keeps the
100
+ * first-party admin (`user`) and stdio (`system`) paths unchanged.
101
+ * - Otherwise the caller is an `oauth` principal: the gate PASSES iff EVERY
102
+ * required scope is satisfied — a required scope is satisfied when the caller
103
+ * holds it directly OR holds its applicable coarse umbrella
104
+ * ({@link umbrellaScopeFor}). An empty `required` needs nothing, so it passes
105
+ * for everyone.
106
+ *
107
+ * The umbrella widening is deliberately narrow — it can only satisfy a
108
+ * granular `<resource>:<name>:read|write` with the matching `<resource>:read`
109
+ * or `<resource>:write` umbrella. `read` and `write` are independent (holding
110
+ * `collections:write` never satisfies a `<name>:read` requirement, and vice
111
+ * versa), and there is NO umbrella for `:delete` or `routes:…:invoke`. So the
112
+ * umbrella grants convenience without ever over-granting across verb, resource
113
+ * kind, or into delete/invoke.
114
+ *
115
+ * This gate is **additive** — it can only ever REMOVE access from an `oauth`
116
+ * caller. It never grants access on its own: callers still run the MCP rule and
117
+ * the collection/global `.access()` RBAC independently, and all must pass. The
118
+ * effective `oauth` permission is therefore `scopes ∩ RBAC`.
119
+ */
120
+ declare function scopeGateAllows(heldScopes: string[] | undefined, required: string[]): boolean;
121
+ //#endregion
122
+ export { type McpAccessMode, type McpAccessRule, type McpAccessRuleContext, type McpConfig, type McpCrudConfig, type McpCrudDefaults, type McpEntityPolicy, type McpExecutionOptions, type McpHttpConfig, type McpRequiredScopes, type McpResourcesConfig, type McpRoutesConfig, type McpStdioConfig, type McpToolConfig, type McpToolDefinition, type McpToolHandlerArgs, type McpTransportKind, type ScopeOperationKind, createMcpServer, mcpModule as default, mcpModule, defaultOperationScope, mcpConfig, mcpPlugin, mcpTool, normalizeRequiredScopes, requiredScopesForOperation, scopeGateAllows, scopesFromContext, startStdioServer };
package/dist/index.mjs ADDED
@@ -0,0 +1,12 @@
1
+ import { a as requiredScopesForOperation, i as normalizeRequiredScopes, n as mcpTool, o as scopeGateAllows, r as defaultOperationScope, s as scopesFromContext, t as createMcpServer } from "./create-server-DIvtVlma.mjs";
2
+ import { n as mcp_default, t as mcpModule } from "./mcp-DapXh3Mk.mjs";
3
+ import { t as mcpPlugin } from "./plugin-BJ6gELRj.mjs";
4
+ import { t as startStdioServer } from "./stdio-qyQFVEyU.mjs";
5
+
6
+ //#region src/server/config.ts
7
+ function mcpConfig(config) {
8
+ return config;
9
+ }
10
+
11
+ //#endregion
12
+ export { createMcpServer, mcp_default as default, defaultOperationScope, mcpConfig, mcpModule, mcpPlugin, mcpTool, normalizeRequiredScopes, requiredScopesForOperation, scopeGateAllows, scopesFromContext, startStdioServer };
@@ -0,0 +1,163 @@
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 at the server root by the core `oauth-protected-
51
+ * resource` route (MO4). An MCP client reads it to discover the authorization
52
+ * server and start the OAuth 2.1 flow.
53
+ *
54
+ * The origin is derived from `app.config.app.url` — the same base MO2/MO6 use to
55
+ * bind and verify token audience — so the advertised metadata URL always matches
56
+ * where discovery actually lives. `new URL(...).origin` strips any path/query and
57
+ * yields a bare `scheme://host[:port]`, so an app URL with a subpath still
58
+ * produces a root-mounted metadata URL.
59
+ */
60
+ function protectedResourceChallenge(appUrl) {
61
+ return `Bearer resource_metadata="${new URL(appUrl).origin}/.well-known/oauth-protected-resource"`;
62
+ }
63
+ /**
64
+ * A verified principal is required to reach MCP tool execution over HTTP. The
65
+ * request context resolves one for a cookie/bearer session (`kind: "user"`) or a
66
+ * valid OAuth access token (`kind: "oauth"`); an unauthenticated request has
67
+ * none. Read it structurally — the handler-args type does not surface it.
68
+ */
69
+ function hasVerifiedPrincipal(ctx) {
70
+ return Boolean(ctx.principal);
71
+ }
72
+ async function mcpHandler(ctx) {
73
+ const { request } = ctx;
74
+ const app = appFromRouteContext(ctx);
75
+ if (request.method === "OPTIONS") return withCors(new Response(null, { status: 204 }), request);
76
+ if (!hasVerifiedPrincipal(ctx)) return withCors(new Response(null, {
77
+ status: 401,
78
+ headers: { "WWW-Authenticate": protectedResourceChallenge(app.config.app.url) }
79
+ }), request);
80
+ const config = app.state?.config?.mcp ?? {};
81
+ const server = await createMcpServer(app, {
82
+ transport: "http",
83
+ accessMode: "user",
84
+ request,
85
+ ctx: executionContextFromRouteContext(ctx)
86
+ });
87
+ const transport = new WebStandardStreamableHTTPServerTransport({
88
+ sessionIdGenerator: void 0,
89
+ allowedOrigins: config.http?.allowedOrigins,
90
+ allowedHosts: config.http?.allowedHosts,
91
+ enableJsonResponse: config.http?.enableJsonResponse ?? true
92
+ });
93
+ await server.connect(transport);
94
+ return withCors(await transport.handleRequest(request), request);
95
+ }
96
+
97
+ //#endregion
98
+ //#region src/server/modules/mcp/routes/mcp.ts
99
+ var mcp_default$1 = route().post().raw().meta(mcpMeta).handler(mcpHandler);
100
+
101
+ //#endregion
102
+ //#region src/server/modules/mcp/routes/mcp.delete.ts
103
+ var mcp_delete_default = route().delete().raw().meta(mcpMeta).handler(mcpHandler);
104
+
105
+ //#endregion
106
+ //#region src/server/modules/mcp/routes/mcp.get.ts
107
+ var mcp_get_default = route().get().raw().meta(mcpMeta).handler(mcpHandler);
108
+
109
+ //#endregion
110
+ //#region src/server/modules/mcp/routes/mcp.options.ts
111
+ var mcp_options_default = route().options().raw().meta(mcpMeta).handler(mcpHandler);
112
+
113
+ //#endregion
114
+ //#region src/server/modules/mcp/plugin.ts
115
+ /**
116
+ * MCP module plugin — re-exports the MCP codegen plugin so that module
117
+ * codegen discovers it and embeds it in the generated module definition.
118
+ * This allows `extractPluginsFromModules` to pick it up automatically at
119
+ * root-app codegen time (so consuming apps get the `mcp-tools` category,
120
+ * `config/mcp.ts` discover, and scaffolds).
121
+ */
122
+ var plugin_default = mcpPlugin();
123
+
124
+ //#endregion
125
+ //#region src/server/modules/mcp/.generated/module.ts
126
+ const _module = {
127
+ name: "questpie-mcp",
128
+ routes: {
129
+ mcp: mcp_default$1,
130
+ "mcp:DELETE": mcp_delete_default,
131
+ "mcp:GET": mcp_get_default,
132
+ "mcp:OPTIONS": mcp_options_default
133
+ },
134
+ collections: {},
135
+ globals: {},
136
+ jobs: {},
137
+ messages: {},
138
+ services: {},
139
+ emails: {},
140
+ migrations: [],
141
+ seeds: [],
142
+ fieldTypes: {},
143
+ mcpTools: {},
144
+ plugin: plugin_default
145
+ };
146
+ var module_default = _module;
147
+
148
+ //#endregion
149
+ //#region src/server/modules/mcp/index.ts
150
+ /**
151
+ * MCP Module
152
+ *
153
+ * Backend module for the QUESTPIE Model Context Protocol endpoint.
154
+ *
155
+ * Exports:
156
+ * - `mcpModule` — static module definition (generated by codegen from file convention)
157
+ * - `McpModule` — type of the static module
158
+ */
159
+ const mcpModule = module_default;
160
+ var mcp_default = mcpModule;
161
+
162
+ //#endregion
163
+ export { mcp_default as n, mcpModule as t };
@@ -0,0 +1,2 @@
1
+ import { n as McpModule, t as mcpModule } from "../index-Cxta5KOn.mjs";
2
+ export { type McpModule, mcpModule };
@@ -0,0 +1,3 @@
1
+ import { t as mcpModule } from "../mcp-DapXh3Mk.mjs";
2
+
3
+ export { mcpModule };
@@ -0,0 +1,39 @@
1
+ //#region src/server/plugin.ts
2
+ function mcpPlugin() {
3
+ return {
4
+ name: "questpie-mcp",
5
+ targets: { server: {
6
+ root: ".",
7
+ outputFile: "index.ts",
8
+ categories: { mcpTools: {
9
+ dirs: ["mcp-tools"],
10
+ prefix: "mcpTool",
11
+ factoryFunctions: ["mcpTool"],
12
+ registryKey: true,
13
+ includeInAppState: true,
14
+ extractFromModules: true,
15
+ typeEmit: "standard"
16
+ } },
17
+ discover: { mcpConfig: {
18
+ pattern: "config/mcp.ts",
19
+ configKey: "mcp"
20
+ } },
21
+ registries: { singletonFactories: { mcpConfig: {
22
+ configType: "McpConfig",
23
+ imports: [{
24
+ name: "McpConfig",
25
+ from: "@questpie/mcp"
26
+ }],
27
+ isCallback: true
28
+ } } },
29
+ scaffolds: { "mcp-tool": {
30
+ dir: "mcp-tools",
31
+ description: "MCP custom tool definition",
32
+ template: ({ kebab, camel }) => `import { mcpTool } from "@questpie/mcp";\nimport { z } from "zod";\n\nexport default mcpTool("${kebab}", {\n\tdescription: "Run ${kebab}.",\n\tinputSchema: z.object({}),\n}).handler(async ({ ctx }) => {\n\treturn {\n\t\tstructuredContent: { ok: true },\n\t\tcontent: [{ type: "text", text: "${camel} completed" }],\n\t};\n});\n`
33
+ } }
34
+ } }
35
+ };
36
+ }
37
+
38
+ //#endregion
39
+ export { mcpPlugin as t };
@@ -0,0 +1,6 @@
1
+ import { CodegenPlugin } from "questpie/codegen";
2
+
3
+ //#region src/server/plugin.d.ts
4
+ declare function mcpPlugin(): CodegenPlugin;
5
+ //#endregion
6
+ export { mcpPlugin as t };
@@ -0,0 +1,2 @@
1
+ import { t as mcpPlugin } from "./plugin-CMR-wkeP.mjs";
2
+ export { mcpPlugin };
@@ -0,0 +1,3 @@
1
+ import { t as mcpPlugin } from "./plugin-BJ6gELRj.mjs";
2
+
3
+ export { mcpPlugin };
@@ -0,0 +1,16 @@
1
+ import { t as createMcpServer } from "./create-server-DIvtVlma.mjs";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+
4
+ //#region src/server/stdio.ts
5
+ async function startStdioServer(app, options = {}) {
6
+ const server = await createMcpServer(app, {
7
+ ...options,
8
+ transport: "stdio"
9
+ });
10
+ const transport = new StdioServerTransport();
11
+ await server.connect(transport);
12
+ return server;
13
+ }
14
+
15
+ //#endregion
16
+ export { startStdioServer as t };
@@ -0,0 +1,154 @@
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 };
@@ -0,0 +1,2 @@
1
+ import { t as startStdioServer } from "./stdio-t_9rKayH.mjs";
2
+ export { startStdioServer };
package/dist/stdio.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { t as startStdioServer } from "./stdio-qyQFVEyU.mjs";
2
+
3
+ export { startStdioServer };