@classytic/arc 2.15.3 → 2.16.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.
- package/README.md +1 -0
- package/bin/arc.js +12 -0
- package/dist/{BaseController-dx3m2J8V.mjs → BaseController-DlCCTIxJ.mjs} +61 -19
- package/dist/{HookSystem-Iiebom92.mjs → HookSystem-Cmf7-Etp.mjs} +8 -4
- package/dist/{QueryCache-D41bfdBB.d.mts → QueryCache-SvmT_9ti.d.mts} +1 -1
- package/dist/{ResourceRegistry-CTERg_2x.mjs → ResourceRegistry-f48hFk3m.mjs} +52 -9
- package/dist/audit/index.d.mts +1 -1
- package/dist/audit/index.mjs +4 -2
- package/dist/auth/index.d.mts +4 -4
- package/dist/auth/index.mjs +4 -4
- package/dist/auth/redis-session.d.mts +1 -1
- package/dist/{betterAuthOpenApi--M_i87dQ.mjs → betterAuthOpenApi-ClWxaceA.mjs} +10 -6
- package/dist/buildHandler-BZX6zzDM.mjs +300 -0
- package/dist/cache/index.d.mts +3 -3
- package/dist/cache/index.mjs +3 -3
- package/dist/{caching-SM8gghN6.mjs → caching-TeHE8G-v.mjs} +1 -1
- package/dist/cli/commands/describe.d.mts +35 -1
- package/dist/cli/commands/describe.mjs +52 -12
- package/dist/cli/commands/docs.d.mts +1 -4
- package/dist/cli/commands/docs.mjs +4 -16
- package/dist/cli/commands/generate.d.mts +2 -20
- package/dist/cli/commands/generate.mjs +1 -546
- package/dist/cli/commands/init.d.mts +2 -40
- package/dist/cli/commands/init.mjs +1 -3036
- package/dist/cli/commands/introspect.mjs +53 -64
- package/dist/cli/index.d.mts +2 -2
- package/dist/cli/index.mjs +2 -2
- package/dist/{constants-Cxde4rpC.mjs → constants-TrJVIJl0.mjs} +7 -0
- package/dist/core/index.d.mts +3 -3
- package/dist/core/index.mjs +5 -5
- package/dist/{core-CvmOqEms.mjs → core-DBJ_j6rX.mjs} +222 -44
- package/dist/createActionRouter-DUpN3Dd1.mjs +288 -0
- package/dist/{createAggregationRouter-B0bPDf5b.mjs → createAggregationRouter-Dq-TUCuY.mjs} +3 -2
- package/dist/{createApp-PFegs47-.mjs → createApp-DNccuhyI.mjs} +16 -14
- package/dist/{defineEvent-D5h7EvAx.mjs → defineEvent-DRwY0fYm.mjs} +1 -1
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.mjs +1 -1
- package/dist/{errorHandler-Bk-AGhkU.mjs → errorHandler-DpoXQHZ9.mjs} +17 -14
- package/dist/errors-C1lX_jlm.d.mts +91 -0
- package/dist/{eventPlugin-CaKTYkYM.mjs → eventPlugin-C2cGqtRO.mjs} +1 -1
- package/dist/{eventPlugin-qXpqTebY.d.mts → eventPlugin-CtHC_av1.d.mts} +1 -1
- package/dist/events/index.d.mts +3 -3
- package/dist/events/index.mjs +5 -5
- package/dist/events/transports/redis-stream-entry.d.mts +1 -1
- package/dist/events/transports/redis.d.mts +1 -1
- package/dist/factory/index.d.mts +1 -1
- package/dist/factory/index.mjs +2 -2
- package/dist/{fields-COhcH3fk.d.mts → fields-Anj0xdih.d.mts} +1 -1
- package/dist/generate-BWFwgcCM.d.mts +38 -0
- package/dist/generate-CYac-OLv.mjs +654 -0
- package/dist/hooks/index.d.mts +1 -1
- package/dist/hooks/index.mjs +1 -1
- package/dist/idempotency/index.d.mts +2 -2
- package/dist/idempotency/index.mjs +1 -1
- package/dist/idempotency/redis.d.mts +1 -1
- package/dist/{index-BTqLEvhu.d.mts → index-3oIimXQn.d.mts} +12 -12
- package/dist/{index-BstGxcc3.d.mts → index-B-ulKx5P.d.mts} +55 -4
- package/dist/{index-BswOSJCE.d.mts → index-CkW0flkU.d.mts} +355 -16
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +7 -8
- package/dist/init-Dv71MsJr.d.mts +71 -0
- package/dist/init-HDvoO9L5.mjs +3098 -0
- package/dist/integrations/event-gateway.d.mts +2 -2
- package/dist/integrations/event-gateway.mjs +1 -1
- package/dist/integrations/index.d.mts +2 -2
- package/dist/integrations/jobs.mjs +3 -3
- package/dist/integrations/mcp/index.d.mts +239 -7
- package/dist/integrations/mcp/index.mjs +2 -528
- package/dist/integrations/mcp/testing.d.mts +2 -2
- package/dist/integrations/mcp/testing.mjs +6 -10
- package/dist/integrations/streamline.d.mts +71 -2
- package/dist/integrations/streamline.mjs +81 -8
- package/dist/integrations/websocket-redis.d.mts +1 -1
- package/dist/integrations/websocket.d.mts +1 -1
- package/dist/integrations/websocket.mjs +1 -0
- package/dist/loadResourcesFromEntry-BLMEI2Xa.mjs +51 -0
- package/dist/{resourceToTools-tFYUNmM0.mjs → mcpPlugin-7vGV51ED.mjs} +1021 -318
- package/dist/{memory-UBydS5ku.mjs → memory-QOLe11D5.mjs} +2 -0
- package/dist/middleware/index.d.mts +1 -1
- package/dist/middleware/index.mjs +1 -1
- package/dist/{openapi-BHXhoX8O.mjs → openapi-34T9yNwd.mjs} +47 -36
- package/dist/permissions/index.d.mts +2 -2
- package/dist/permissions/index.mjs +1 -1
- package/dist/{permissions-ohQyv50e.mjs → permissions-CTxMrreC.mjs} +2 -2
- package/dist/{pipe-Zr0KXjQe.mjs → pipe-DiCyvyPN.mjs} +1 -0
- package/dist/pipeline/index.d.mts +1 -1
- package/dist/pipeline/index.mjs +1 -1
- package/dist/plugins/index.d.mts +5 -5
- package/dist/plugins/index.mjs +10 -10
- package/dist/plugins/response-cache.mjs +5 -5
- package/dist/plugins/tracing-entry.d.mts +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{pluralize-DQgqgifU.mjs → pluralize-B9M8xvy-.mjs} +2 -1
- package/dist/presets/filesUpload.d.mts +4 -4
- package/dist/presets/filesUpload.mjs +2 -2
- package/dist/presets/index.d.mts +1 -1
- package/dist/presets/index.mjs +1 -1
- package/dist/presets/multiTenant.d.mts +1 -1
- package/dist/presets/multiTenant.mjs +4 -3
- package/dist/presets/search.d.mts +2 -2
- package/dist/presets/search.mjs +1 -1
- package/dist/{presets-BbkjdPeH.mjs → presets-C9BE6WaZ.mjs} +2 -2
- package/dist/{queryCachePlugin-m1XsgAIJ.mjs → queryCachePlugin-B4XMSSe7.mjs} +2 -2
- package/dist/{queryCachePlugin-CqMdLI2-.d.mts → queryCachePlugin-Biqzfbi5.d.mts} +2 -2
- package/dist/{redis-DiMkdHEl.d.mts → redis-Cyzrz6SX.d.mts} +1 -1
- package/dist/{redis-stream-D6HzR1Z_.d.mts → redis-stream-DT-YjzrB.d.mts} +1 -1
- package/dist/registry/index.d.mts +319 -2
- package/dist/registry/index.mjs +3 -3
- package/dist/registry-BBE23CDj.mjs +576 -0
- package/dist/{routerShared-DrOa-26E.mjs → routerShared-CZV5aabX.mjs} +3 -3
- package/dist/scope/index.d.mts +3 -3
- package/dist/scope/index.mjs +3 -3
- package/dist/{sse-Bz-5ZeTt.mjs → sse-BY6sTy4P.mjs} +1 -1
- package/dist/testing/index.d.mts +2 -2
- package/dist/testing/index.mjs +16 -7
- package/dist/testing/storageContract.d.mts +1 -1
- package/dist/types/index.d.mts +5 -5
- package/dist/types/storage.d.mts +1 -1
- package/dist/{types-C_s5moIu.mjs → types-Bi0r0vjG.mjs} +53 -1
- package/dist/{types-BQsjgQzS.d.mts → types-BsJMEQ4D.d.mts} +106 -12
- package/dist/{types-DrBaUwyV.d.mts → types-D-fYtKjb.d.mts} +33 -10
- package/dist/{types-CTYvcwHe.d.mts → types-DVfpSfx2.d.mts} +42 -1
- package/dist/utils/index.d.mts +1286 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/{utils-_h9B3c57.mjs → utils-DC5ycPfr.mjs} +89 -40
- package/dist/{buildHandler-CcFOpJLh.mjs → validate-By96rH0r.mjs} +8 -299
- package/dist/{versioning-hmkPcDlX.d.mts → versioning-ZwX9tmbS.d.mts} +1 -1
- package/package.json +22 -29
- package/skills/arc/SKILL.md +299 -689
- package/skills/arc/references/auth.md +19 -7
- package/skills/arc-code-review/SKILL.md +1 -1
- package/skills/arc-code-review/references/arc-cheatsheet.md +100 -322
- package/dist/createActionRouter-S3MLVYot.mjs +0 -220
- package/dist/index-bRjYu21O.d.mts +0 -1320
- package/dist/org/index.d.mts +0 -66
- package/dist/org/index.mjs +0 -486
- package/dist/org/types.d.mts +0 -82
- package/dist/org/types.mjs +0 -1
- package/dist/registry-I-ogLgL9.mjs +0 -46
- /package/dist/{EventTransport-CT_52aWU.d.mts → EventTransport-C-2oAHtw.d.mts} +0 -0
- /package/dist/{EventTransport-DLWoUMHy.mjs → EventTransport-Hxvv5QQz.mjs} +0 -0
- /package/dist/{actionPermissions-CyUkQu6O.mjs → actionPermissions-Bjmvn7Eb.mjs} +0 -0
- /package/dist/{elevation-BXOWoGCF.d.mts → elevation-0YBpa663.d.mts} +0 -0
- /package/dist/{elevation-DgoeTyfX.mjs → elevation-Dci0AYLT.mjs} +0 -0
- /package/dist/{errorHandler-DFr45ZG4.d.mts → errorHandler-mHuyWzZE.d.mts} +0 -0
- /package/dist/{externalPaths-BD5nw6St.d.mts → externalPaths-DFg-2KTp.d.mts} +0 -0
- /package/dist/{interface-beEtJyWM.d.mts → interface-CH0OQudo.d.mts} +0 -0
- /package/dist/{interface-DfLGcus7.d.mts → interface-NwJ_qPlY.d.mts} +0 -0
- /package/dist/{keys-CGcCbNyu.mjs → keys-DopsCuyQ.mjs} +0 -0
- /package/dist/{loadResources-DBMQg_Aj.mjs → loadResources-ChQEj8ih.mjs} +0 -0
- /package/dist/{metrics-Qnvwc-LQ.mjs → metrics-TuOmguhi.mjs} +0 -0
- /package/dist/{replyHelpers-CK-FNO8E.mjs → replyHelpers-C-gD32oF.mjs} +0 -0
- /package/dist/{schemaIR-lYhC2gE5.mjs → schemaIR-Ctc89DSn.mjs} +0 -0
- /package/dist/{sessionManager-C4Le_UB3.d.mts → sessionManager-BqFegc0W.d.mts} +0 -0
- /package/dist/{storage-Dfzt4VTl.d.mts → storage-D2KZJAmn.d.mts} +0 -0
- /package/dist/{store-helpers-BkIN9-vu.mjs → store-helpers-B0sunfZZ.mjs} +0 -0
- /package/dist/{tracing-QJVprktp.d.mts → tracing-Dm8n7Cnn.d.mts} +0 -0
- /package/dist/{versioning-BUrT5aP4.mjs → versioning-B6mimogM.mjs} +0 -0
- /package/dist/{websocket-ChC2rqe1.d.mts → websocket-BkjeGZRn.d.mts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as DomainEvent } from "../EventTransport-
|
|
2
|
-
import { a as WebSocketMessage, i as WebSocketClient } from "../websocket-
|
|
1
|
+
import { n as DomainEvent } from "../EventTransport-C-2oAHtw.mjs";
|
|
2
|
+
import { a as WebSocketMessage, i as WebSocketClient } from "../websocket-BkjeGZRn.mjs";
|
|
3
3
|
import { FastifyPluginAsync, FastifyRequest } from "fastify";
|
|
4
4
|
|
|
5
5
|
//#region src/integrations/event-gateway.d.ts
|
|
@@ -4,7 +4,7 @@ const eventGatewayPluginImpl = async (fastify, opts = {}) => {
|
|
|
4
4
|
const { auth = true, orgScoped = false, roomPolicy, maxMessageBytes, maxSubscriptionsPerClient, authenticate } = opts;
|
|
5
5
|
if (auth && !authenticate && !fastify.hasDecorator("authenticate")) throw new Error("[arc-event-gateway] auth is true but fastify.authenticate is not registered. Register an auth plugin first, provide a custom authenticate function, or set auth: false.");
|
|
6
6
|
if (opts.sse !== false) {
|
|
7
|
-
const { default: ssePlugin } = await import("../sse-
|
|
7
|
+
const { default: ssePlugin } = await import("../sse-BY6sTy4P.mjs").then((n) => n.r);
|
|
8
8
|
await fastify.register(ssePlugin, {
|
|
9
9
|
path: opts.sse?.path ?? "/events/stream",
|
|
10
10
|
requireAuth: auth,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as WebSocketMessage, i as WebSocketClient, o as WebSocketPluginOptions } from "../websocket-
|
|
1
|
+
import { a as WebSocketMessage, i as WebSocketClient, o as WebSocketPluginOptions } from "../websocket-BkjeGZRn.mjs";
|
|
2
2
|
import { EventGatewayOptions } from "./event-gateway.mjs";
|
|
3
3
|
import { JobDefinition, JobDispatchOptions, JobDispatcher, JobMeta, JobsPluginOptions, QueueStats } from "./jobs.mjs";
|
|
4
|
-
import { c as
|
|
4
|
+
import { c as McpAuthResult, d as PromptDefinition, g as ToolDefinition, h as ToolContext, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, r as CreateMcpServerConfig, t as BetterAuthHandler, u as McpResourceConfig } from "../types-BsJMEQ4D.mjs";
|
|
5
5
|
import { StreamlinePluginOptions, WorkflowLike, WorkflowRunLike } from "./streamline.mjs";
|
|
6
6
|
import { WebhookDeliveryRecord, WebhookManager, WebhookPluginOptions, WebhookStore, WebhookSubscription } from "./webhooks.mjs";
|
|
7
7
|
export { type BetterAuthHandler, type CallToolResult, type CreateMcpServerConfig, type CrudOperation, type EventGatewayOptions, type JobDefinition, type JobDispatchOptions, type JobDispatcher, type JobMeta, type JobsPluginOptions, type McpAuthResult, type McpPluginOptions, type McpResourceConfig, type PromptDefinition, type QueueStats, type StreamlinePluginOptions, type ToolAnnotations, type ToolContext, type ToolDefinition, type WebSocketClient, type WebSocketMessage, type WebSocketPluginOptions, type WebhookDeliveryRecord, type WebhookManager, type WebhookPluginOptions, type WebhookStore, type WebhookSubscription, type WorkflowLike, type WorkflowRunLike };
|
|
@@ -68,8 +68,8 @@ const jobsPluginImpl = async (fastify, options) => {
|
|
|
68
68
|
const jobTimeout = job.timeout ?? defaults.timeout;
|
|
69
69
|
const worker = new Worker(queueName, async (bullJob) => {
|
|
70
70
|
const meta = {
|
|
71
|
-
jobId: bullJob.id,
|
|
72
|
-
attemptsMade: bullJob.attemptsMade,
|
|
71
|
+
jobId: bullJob.id ?? "",
|
|
72
|
+
attemptsMade: bullJob.attemptsMade ?? 0,
|
|
73
73
|
timestamp: Date.now()
|
|
74
74
|
};
|
|
75
75
|
let result;
|
|
@@ -107,7 +107,7 @@ const jobsPluginImpl = async (fastify, options) => {
|
|
|
107
107
|
});
|
|
108
108
|
worker.on("failed", async (bullJob, error) => {
|
|
109
109
|
const maxAttempts = job.retries ?? defaults.retries ?? 3;
|
|
110
|
-
if (dlqQueue && bullJob && bullJob.attemptsMade >= maxAttempts) try {
|
|
110
|
+
if (dlqQueue && bullJob && (bullJob.attemptsMade ?? 0) >= maxAttempts) try {
|
|
111
111
|
await dlqQueue.add(`${queueName}:dead`, bullJob.data, {
|
|
112
112
|
jobId: `${bullJob.id}:dlq`,
|
|
113
113
|
removeOnComplete: false
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { V as ResourceDefinition } from "../../index-
|
|
2
|
-
import {
|
|
1
|
+
import { V as ResourceDefinition, bt as IRequestContext, yt as IControllerResponse } from "../../index-CkW0flkU.mjs";
|
|
2
|
+
import { i as RequestScope } from "../../types-DVfpSfx2.mjs";
|
|
3
|
+
import { c as PermissionCheck } from "../../fields-Anj0xdih.mjs";
|
|
4
|
+
import { a as CrudDescriptionOverride, c as McpAuthResult, d as PromptDefinition, f as PromptResult, g as ToolDefinition, h as ToolContext, i as CrudDescriptionMeta, l as McpPluginOptions, m as ToolAnnotations, n as CallToolResult, o as CrudOperation, p as SessionEntry, r as CreateMcpServerConfig, s as McpAuthResolver, t as BetterAuthHandler, u as McpResourceConfig } from "../../types-BsJMEQ4D.mjs";
|
|
5
|
+
import { ErrorContract } from "@classytic/repo-core/errors";
|
|
3
6
|
import { FastifyPluginAsync } from "fastify";
|
|
4
7
|
import { z } from "zod";
|
|
5
8
|
|
|
@@ -74,6 +77,30 @@ interface McpServerInstance {
|
|
|
74
77
|
resource: (...args: unknown[]) => void;
|
|
75
78
|
}
|
|
76
79
|
//#endregion
|
|
80
|
+
//#region src/integrations/mcp/crud-tools.d.ts
|
|
81
|
+
/**
|
|
82
|
+
* Default description for a CRUD tool. Enriches list descriptions with the
|
|
83
|
+
* configured filter/sort metadata so MCP clients can see what's queryable
|
|
84
|
+
* without reading the resource source.
|
|
85
|
+
*
|
|
86
|
+
* Exposed publicly so authors using the function-form `descriptions`
|
|
87
|
+
* override can call this from their own override to keep the auto-derived
|
|
88
|
+
* blurb intact and only append extra context.
|
|
89
|
+
*/
|
|
90
|
+
declare function defaultCrudDescription(op: CrudOperation, displayName: string, softDelete: boolean, queryMeta?: {
|
|
91
|
+
filterableFields?: readonly string[];
|
|
92
|
+
allowedOperators?: readonly string[];
|
|
93
|
+
sortableFields?: readonly string[];
|
|
94
|
+
}): string;
|
|
95
|
+
/**
|
|
96
|
+
* Resolve a {@link CrudDescriptionOverride} (string or function) into a
|
|
97
|
+
* concrete description. Centralises the function-form contract so every
|
|
98
|
+
* call site that consumes an override applies it the same way.
|
|
99
|
+
*
|
|
100
|
+
* Falls back to {@link defaultCrudDescription} when no override is set.
|
|
101
|
+
*/
|
|
102
|
+
declare function resolveCrudDescription(override: CrudDescriptionOverride | undefined, meta: CrudDescriptionMeta): string;
|
|
103
|
+
//#endregion
|
|
77
104
|
//#region src/integrations/mcp/definePrompt.d.ts
|
|
78
105
|
/** definePrompt() config */
|
|
79
106
|
interface DefinePromptConfig<TArgs extends Record<string, z.ZodTypeAny>> {
|
|
@@ -92,8 +119,15 @@ interface DefinePromptConfig<TArgs extends Record<string, z.ZodTypeAny>> {
|
|
|
92
119
|
declare function definePrompt<TArgs extends Record<string, z.ZodTypeAny>>(name: string, config: DefinePromptConfig<TArgs>): PromptDefinition;
|
|
93
120
|
//#endregion
|
|
94
121
|
//#region src/integrations/mcp/defineTool.d.ts
|
|
95
|
-
/**
|
|
96
|
-
|
|
122
|
+
/**
|
|
123
|
+
* defineTool() config — uses flat Zod shapes for SDK compatibility.
|
|
124
|
+
*
|
|
125
|
+
* The `TSession` parameter widens `ctx.session` to a host-specific shape.
|
|
126
|
+
* Pass an interface that extends `McpAuthResult` (or one that omits it
|
|
127
|
+
* entirely for custom auth resolvers) to drop the `as any` casts that
|
|
128
|
+
* pre-2.15.5 handlers needed when reading session fields.
|
|
129
|
+
*/
|
|
130
|
+
interface DefineToolConfig<TInput extends Record<string, z.ZodTypeAny>, TSession = McpAuthResult> {
|
|
97
131
|
description: string;
|
|
98
132
|
title?: string;
|
|
99
133
|
/** Flat Zod shape: `{ name: z.string(), age: z.number() }` */
|
|
@@ -101,7 +135,7 @@ interface DefineToolConfig<TInput extends Record<string, z.ZodTypeAny>> {
|
|
|
101
135
|
/** Flat Zod shape for structured output */
|
|
102
136
|
output?: Record<string, z.ZodTypeAny>;
|
|
103
137
|
annotations?: ToolAnnotations;
|
|
104
|
-
handler: (input: { [K in keyof TInput]: z.infer<TInput[K]> }, ctx: ToolContext) => Promise<CallToolResult>;
|
|
138
|
+
handler: (input: { [K in keyof TInput]: z.infer<TInput[K]> }, ctx: ToolContext<TSession>) => Promise<CallToolResult>;
|
|
105
139
|
}
|
|
106
140
|
/**
|
|
107
141
|
* Define a type-safe MCP tool.
|
|
@@ -109,7 +143,7 @@ interface DefineToolConfig<TInput extends Record<string, z.ZodTypeAny>> {
|
|
|
109
143
|
* @param name - Tool name (snake_case recommended)
|
|
110
144
|
* @param config - Tool description, input schema, annotations, handler
|
|
111
145
|
*/
|
|
112
|
-
declare function defineTool<TInput extends Record<string, z.ZodTypeAny
|
|
146
|
+
declare function defineTool<TInput extends Record<string, z.ZodTypeAny>, TSession = McpAuthResult>(name: string, config: DefineToolConfig<TInput, TSession>): ToolDefinition<TSession>;
|
|
113
147
|
//#endregion
|
|
114
148
|
//#region src/integrations/mcp/fieldRulesToZod.d.ts
|
|
115
149
|
interface FieldRulesToZodOptions {
|
|
@@ -202,6 +236,121 @@ declare function requireOrgId(orgId: string): McpGuard;
|
|
|
202
236
|
*/
|
|
203
237
|
declare function customGuard(check: (ctx: ToolContext) => boolean | Promise<boolean>, errorMessage: string): McpGuard;
|
|
204
238
|
//#endregion
|
|
239
|
+
//#region src/integrations/mcp/buildRequestContext.d.ts
|
|
240
|
+
type McpOperation = "list" | "get" | "create" | "update" | "delete" | "action";
|
|
241
|
+
/**
|
|
242
|
+
* Build an IRequestContext from MCP tool input and session auth.
|
|
243
|
+
*
|
|
244
|
+
* | Operation | params | query | body |
|
|
245
|
+
* |-----------|------------|----------------------|---------------------|
|
|
246
|
+
* | list | {} | all input fields | undefined |
|
|
247
|
+
* | get | { id } | {} | undefined |
|
|
248
|
+
* | create | {} | {} | all input fields |
|
|
249
|
+
* | update | { id } | {} | input minus id |
|
|
250
|
+
* | delete | { id } | {} | undefined |
|
|
251
|
+
*
|
|
252
|
+
* **scopeOverride** — when a permission check (e.g. `requireApiKey()`) returns
|
|
253
|
+
* `PermissionResult.scope`, the MCP tool handler must install it on the request
|
|
254
|
+
* context the same way CRUD/action routes do. This parameter follows the exact
|
|
255
|
+
* same non-downgrade rule as `applyPermissionResult`: it overrides only when
|
|
256
|
+
* the session-derived scope is `public` (i.e. MCP called with `auth: false`).
|
|
257
|
+
* An authenticated session scope is never overwritten.
|
|
258
|
+
*/
|
|
259
|
+
declare function buildRequestContext(input: Record<string, unknown>, auth: McpAuthResult | null, operation: McpOperation, policyFilters?: Record<string, unknown>, scopeOverride?: RequestScope): IRequestContext;
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/integrations/mcp/invokeController.d.ts
|
|
262
|
+
/**
|
|
263
|
+
* Options threaded into {@link invokeController}. `session` is required so
|
|
264
|
+
* permission checks and scope resolution can both honor the caller's
|
|
265
|
+
* identity; everything else is optional and falls back to sensible defaults.
|
|
266
|
+
*/
|
|
267
|
+
interface InvokeControllerOptions {
|
|
268
|
+
/** Resolved identity for this invocation — `null` runs as public scope. */
|
|
269
|
+
readonly session: McpAuthResult | null;
|
|
270
|
+
/** Resource name surfaced into the permission context (`PermissionContext.resource`). */
|
|
271
|
+
readonly resourceName: string;
|
|
272
|
+
/**
|
|
273
|
+
* Logical action name surfaced into the permission context
|
|
274
|
+
* (`PermissionContext.action`). Defaults to `op` — pass a distinct name
|
|
275
|
+
* for custom routes / declarative actions to keep audit logs readable.
|
|
276
|
+
*/
|
|
277
|
+
readonly actionName?: string;
|
|
278
|
+
/**
|
|
279
|
+
* Permission to evaluate before invoking the controller. `undefined` means
|
|
280
|
+
* "no gate" — same semantics as CRUD without a declared `permissions.<op>`.
|
|
281
|
+
* Authors that want fail-closed behavior should pass `requireAuth()` or a
|
|
282
|
+
* concrete role gate; `allowPublic()` documents an intentional opt-out.
|
|
283
|
+
*/
|
|
284
|
+
readonly permissions?: PermissionCheck;
|
|
285
|
+
/**
|
|
286
|
+
* Method name on the controller. Defaults to `op`. Override for custom-route
|
|
287
|
+
* dispatch where the method name differs from the MCP operation (e.g. an
|
|
288
|
+
* action handler reached through a `string` route handler).
|
|
289
|
+
*/
|
|
290
|
+
readonly methodName?: string;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Invoke a controller method through the MCP synthetic-context path.
|
|
294
|
+
*
|
|
295
|
+
* Runs the same chain CRUD MCP tools run:
|
|
296
|
+
* 1. {@link evaluatePermission} — fails with the canonical
|
|
297
|
+
* `arc.unauthorized` / `arc.forbidden` `CallToolResult` shape on denial.
|
|
298
|
+
* 2. {@link buildRequestContext} — projects MCP input + session into
|
|
299
|
+
* `IRequestContext`. Permission `filters` / `scope` thread through
|
|
300
|
+
* identically to CRUD/action routes.
|
|
301
|
+
* 3. `controller[methodName](ctx)` — dispatch. Errors are routed through
|
|
302
|
+
* `toCallToolError` so `ArcError` / `HttpError` throws land as the same
|
|
303
|
+
* `ErrorContract` shape an HTTP client would see.
|
|
304
|
+
*
|
|
305
|
+
* @example Run a controller op from a custom MCP tool.
|
|
306
|
+
* ```ts
|
|
307
|
+
* defineTool('promote_post', {
|
|
308
|
+
* description: 'Promote a draft to published',
|
|
309
|
+
* inputSchema: { id: z.string() },
|
|
310
|
+
* handler: (input, ctx) =>
|
|
311
|
+
* invokeController(postController, 'update', { ...input, status: 'published' }, {
|
|
312
|
+
* session: ctx.session,
|
|
313
|
+
* resourceName: 'post',
|
|
314
|
+
* permissions: requireRoles(['editor']),
|
|
315
|
+
* }),
|
|
316
|
+
* });
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* Workflow / scheduled-job callers pass a synthetic `session` they
|
|
320
|
+
* constructed from the job's owning identity — the shape is the same
|
|
321
|
+
* `McpAuthResult` the HTTP MCP plugin produces, so the same permission
|
|
322
|
+
* checks compose.
|
|
323
|
+
*/
|
|
324
|
+
declare function invokeController(controller: unknown, op: McpOperation, input: Record<string, unknown>, options: InvokeControllerOptions): Promise<CallToolResult>;
|
|
325
|
+
/**
|
|
326
|
+
* Wrap an async function as a {@link ToolDefinition} handler — handles the
|
|
327
|
+
* try/catch → canonical-error translation in one place so MCP tools that
|
|
328
|
+
* compose multiple internal calls don't reimplement the boilerplate.
|
|
329
|
+
*
|
|
330
|
+
* The wrapped function may return:
|
|
331
|
+
* - A `CallToolResult` — passed through unchanged (use this to short-circuit
|
|
332
|
+
* with `permissionDeniedResult` or a custom error shape).
|
|
333
|
+
* - An `IControllerResponse` envelope (`{ data, meta?, status?, headers? }`)
|
|
334
|
+
* — serialised via `toCallToolResult` so pagination meta etc. survive.
|
|
335
|
+
* - Any other value — serialised as JSON via `toCallToolSuccess` semantics.
|
|
336
|
+
*
|
|
337
|
+
* Errors raised inside the function are caught and routed through
|
|
338
|
+
* `toCallToolError`, so `ArcError` / `HttpError` throws collapse to the
|
|
339
|
+
* canonical `ErrorContract` shape MCP agents see for every other surface.
|
|
340
|
+
*
|
|
341
|
+
* @example Compose two controller calls in one tool.
|
|
342
|
+
* ```ts
|
|
343
|
+
* defineTool('archive_and_log', {
|
|
344
|
+
* description: '...',
|
|
345
|
+
* handler: mcpHandlerAdapter(async (input, ctx) => {
|
|
346
|
+
* await invokeController(postController, 'update', { ...input, archived: true }, opts);
|
|
347
|
+
* return invokeController(auditController, 'create', { event: 'archive', ...input }, opts);
|
|
348
|
+
* }),
|
|
349
|
+
* });
|
|
350
|
+
* ```
|
|
351
|
+
*/
|
|
352
|
+
declare function mcpHandlerAdapter<TSession = McpAuthResult>(fn: (input: Record<string, unknown>, ctx: ToolContext<TSession>) => Promise<unknown>): ToolDefinition<TSession>["handler"];
|
|
353
|
+
//#endregion
|
|
205
354
|
//#region src/integrations/mcp/sessionCache.d.ts
|
|
206
355
|
declare class McpSessionCache {
|
|
207
356
|
private sessions;
|
|
@@ -261,6 +410,37 @@ declare module "fastify" {
|
|
|
261
410
|
mcp?: McpDecorator;
|
|
262
411
|
}
|
|
263
412
|
}
|
|
413
|
+
interface ResourceFilterInputs {
|
|
414
|
+
readonly expose?: readonly string[];
|
|
415
|
+
readonly include?: readonly string[];
|
|
416
|
+
readonly exclude?: readonly string[];
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Resolve `expose` / `include` / `exclude` into the filtered resource list
|
|
420
|
+
* `mcpPlugin` should surface. Three mutually exclusive intents:
|
|
421
|
+
*
|
|
422
|
+
* - `expose`: default-deny allowlist (preferred — new resources auto-deny).
|
|
423
|
+
* - `include`: legacy alias for `expose`, kept for back-compat.
|
|
424
|
+
* - `exclude`: default-allow opt-out (drift-prone — new resources auto-leak).
|
|
425
|
+
*
|
|
426
|
+
* Conflicting combinations throw with an actionable message so a host that
|
|
427
|
+
* accidentally mixed paradigms fails at boot instead of silently leaking or
|
|
428
|
+
* starving the LLM surface.
|
|
429
|
+
*
|
|
430
|
+
* **Local opt-out wins.** Any resource declared with
|
|
431
|
+
* `defineResource({ mcp: false })` is dropped FIRST, before any of the
|
|
432
|
+
* plugin-level allowlists/blocklists run. The opt-out is colocated with
|
|
433
|
+
* the resource definition, so adding a new "never-expose" resource is
|
|
434
|
+
* a single-file change instead of a host-wide blocklist update that
|
|
435
|
+
* drifts as the codebase grows.
|
|
436
|
+
*
|
|
437
|
+
* Exported so `mcp/testing.ts` and external test harnesses can apply the
|
|
438
|
+
* same precedence rules without duplicating them.
|
|
439
|
+
*/
|
|
440
|
+
declare function filterResourcesForMcp<T extends {
|
|
441
|
+
name: string;
|
|
442
|
+
mcp?: boolean;
|
|
443
|
+
}>(resources: readonly T[], inputs: ResourceFilterInputs): T[];
|
|
264
444
|
declare const mcpPlugin: FastifyPluginAsync<McpPluginOptions>;
|
|
265
445
|
//#endregion
|
|
266
446
|
//#region src/integrations/mcp/resourceToTools.d.ts
|
|
@@ -284,4 +464,56 @@ interface ResourceToToolsConfig extends McpResourceConfig {
|
|
|
284
464
|
*/
|
|
285
465
|
declare function resourceToTools(resource: ResourceDefinition, config?: ResourceToToolsConfig): ToolDefinition[];
|
|
286
466
|
//#endregion
|
|
287
|
-
|
|
467
|
+
//#region src/integrations/mcp/tool-helpers.d.ts
|
|
468
|
+
/**
|
|
469
|
+
* Convert a controller response envelope into an MCP `CallToolResult`.
|
|
470
|
+
* Carries `meta` into the serialized payload so consumers see pagination
|
|
471
|
+
* totals, stripped-field arrays, etc.
|
|
472
|
+
*
|
|
473
|
+
* Errors are not represented here — controllers throw `ArcError` and the
|
|
474
|
+
* MCP tool wrapper catches them via {@link toCallToolError}.
|
|
475
|
+
*/
|
|
476
|
+
declare function toCallToolResult(result: IControllerResponse): CallToolResult;
|
|
477
|
+
/**
|
|
478
|
+
* Wrap a raw success payload as an MCP `CallToolResult`. Use when the
|
|
479
|
+
* tool produced a value directly (action handler return, aggregation
|
|
480
|
+
* rows, etc.) instead of an `IControllerResponse` envelope.
|
|
481
|
+
*
|
|
482
|
+
* Emits the value as JSON with no envelope — same no-envelope contract
|
|
483
|
+
* the HTTP wire follows. The `isError: true` flag on `CallToolResult`
|
|
484
|
+
* is the success/error discriminant for MCP, mirroring HTTP status.
|
|
485
|
+
*/
|
|
486
|
+
declare function toCallToolSuccess(value: unknown): CallToolResult;
|
|
487
|
+
/**
|
|
488
|
+
* Wrap an error as an MCP `CallToolResult` with the canonical
|
|
489
|
+
* `ErrorContract` shape inside the text payload. Single source of truth
|
|
490
|
+
* for MCP error serialization — every tool surface (CRUD, action, route,
|
|
491
|
+
* aggregation) routes through here so the JSON shape an agent sees is
|
|
492
|
+
* identical to what an HTTP client sees.
|
|
493
|
+
*
|
|
494
|
+
* Accepts:
|
|
495
|
+
* - An `ArcError` (or any `HttpError`-shaped throw) → routes through
|
|
496
|
+
* `toErrorContract()` for the canonical conversion.
|
|
497
|
+
* - A partial contract `{code, message, status, details?}` → used as-is.
|
|
498
|
+
* - Any other `Error` → falls back to `arc.internal_error` 500.
|
|
499
|
+
*/
|
|
500
|
+
declare function toCallToolError(input: Error | {
|
|
501
|
+
code: string;
|
|
502
|
+
message: string;
|
|
503
|
+
status?: number;
|
|
504
|
+
details?: ErrorContract["details"];
|
|
505
|
+
}): CallToolResult;
|
|
506
|
+
/**
|
|
507
|
+
* Build the canonical permission-denied `CallToolResult` for an MCP
|
|
508
|
+
* tool. Discriminates 401 (no session — "Authentication required") from
|
|
509
|
+
* 403 (session present, denied — "Permission denied"). Mirrors the
|
|
510
|
+
* status split the HTTP `errorHandler` plugin uses.
|
|
511
|
+
*/
|
|
512
|
+
declare function permissionDeniedResult(args: {
|
|
513
|
+
resource: string;
|
|
514
|
+
operation: string;
|
|
515
|
+
reason?: string;
|
|
516
|
+
session: McpAuthResult | null;
|
|
517
|
+
}): CallToolResult;
|
|
518
|
+
//#endregion
|
|
519
|
+
export { type AuthRef, type BetterAuthHandler, type BuildMcpToolsFromBridgesOptions, type CallToolResult, type CreateMcpServerConfig, type CrudDescriptionMeta, type CrudDescriptionOverride, type CrudOperation, type DefinePromptConfig, type DefineToolConfig, type FieldRuleEntry, type FieldRulesToZodOptions, type InvokeControllerOptions, type McpAuthResolver, type McpAuthResult, type McpBridge, type McpGuard, type McpOperation, type McpPluginOptions, type McpResourceConfig, type McpServerInstance, type PromptDefinition, type PromptResult, type ResourceToToolsConfig, type ToolAnnotations, type ToolContext, type ToolDefinition, bridgeToMcp, buildMcpToolsFromBridges, buildRequestContext, createMcpServer, customGuard, defaultCrudDescription, definePrompt, defineTool, denied, fieldRulesToZod, filterResourcesForMcp, getOrgId, getUserId, guard, hasOrg, invokeController, isAuthenticated, isOrg, mcpHandlerAdapter, mcpPlugin, permissionDeniedResult, requireAuth, requireOrg, requireOrgId, requireRole, resolveCrudDescription, resourceToTools, toCallToolError, toCallToolResult, toCallToolSuccess };
|