@strapi/core 5.46.0 → 5.47.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/dist/core-api/routes/index.js +2 -0
- package/dist/core-api/routes/index.js.map +1 -1
- package/dist/core-api/routes/index.mjs +2 -0
- package/dist/core-api/routes/index.mjs.map +1 -1
- package/dist/core-api/routes/validation/content-type.d.ts +13 -1
- package/dist/core-api/routes/validation/content-type.d.ts.map +1 -1
- package/dist/core-api/routes/validation/content-type.js +15 -2
- package/dist/core-api/routes/validation/content-type.js.map +1 -1
- package/dist/core-api/routes/validation/content-type.mjs +15 -2
- package/dist/core-api/routes/validation/content-type.mjs.map +1 -1
- package/dist/migrations/database/5.0.0-discard-drafts.d.ts +2 -1
- package/dist/migrations/database/5.0.0-discard-drafts.d.ts.map +1 -1
- package/dist/migrations/database/5.0.0-discard-drafts.js +64 -30
- package/dist/migrations/database/5.0.0-discard-drafts.js.map +1 -1
- package/dist/migrations/database/5.0.0-discard-drafts.mjs +64 -30
- package/dist/migrations/database/5.0.0-discard-drafts.mjs.map +1 -1
- package/dist/package.json.js +14 -12
- package/dist/package.json.js.map +1 -1
- package/dist/package.json.mjs +14 -12
- package/dist/package.json.mjs.map +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/index.mjs +3 -1
- package/dist/providers/index.mjs.map +1 -1
- package/dist/providers/mcp.d.ts +3 -0
- package/dist/providers/mcp.d.ts.map +1 -0
- package/dist/providers/mcp.js +39 -0
- package/dist/providers/mcp.js.map +1 -0
- package/dist/providers/mcp.mjs +37 -0
- package/dist/providers/mcp.mjs.map +1 -0
- package/dist/providers/session-manager.d.ts.map +1 -1
- package/dist/providers/session-manager.js +1 -2
- package/dist/providers/session-manager.js.map +1 -1
- package/dist/providers/session-manager.mjs +1 -2
- package/dist/providers/session-manager.mjs.map +1 -1
- package/dist/services/ai.d.ts.map +1 -1
- package/dist/services/ai.js +3 -0
- package/dist/services/ai.js.map +1 -1
- package/dist/services/ai.mjs +3 -0
- package/dist/services/ai.mjs.map +1 -1
- package/dist/services/document-service/draft-and-publish.d.ts +2 -16
- package/dist/services/document-service/draft-and-publish.d.ts.map +1 -1
- package/dist/services/document-service/draft-and-publish.js +0 -53
- package/dist/services/document-service/draft-and-publish.js.map +1 -1
- package/dist/services/document-service/draft-and-publish.mjs +2 -53
- package/dist/services/document-service/draft-and-publish.mjs.map +1 -1
- package/dist/services/document-service/params.d.ts +2 -2
- package/dist/services/document-service/params.d.ts.map +1 -1
- package/dist/services/document-service/publication-filter.d.ts +6 -0
- package/dist/services/document-service/publication-filter.d.ts.map +1 -0
- package/dist/services/document-service/publication-filter.js +20 -0
- package/dist/services/document-service/publication-filter.js.map +1 -0
- package/dist/services/document-service/publication-filter.mjs +15 -0
- package/dist/services/document-service/publication-filter.mjs.map +1 -0
- package/dist/services/document-service/transform/query.d.ts +1 -1
- package/dist/services/document-service/transform/query.d.ts.map +1 -1
- package/dist/services/document-service/transform/query.js +32 -19
- package/dist/services/document-service/transform/query.js.map +1 -1
- package/dist/services/document-service/transform/query.mjs +33 -20
- package/dist/services/document-service/transform/query.mjs.map +1 -1
- package/dist/services/entity-validator/blocks-validator.js +1 -1
- package/dist/services/entity-validator/blocks-validator.js.map +1 -1
- package/dist/services/entity-validator/blocks-validator.mjs +1 -1
- package/dist/services/entity-validator/blocks-validator.mjs.map +1 -1
- package/dist/services/mcp/authentication.d.ts +23 -0
- package/dist/services/mcp/authentication.d.ts.map +1 -0
- package/dist/services/mcp/authentication.js +45 -0
- package/dist/services/mcp/authentication.js.map +1 -0
- package/dist/services/mcp/authentication.mjs +43 -0
- package/dist/services/mcp/authentication.mjs.map +1 -0
- package/dist/services/mcp/handlers/handlePost.d.ts +4 -0
- package/dist/services/mcp/handlers/handlePost.d.ts.map +1 -0
- package/dist/services/mcp/handlers/handlePost.js +59 -0
- package/dist/services/mcp/handlers/handlePost.js.map +1 -0
- package/dist/services/mcp/handlers/handlePost.mjs +57 -0
- package/dist/services/mcp/handlers/handlePost.mjs.map +1 -0
- package/dist/services/mcp/handlers/types.d.ts +12 -0
- package/dist/services/mcp/handlers/types.d.ts.map +1 -0
- package/dist/services/mcp/index.d.ts +6 -0
- package/dist/services/mcp/index.d.ts.map +1 -0
- package/dist/services/mcp/index.js +101 -0
- package/dist/services/mcp/index.js.map +1 -0
- package/dist/services/mcp/index.mjs +99 -0
- package/dist/services/mcp/index.mjs.map +1 -0
- package/dist/services/mcp/internal/McpCapabilityDefinitionRegistry.d.ts +13 -0
- package/dist/services/mcp/internal/McpCapabilityDefinitionRegistry.d.ts.map +1 -0
- package/dist/services/mcp/internal/McpCapabilityDefinitionRegistry.js +53 -0
- package/dist/services/mcp/internal/McpCapabilityDefinitionRegistry.js.map +1 -0
- package/dist/services/mcp/internal/McpCapabilityDefinitionRegistry.mjs +51 -0
- package/dist/services/mcp/internal/McpCapabilityDefinitionRegistry.mjs.map +1 -0
- package/dist/services/mcp/internal/McpCapabilityRegistry.d.ts +43 -0
- package/dist/services/mcp/internal/McpCapabilityRegistry.d.ts.map +1 -0
- package/dist/services/mcp/internal/McpCapabilityRegistry.js +108 -0
- package/dist/services/mcp/internal/McpCapabilityRegistry.js.map +1 -0
- package/dist/services/mcp/internal/McpCapabilityRegistry.mjs +106 -0
- package/dist/services/mcp/internal/McpCapabilityRegistry.mjs.map +1 -0
- package/dist/services/mcp/internal/McpConfiguration.d.ts +11 -0
- package/dist/services/mcp/internal/McpConfiguration.d.ts.map +1 -0
- package/dist/services/mcp/internal/McpConfiguration.js +34 -0
- package/dist/services/mcp/internal/McpConfiguration.js.map +1 -0
- package/dist/services/mcp/internal/McpConfiguration.mjs +32 -0
- package/dist/services/mcp/internal/McpConfiguration.mjs.map +1 -0
- package/dist/services/mcp/internal/McpServerFactory.d.ts +37 -0
- package/dist/services/mcp/internal/McpServerFactory.d.ts.map +1 -0
- package/dist/services/mcp/internal/McpServerFactory.js +71 -0
- package/dist/services/mcp/internal/McpServerFactory.js.map +1 -0
- package/dist/services/mcp/internal/McpServerFactory.mjs +69 -0
- package/dist/services/mcp/internal/McpServerFactory.mjs.map +1 -0
- package/dist/services/mcp/internal/syncMcpSessionCapabilities.d.ts +21 -0
- package/dist/services/mcp/internal/syncMcpSessionCapabilities.d.ts.map +1 -0
- package/dist/services/mcp/internal/syncMcpSessionCapabilities.js +76 -0
- package/dist/services/mcp/internal/syncMcpSessionCapabilities.js.map +1 -0
- package/dist/services/mcp/internal/syncMcpSessionCapabilities.mjs +73 -0
- package/dist/services/mcp/internal/syncMcpSessionCapabilities.mjs.map +1 -0
- package/dist/services/mcp/metrics/metrics.d.ts +29 -0
- package/dist/services/mcp/metrics/metrics.d.ts.map +1 -0
- package/dist/services/mcp/metrics/metrics.js +97 -0
- package/dist/services/mcp/metrics/metrics.js.map +1 -0
- package/dist/services/mcp/metrics/metrics.mjs +88 -0
- package/dist/services/mcp/metrics/metrics.mjs.map +1 -0
- package/dist/services/mcp/metrics/normalizeMcpCapability.d.ts +11 -0
- package/dist/services/mcp/metrics/normalizeMcpCapability.d.ts.map +1 -0
- package/dist/services/mcp/metrics/normalizeMcpCapability.js +10 -0
- package/dist/services/mcp/metrics/normalizeMcpCapability.js.map +1 -0
- package/dist/services/mcp/metrics/normalizeMcpCapability.mjs +8 -0
- package/dist/services/mcp/metrics/normalizeMcpCapability.mjs.map +1 -0
- package/dist/services/mcp/metrics/wrapCapabilityHandlerForMetrics.d.ts +4 -0
- package/dist/services/mcp/metrics/wrapCapabilityHandlerForMetrics.d.ts.map +1 -0
- package/dist/services/mcp/metrics/wrapCapabilityHandlerForMetrics.js +27 -0
- package/dist/services/mcp/metrics/wrapCapabilityHandlerForMetrics.js.map +1 -0
- package/dist/services/mcp/metrics/wrapCapabilityHandlerForMetrics.mjs +25 -0
- package/dist/services/mcp/metrics/wrapCapabilityHandlerForMetrics.mjs.map +1 -0
- package/dist/services/mcp/middleware/oauthDiscoveryFallback.d.ts +3 -0
- package/dist/services/mcp/middleware/oauthDiscoveryFallback.d.ts.map +1 -0
- package/dist/services/mcp/middleware/oauthDiscoveryFallback.js +47 -0
- package/dist/services/mcp/middleware/oauthDiscoveryFallback.js.map +1 -0
- package/dist/services/mcp/middleware/oauthDiscoveryFallback.mjs +45 -0
- package/dist/services/mcp/middleware/oauthDiscoveryFallback.mjs.map +1 -0
- package/dist/services/mcp/prompt-registry.d.ts +16 -0
- package/dist/services/mcp/prompt-registry.d.ts.map +1 -0
- package/dist/services/mcp/prompt-registry.js +77 -0
- package/dist/services/mcp/prompt-registry.js.map +1 -0
- package/dist/services/mcp/prompt-registry.mjs +75 -0
- package/dist/services/mcp/prompt-registry.mjs.map +1 -0
- package/dist/services/mcp/resource-registry.d.ts +14 -0
- package/dist/services/mcp/resource-registry.d.ts.map +1 -0
- package/dist/services/mcp/resource-registry.js +67 -0
- package/dist/services/mcp/resource-registry.js.map +1 -0
- package/dist/services/mcp/resource-registry.mjs +65 -0
- package/dist/services/mcp/resource-registry.mjs.map +1 -0
- package/dist/services/mcp/routes.d.ts +11 -0
- package/dist/services/mcp/routes.d.ts.map +1 -0
- package/dist/services/mcp/routes.js +58 -0
- package/dist/services/mcp/routes.js.map +1 -0
- package/dist/services/mcp/routes.mjs +56 -0
- package/dist/services/mcp/routes.mjs.map +1 -0
- package/dist/services/mcp/tool-registry.d.ts +25 -0
- package/dist/services/mcp/tool-registry.d.ts.map +1 -0
- package/dist/services/mcp/tool-registry.js +102 -0
- package/dist/services/mcp/tool-registry.js.map +1 -0
- package/dist/services/mcp/tool-registry.mjs +99 -0
- package/dist/services/mcp/tool-registry.mjs.map +1 -0
- package/dist/services/mcp/tools/log.d.ts +87 -0
- package/dist/services/mcp/tools/log.d.ts.map +1 -0
- package/dist/services/mcp/tools/log.js +88 -0
- package/dist/services/mcp/tools/log.js.map +1 -0
- package/dist/services/mcp/tools/log.mjs +86 -0
- package/dist/services/mcp/tools/log.mjs.map +1 -0
- package/dist/services/mcp/utils/createSafeCapabilityRegistration.d.ts +36 -0
- package/dist/services/mcp/utils/createSafeCapabilityRegistration.d.ts.map +1 -0
- package/dist/services/mcp/utils/createSafeCapabilityRegistration.js +59 -0
- package/dist/services/mcp/utils/createSafeCapabilityRegistration.js.map +1 -0
- package/dist/services/mcp/utils/createSafeCapabilityRegistration.mjs +56 -0
- package/dist/services/mcp/utils/createSafeCapabilityRegistration.mjs.map +1 -0
- package/dist/services/mcp/utils/jsonRpcErrors.d.ts +22 -0
- package/dist/services/mcp/utils/jsonRpcErrors.d.ts.map +1 -0
- package/dist/services/mcp/utils/jsonRpcErrors.js +25 -0
- package/dist/services/mcp/utils/jsonRpcErrors.js.map +1 -0
- package/dist/services/mcp/utils/jsonRpcErrors.mjs +23 -0
- package/dist/services/mcp/utils/jsonRpcErrors.mjs.map +1 -0
- package/dist/services/mcp/utils/safeHandlerWrapper.d.ts +18 -0
- package/dist/services/mcp/utils/safeHandlerWrapper.d.ts.map +1 -0
- package/dist/services/mcp/utils/safeHandlerWrapper.js +29 -0
- package/dist/services/mcp/utils/safeHandlerWrapper.js.map +1 -0
- package/dist/services/mcp/utils/safeHandlerWrapper.mjs +27 -0
- package/dist/services/mcp/utils/safeHandlerWrapper.mjs.map +1 -0
- package/dist/services/mcp/utils/sendJsonRpcError.d.ts +5 -0
- package/dist/services/mcp/utils/sendJsonRpcError.d.ts.map +1 -0
- package/dist/services/mcp/utils/sendJsonRpcError.js +23 -0
- package/dist/services/mcp/utils/sendJsonRpcError.js.map +1 -0
- package/dist/services/mcp/utils/sendJsonRpcError.mjs +21 -0
- package/dist/services/mcp/utils/sendJsonRpcError.mjs.map +1 -0
- package/dist/services/mcp/utils/withTimeout.d.ts +7 -0
- package/dist/services/mcp/utils/withTimeout.d.ts.map +1 -0
- package/dist/services/mcp/utils/withTimeout.js +23 -0
- package/dist/services/mcp/utils/withTimeout.js.map +1 -0
- package/dist/services/mcp/utils/withTimeout.mjs +21 -0
- package/dist/services/mcp/utils/withTimeout.mjs.map +1 -0
- package/dist/services/metrics/index.d.ts.map +1 -1
- package/dist/services/metrics/index.js +3 -1
- package/dist/services/metrics/index.js.map +1 -1
- package/dist/services/metrics/index.mjs +3 -1
- package/dist/services/metrics/index.mjs.map +1 -1
- package/package.json +14 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.mjs","sources":["../../../src/services/mcp/routes.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { McpConfiguration } from './internal/McpConfiguration';\nimport { sendJsonRpcError } from './utils/sendJsonRpcError';\n\n/**\n * Handler for unsupported HTTP methods on /mcp endpoint.\n * Returns JSON-RPC error instead of plain text so MCP clients can parse it.\n */\nconst handleMethodNotAllowed: Core.MiddlewareHandler = async (ctx) => {\n // Opt out of Koa's response phase — sendJsonRpcError writes directly to ctx.res.\n ctx.respond = false;\n // ctx.set() writes to Koa's in-memory headers which are never flushed when ctx.respond = false.\n // Use res.setHeader() so the header is included when sendJsonRpcError calls res.writeHead().\n ctx.res.setHeader('Allow', 'POST');\n sendJsonRpcError(ctx.res, 'METHOD_NOT_ALLOWED');\n};\n\nexport type McpRouteHandlers = {\n handlePost: Core.MiddlewareHandler;\n};\n\n/**\n * Creates MCP route definitions for registration with Strapi server.\n * @internal\n */\nexport const createMcpRoutes = (\n config: McpConfiguration,\n handlers: McpRouteHandlers\n): Omit<Core.Route, 'info'>[] => {\n const noAuth = { auth: false } as const;\n\n return [\n { method: 'POST', path: config.path, handler: handlers.handlePost, config: noAuth },\n { method: 'GET', path: config.path, handler: handleMethodNotAllowed, config: noAuth },\n { method: 'DELETE', path: config.path, handler: handleMethodNotAllowed, config: noAuth },\n { method: 'PUT', path: config.path, handler: handleMethodNotAllowed, config: noAuth },\n { method: 'PATCH', path: config.path, handler: handleMethodNotAllowed, config: noAuth },\n ];\n};\n"],"names":["handleMethodNotAllowed","ctx","respond","res","setHeader","sendJsonRpcError","createMcpRoutes","config","handlers","noAuth","auth","method","path","handler","handlePost"],"mappings":";;AAIA;;;IAIA,MAAMA,yBAAiD,OAAOC,GAAAA,GAAAA;;AAE5DA,IAAAA,GAAAA,CAAIC,OAAO,GAAG,KAAA;;;AAGdD,IAAAA,GAAAA,CAAIE,GAAG,CAACC,SAAS,CAAC,OAAA,EAAS,MAAA,CAAA;IAC3BC,gBAAAA,CAAiBJ,GAAAA,CAAIE,GAAG,EAAE,oBAAA,CAAA;AAC5B,CAAA;AAMA;;;AAGC,IACM,MAAMG,eAAAA,GAAkB,CAC7BC,MAAAA,EACAC,QAAAA,GAAAA;AAEA,IAAA,MAAMC,MAAAA,GAAS;QAAEC,IAAAA,EAAM;AAAM,KAAA;IAE7B,OAAO;AACL,QAAA;YAAEC,MAAAA,EAAQ,MAAA;AAAQC,YAAAA,IAAAA,EAAML,OAAOK,IAAI;AAAEC,YAAAA,OAAAA,EAASL,SAASM,UAAU;YAAEP,MAAAA,EAAQE;AAAO,SAAA;AAClF,QAAA;YAAEE,MAAAA,EAAQ,KAAA;AAAOC,YAAAA,IAAAA,EAAML,OAAOK,IAAI;YAAEC,OAAAA,EAASb,sBAAAA;YAAwBO,MAAAA,EAAQE;AAAO,SAAA;AACpF,QAAA;YAAEE,MAAAA,EAAQ,QAAA;AAAUC,YAAAA,IAAAA,EAAML,OAAOK,IAAI;YAAEC,OAAAA,EAASb,sBAAAA;YAAwBO,MAAAA,EAAQE;AAAO,SAAA;AACvF,QAAA;YAAEE,MAAAA,EAAQ,KAAA;AAAOC,YAAAA,IAAAA,EAAML,OAAOK,IAAI;YAAEC,OAAAA,EAASb,sBAAAA;YAAwBO,MAAAA,EAAQE;AAAO,SAAA;AACpF,QAAA;YAAEE,MAAAA,EAAQ,OAAA;AAASC,YAAAA,IAAAA,EAAML,OAAOK,IAAI;YAAEC,OAAAA,EAASb,sBAAAA;YAAwBO,MAAAA,EAAQE;AAAO;AACvF,KAAA;AACH;;;;"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Core, Modules } from '@strapi/types';
|
|
3
|
+
import { z } from '@strapi/utils';
|
|
4
|
+
import { McpCapabilityDefinitionRegistry } from './internal/McpCapabilityDefinitionRegistry';
|
|
5
|
+
import { type McpCapabilityRegistry, McpCapabilityRegistryBase } from './internal/McpCapabilityRegistry';
|
|
6
|
+
import type { McpAdminTokenAbility } from './authentication';
|
|
7
|
+
export declare function makeMcpToolDefinition<Name extends string, Title extends string, Description extends string, OutputSchema extends z.ZodObject<z.ZodRawShape>, InputSchema extends z.ZodObject<z.ZodRawShape> | undefined = undefined, Access extends Modules.MCP.McpCapabilityAccess = Modules.MCP.McpCapabilityAccess>(tool: {
|
|
8
|
+
name: Name;
|
|
9
|
+
title: Title;
|
|
10
|
+
description: Description;
|
|
11
|
+
resolveInputSchema?: (context: Modules.MCP.McpHandlerContext) => InputSchema;
|
|
12
|
+
resolveOutputSchema: (context: Modules.MCP.McpHandlerContext) => OutputSchema;
|
|
13
|
+
createHandler: (strapi: Core.Strapi, context: Modules.MCP.McpHandlerContext) => Modules.MCP.McpToolHandler<NoInfer<InputSchema>, NoInfer<OutputSchema>>;
|
|
14
|
+
} & Access): Modules.MCP.McpToolDefinition<Name, InputSchema, OutputSchema, Title, Description> & Access;
|
|
15
|
+
export declare class McpToolRegistry extends McpCapabilityRegistryBase<'tool', Modules.MCP.McpToolDefinition, RegisteredTool> implements McpCapabilityRegistry {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(ctx: {
|
|
18
|
+
strapi: Core.Strapi;
|
|
19
|
+
definitions: McpCapabilityDefinitionRegistry<'tool', Modules.MCP.McpToolDefinition>;
|
|
20
|
+
ability: McpAdminTokenAbility;
|
|
21
|
+
user: Modules.MCP.McpHandlerContext['user'];
|
|
22
|
+
});
|
|
23
|
+
bind(mcpServer: McpServer): void;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=tool-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../../src/services/mcp/tool-registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzF,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EACL,KAAK,qBAAqB,EAC1B,yBAAyB,EAC1B,MAAM,kCAAkC,CAAC;AAG1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,wBAAgB,qBAAqB,CACnC,IAAI,SAAS,MAAM,EACnB,KAAK,SAAS,MAAM,EACpB,WAAW,SAAS,MAAM,EAC1B,YAAY,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,EAC/C,WAAW,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,SAAS,GAAG,SAAS,EACtE,MAAM,SAAS,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAEhF,IAAI,EAAE;IACJ,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,WAAW,CAAC;IAC7E,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,YAAY,CAAC;IAC9E,aAAa,EAAE,CACb,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,KACnC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;CAC9E,GAAG,MAAM,GACT,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,MAAM,CAS7F;AAED,qBAAa,eACX,SAAQ,yBAAyB,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,cAAc,CACvF,YAAW,qBAAqB;;gBAQpB,GAAG,EAAE;QACf,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;QACpB,WAAW,EAAE,+BAA+B,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;QACpF,OAAO,EAAE,oBAAoB,CAAC;QAC9B,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;KAC7C;IAOD,IAAI,CAAC,SAAS,EAAE,SAAS;CAwE1B"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var McpCapabilityRegistry = require('./internal/McpCapabilityRegistry.js');
|
|
4
|
+
var wrapCapabilityHandlerForMetrics = require('./metrics/wrapCapabilityHandlerForMetrics.js');
|
|
5
|
+
var createSafeCapabilityRegistration = require('./utils/createSafeCapabilityRegistration.js');
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line import/extensions
|
|
8
|
+
function _class_private_field_loose_base(receiver, privateKey) {
|
|
9
|
+
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
|
|
10
|
+
throw new TypeError("attempted to use private field on non-instance");
|
|
11
|
+
}
|
|
12
|
+
return receiver;
|
|
13
|
+
}
|
|
14
|
+
var id = 0;
|
|
15
|
+
function _class_private_field_loose_key(name) {
|
|
16
|
+
return "__private_" + id++ + "_" + name;
|
|
17
|
+
}
|
|
18
|
+
function makeMcpToolDefinition(tool) {
|
|
19
|
+
return tool;
|
|
20
|
+
}
|
|
21
|
+
var _strapi = /*#__PURE__*/ _class_private_field_loose_key("_strapi"), _ability = /*#__PURE__*/ _class_private_field_loose_key("_ability"), _user = /*#__PURE__*/ _class_private_field_loose_key("_user");
|
|
22
|
+
class McpToolRegistry extends McpCapabilityRegistry.McpCapabilityRegistryBase {
|
|
23
|
+
bind(mcpServer) {
|
|
24
|
+
const strapi = _class_private_field_loose_base(this, _strapi)[_strapi];
|
|
25
|
+
super.register((definition)=>{
|
|
26
|
+
const { name, title, description, resolveInputSchema, resolveOutputSchema, createHandler } = definition;
|
|
27
|
+
// Bind the session ability and token owner into the handler context so handlers can enforce
|
|
28
|
+
// field-level and entity-level permission checks and set creator fields.
|
|
29
|
+
const context = {
|
|
30
|
+
userAbility: _class_private_field_loose_base(this, _ability)[_ability],
|
|
31
|
+
user: _class_private_field_loose_base(this, _user)[_user]
|
|
32
|
+
};
|
|
33
|
+
const createHandlerWithContext = (strapi)=>createHandler(strapi, context);
|
|
34
|
+
return createSafeCapabilityRegistration.createSafeCapabilityRegistration({
|
|
35
|
+
strapi,
|
|
36
|
+
capabilityType: 'Tool',
|
|
37
|
+
name,
|
|
38
|
+
createHandler: createHandlerWithContext,
|
|
39
|
+
createFallbackHandler (errorMessage) {
|
|
40
|
+
return async ()=>({
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: 'text',
|
|
44
|
+
text: `Tool "${name}" failed to initialize: ${errorMessage}`
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
isError: true
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
createErrorResult (error) {
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
{
|
|
54
|
+
type: 'text',
|
|
55
|
+
text: `Tool "${name}" execution failed: ${error.message}`
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
isError: true
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
registerWithSdk (safeHandler) {
|
|
62
|
+
const inputSchema = resolveInputSchema !== undefined ? resolveInputSchema(context) : undefined;
|
|
63
|
+
const outputSchema = resolveOutputSchema(context);
|
|
64
|
+
// Adapt from our object-literal handler `({ args, extra })` to
|
|
65
|
+
// the MCP SDK's positional form `(args, extra)` / `(extra)`.
|
|
66
|
+
const baseHandler = inputSchema !== undefined ? (args, extra)=>safeHandler({
|
|
67
|
+
args,
|
|
68
|
+
extra
|
|
69
|
+
}) : (extra)=>safeHandler({
|
|
70
|
+
extra
|
|
71
|
+
});
|
|
72
|
+
const sdkHandler = wrapCapabilityHandlerForMetrics.wrapCapabilityHandlerForMetrics(strapi, 'tool', name, definition.telemetry, baseHandler);
|
|
73
|
+
return mcpServer.registerTool(name, {
|
|
74
|
+
title,
|
|
75
|
+
description,
|
|
76
|
+
inputSchema,
|
|
77
|
+
outputSchema
|
|
78
|
+
}, sdkHandler);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
constructor(ctx){
|
|
84
|
+
super(ctx.definitions), Object.defineProperty(this, _strapi, {
|
|
85
|
+
writable: true,
|
|
86
|
+
value: void 0
|
|
87
|
+
}), Object.defineProperty(this, _ability, {
|
|
88
|
+
writable: true,
|
|
89
|
+
value: void 0
|
|
90
|
+
}), Object.defineProperty(this, _user, {
|
|
91
|
+
writable: true,
|
|
92
|
+
value: void 0
|
|
93
|
+
});
|
|
94
|
+
_class_private_field_loose_base(this, _strapi)[_strapi] = ctx.strapi;
|
|
95
|
+
_class_private_field_loose_base(this, _ability)[_ability] = ctx.ability;
|
|
96
|
+
_class_private_field_loose_base(this, _user)[_user] = ctx.user;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
exports.McpToolRegistry = McpToolRegistry;
|
|
101
|
+
exports.makeMcpToolDefinition = makeMcpToolDefinition;
|
|
102
|
+
//# sourceMappingURL=tool-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-registry.js","sources":["../../../src/services/mcp/tool-registry.ts"],"sourcesContent":["// eslint-disable-next-line import/extensions\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Core, Modules } from '@strapi/types';\nimport { z } from '@strapi/utils';\nimport { McpCapabilityDefinitionRegistry } from './internal/McpCapabilityDefinitionRegistry';\nimport {\n type McpCapabilityRegistry,\n McpCapabilityRegistryBase,\n} from './internal/McpCapabilityRegistry';\nimport { wrapCapabilityHandlerForMetrics } from './metrics/wrapCapabilityHandlerForMetrics';\nimport { createSafeCapabilityRegistration } from './utils/createSafeCapabilityRegistration';\nimport type { McpAdminTokenAbility } from './authentication';\n\nexport function makeMcpToolDefinition<\n Name extends string,\n Title extends string,\n Description extends string,\n OutputSchema extends z.ZodObject<z.ZodRawShape>,\n InputSchema extends z.ZodObject<z.ZodRawShape> | undefined = undefined,\n Access extends Modules.MCP.McpCapabilityAccess = Modules.MCP.McpCapabilityAccess,\n>(\n tool: {\n name: Name;\n title: Title;\n description: Description;\n resolveInputSchema?: (context: Modules.MCP.McpHandlerContext) => InputSchema;\n resolveOutputSchema: (context: Modules.MCP.McpHandlerContext) => OutputSchema;\n createHandler: (\n strapi: Core.Strapi,\n context: Modules.MCP.McpHandlerContext\n ) => Modules.MCP.McpToolHandler<NoInfer<InputSchema>, NoInfer<OutputSchema>>;\n } & Access\n): Modules.MCP.McpToolDefinition<Name, InputSchema, OutputSchema, Title, Description> & Access {\n return tool as Modules.MCP.McpToolDefinition<\n Name,\n InputSchema,\n OutputSchema,\n Title,\n Description\n > &\n Access;\n}\n\nexport class McpToolRegistry\n extends McpCapabilityRegistryBase<'tool', Modules.MCP.McpToolDefinition, RegisteredTool>\n implements McpCapabilityRegistry\n{\n #strapi: Core.Strapi;\n\n #ability: McpAdminTokenAbility;\n\n #user: Modules.MCP.McpHandlerContext['user'];\n\n constructor(ctx: {\n strapi: Core.Strapi;\n definitions: McpCapabilityDefinitionRegistry<'tool', Modules.MCP.McpToolDefinition>;\n ability: McpAdminTokenAbility;\n user: Modules.MCP.McpHandlerContext['user'];\n }) {\n super(ctx.definitions);\n this.#strapi = ctx.strapi;\n this.#ability = ctx.ability;\n this.#user = ctx.user;\n }\n\n bind(mcpServer: McpServer) {\n const strapi = this.#strapi;\n\n super.register((definition) => {\n const { name, title, description, resolveInputSchema, resolveOutputSchema, createHandler } =\n definition;\n\n // Bind the session ability and token owner into the handler context so handlers can enforce\n // field-level and entity-level permission checks and set creator fields.\n const context: Modules.MCP.McpHandlerContext = {\n userAbility: this.#ability,\n user: this.#user,\n };\n const createHandlerWithContext = (strapi: Core.Strapi) => createHandler(strapi, context);\n\n return createSafeCapabilityRegistration({\n strapi,\n capabilityType: 'Tool',\n name,\n createHandler: createHandlerWithContext,\n createFallbackHandler(errorMessage) {\n return async () => ({\n content: [\n {\n type: 'text' as const,\n text: `Tool \"${name}\" failed to initialize: ${errorMessage}`,\n },\n ],\n isError: true,\n });\n },\n createErrorResult(error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Tool \"${name}\" execution failed: ${error.message}`,\n },\n ],\n isError: true,\n };\n },\n registerWithSdk(safeHandler) {\n const inputSchema =\n resolveInputSchema !== undefined ? resolveInputSchema(context) : undefined;\n const outputSchema = resolveOutputSchema(context);\n\n // Adapt from our object-literal handler `({ args, extra })` to\n // the MCP SDK's positional form `(args, extra)` / `(extra)`.\n const baseHandler =\n inputSchema !== undefined\n ? (args: unknown, extra: unknown) =>\n safeHandler({ args, extra } as Parameters<typeof safeHandler>[0])\n : (extra: unknown) => safeHandler({ extra } as Parameters<typeof safeHandler>[0]);\n\n const sdkHandler = wrapCapabilityHandlerForMetrics(\n strapi,\n 'tool',\n name,\n definition.telemetry,\n baseHandler\n );\n\n return mcpServer.registerTool(\n name,\n { title, description, inputSchema, outputSchema },\n sdkHandler\n );\n },\n });\n });\n }\n}\n"],"names":["makeMcpToolDefinition","tool","McpToolRegistry","McpCapabilityRegistryBase","bind","mcpServer","strapi","register","definition","name","title","description","resolveInputSchema","resolveOutputSchema","createHandler","context","userAbility","user","createHandlerWithContext","createSafeCapabilityRegistration","capabilityType","createFallbackHandler","errorMessage","content","type","text","isError","createErrorResult","error","message","registerWithSdk","safeHandler","inputSchema","undefined","outputSchema","baseHandler","args","extra","sdkHandler","wrapCapabilityHandlerForMetrics","telemetry","registerTool","ctx","definitions","ability"],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { McpCapabilityRegistryBase } from './internal/McpCapabilityRegistry.mjs';
|
|
2
|
+
import { wrapCapabilityHandlerForMetrics } from './metrics/wrapCapabilityHandlerForMetrics.mjs';
|
|
3
|
+
import { createSafeCapabilityRegistration } from './utils/createSafeCapabilityRegistration.mjs';
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line import/extensions
|
|
6
|
+
function _class_private_field_loose_base(receiver, privateKey) {
|
|
7
|
+
if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
|
|
8
|
+
throw new TypeError("attempted to use private field on non-instance");
|
|
9
|
+
}
|
|
10
|
+
return receiver;
|
|
11
|
+
}
|
|
12
|
+
var id = 0;
|
|
13
|
+
function _class_private_field_loose_key(name) {
|
|
14
|
+
return "__private_" + id++ + "_" + name;
|
|
15
|
+
}
|
|
16
|
+
function makeMcpToolDefinition(tool) {
|
|
17
|
+
return tool;
|
|
18
|
+
}
|
|
19
|
+
var _strapi = /*#__PURE__*/ _class_private_field_loose_key("_strapi"), _ability = /*#__PURE__*/ _class_private_field_loose_key("_ability"), _user = /*#__PURE__*/ _class_private_field_loose_key("_user");
|
|
20
|
+
class McpToolRegistry extends McpCapabilityRegistryBase {
|
|
21
|
+
bind(mcpServer) {
|
|
22
|
+
const strapi = _class_private_field_loose_base(this, _strapi)[_strapi];
|
|
23
|
+
super.register((definition)=>{
|
|
24
|
+
const { name, title, description, resolveInputSchema, resolveOutputSchema, createHandler } = definition;
|
|
25
|
+
// Bind the session ability and token owner into the handler context so handlers can enforce
|
|
26
|
+
// field-level and entity-level permission checks and set creator fields.
|
|
27
|
+
const context = {
|
|
28
|
+
userAbility: _class_private_field_loose_base(this, _ability)[_ability],
|
|
29
|
+
user: _class_private_field_loose_base(this, _user)[_user]
|
|
30
|
+
};
|
|
31
|
+
const createHandlerWithContext = (strapi)=>createHandler(strapi, context);
|
|
32
|
+
return createSafeCapabilityRegistration({
|
|
33
|
+
strapi,
|
|
34
|
+
capabilityType: 'Tool',
|
|
35
|
+
name,
|
|
36
|
+
createHandler: createHandlerWithContext,
|
|
37
|
+
createFallbackHandler (errorMessage) {
|
|
38
|
+
return async ()=>({
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: 'text',
|
|
42
|
+
text: `Tool "${name}" failed to initialize: ${errorMessage}`
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
isError: true
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
createErrorResult (error) {
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: `Tool "${name}" execution failed: ${error.message}`
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
isError: true
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
registerWithSdk (safeHandler) {
|
|
60
|
+
const inputSchema = resolveInputSchema !== undefined ? resolveInputSchema(context) : undefined;
|
|
61
|
+
const outputSchema = resolveOutputSchema(context);
|
|
62
|
+
// Adapt from our object-literal handler `({ args, extra })` to
|
|
63
|
+
// the MCP SDK's positional form `(args, extra)` / `(extra)`.
|
|
64
|
+
const baseHandler = inputSchema !== undefined ? (args, extra)=>safeHandler({
|
|
65
|
+
args,
|
|
66
|
+
extra
|
|
67
|
+
}) : (extra)=>safeHandler({
|
|
68
|
+
extra
|
|
69
|
+
});
|
|
70
|
+
const sdkHandler = wrapCapabilityHandlerForMetrics(strapi, 'tool', name, definition.telemetry, baseHandler);
|
|
71
|
+
return mcpServer.registerTool(name, {
|
|
72
|
+
title,
|
|
73
|
+
description,
|
|
74
|
+
inputSchema,
|
|
75
|
+
outputSchema
|
|
76
|
+
}, sdkHandler);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
constructor(ctx){
|
|
82
|
+
super(ctx.definitions), Object.defineProperty(this, _strapi, {
|
|
83
|
+
writable: true,
|
|
84
|
+
value: void 0
|
|
85
|
+
}), Object.defineProperty(this, _ability, {
|
|
86
|
+
writable: true,
|
|
87
|
+
value: void 0
|
|
88
|
+
}), Object.defineProperty(this, _user, {
|
|
89
|
+
writable: true,
|
|
90
|
+
value: void 0
|
|
91
|
+
});
|
|
92
|
+
_class_private_field_loose_base(this, _strapi)[_strapi] = ctx.strapi;
|
|
93
|
+
_class_private_field_loose_base(this, _ability)[_ability] = ctx.ability;
|
|
94
|
+
_class_private_field_loose_base(this, _user)[_user] = ctx.user;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export { McpToolRegistry, makeMcpToolDefinition };
|
|
99
|
+
//# sourceMappingURL=tool-registry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-registry.mjs","sources":["../../../src/services/mcp/tool-registry.ts"],"sourcesContent":["// eslint-disable-next-line import/extensions\nimport type { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Core, Modules } from '@strapi/types';\nimport { z } from '@strapi/utils';\nimport { McpCapabilityDefinitionRegistry } from './internal/McpCapabilityDefinitionRegistry';\nimport {\n type McpCapabilityRegistry,\n McpCapabilityRegistryBase,\n} from './internal/McpCapabilityRegistry';\nimport { wrapCapabilityHandlerForMetrics } from './metrics/wrapCapabilityHandlerForMetrics';\nimport { createSafeCapabilityRegistration } from './utils/createSafeCapabilityRegistration';\nimport type { McpAdminTokenAbility } from './authentication';\n\nexport function makeMcpToolDefinition<\n Name extends string,\n Title extends string,\n Description extends string,\n OutputSchema extends z.ZodObject<z.ZodRawShape>,\n InputSchema extends z.ZodObject<z.ZodRawShape> | undefined = undefined,\n Access extends Modules.MCP.McpCapabilityAccess = Modules.MCP.McpCapabilityAccess,\n>(\n tool: {\n name: Name;\n title: Title;\n description: Description;\n resolveInputSchema?: (context: Modules.MCP.McpHandlerContext) => InputSchema;\n resolveOutputSchema: (context: Modules.MCP.McpHandlerContext) => OutputSchema;\n createHandler: (\n strapi: Core.Strapi,\n context: Modules.MCP.McpHandlerContext\n ) => Modules.MCP.McpToolHandler<NoInfer<InputSchema>, NoInfer<OutputSchema>>;\n } & Access\n): Modules.MCP.McpToolDefinition<Name, InputSchema, OutputSchema, Title, Description> & Access {\n return tool as Modules.MCP.McpToolDefinition<\n Name,\n InputSchema,\n OutputSchema,\n Title,\n Description\n > &\n Access;\n}\n\nexport class McpToolRegistry\n extends McpCapabilityRegistryBase<'tool', Modules.MCP.McpToolDefinition, RegisteredTool>\n implements McpCapabilityRegistry\n{\n #strapi: Core.Strapi;\n\n #ability: McpAdminTokenAbility;\n\n #user: Modules.MCP.McpHandlerContext['user'];\n\n constructor(ctx: {\n strapi: Core.Strapi;\n definitions: McpCapabilityDefinitionRegistry<'tool', Modules.MCP.McpToolDefinition>;\n ability: McpAdminTokenAbility;\n user: Modules.MCP.McpHandlerContext['user'];\n }) {\n super(ctx.definitions);\n this.#strapi = ctx.strapi;\n this.#ability = ctx.ability;\n this.#user = ctx.user;\n }\n\n bind(mcpServer: McpServer) {\n const strapi = this.#strapi;\n\n super.register((definition) => {\n const { name, title, description, resolveInputSchema, resolveOutputSchema, createHandler } =\n definition;\n\n // Bind the session ability and token owner into the handler context so handlers can enforce\n // field-level and entity-level permission checks and set creator fields.\n const context: Modules.MCP.McpHandlerContext = {\n userAbility: this.#ability,\n user: this.#user,\n };\n const createHandlerWithContext = (strapi: Core.Strapi) => createHandler(strapi, context);\n\n return createSafeCapabilityRegistration({\n strapi,\n capabilityType: 'Tool',\n name,\n createHandler: createHandlerWithContext,\n createFallbackHandler(errorMessage) {\n return async () => ({\n content: [\n {\n type: 'text' as const,\n text: `Tool \"${name}\" failed to initialize: ${errorMessage}`,\n },\n ],\n isError: true,\n });\n },\n createErrorResult(error) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Tool \"${name}\" execution failed: ${error.message}`,\n },\n ],\n isError: true,\n };\n },\n registerWithSdk(safeHandler) {\n const inputSchema =\n resolveInputSchema !== undefined ? resolveInputSchema(context) : undefined;\n const outputSchema = resolveOutputSchema(context);\n\n // Adapt from our object-literal handler `({ args, extra })` to\n // the MCP SDK's positional form `(args, extra)` / `(extra)`.\n const baseHandler =\n inputSchema !== undefined\n ? (args: unknown, extra: unknown) =>\n safeHandler({ args, extra } as Parameters<typeof safeHandler>[0])\n : (extra: unknown) => safeHandler({ extra } as Parameters<typeof safeHandler>[0]);\n\n const sdkHandler = wrapCapabilityHandlerForMetrics(\n strapi,\n 'tool',\n name,\n definition.telemetry,\n baseHandler\n );\n\n return mcpServer.registerTool(\n name,\n { title, description, inputSchema, outputSchema },\n sdkHandler\n );\n },\n });\n });\n }\n}\n"],"names":["makeMcpToolDefinition","tool","McpToolRegistry","McpCapabilityRegistryBase","bind","mcpServer","strapi","register","definition","name","title","description","resolveInputSchema","resolveOutputSchema","createHandler","context","userAbility","user","createHandlerWithContext","createSafeCapabilityRegistration","capabilityType","createFallbackHandler","errorMessage","content","type","text","isError","createErrorResult","error","message","registerWithSdk","safeHandler","inputSchema","undefined","outputSchema","baseHandler","args","extra","sdkHandler","wrapCapabilityHandlerForMetrics","telemetry","registerTool","ctx","definitions","ability"],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from '@strapi/utils';
|
|
2
|
+
export declare const logToolDefinition: {
|
|
3
|
+
name: "log";
|
|
4
|
+
telemetry?: import("@strapi/types/dist/modules/mcp").McpCapabilityTelemetry | undefined;
|
|
5
|
+
} & {
|
|
6
|
+
devModeOnly: true;
|
|
7
|
+
auth?: undefined;
|
|
8
|
+
} & {
|
|
9
|
+
title: "Strapi Log";
|
|
10
|
+
description: "Logs a message to the Strapi logger with specified level";
|
|
11
|
+
resolveInputSchema?: import("@strapi/types/dist/modules/mcp").McpToolSchemaResolver<z.ZodObject<{
|
|
12
|
+
message: z.ZodString;
|
|
13
|
+
level: z.ZodDefault<z.ZodEnum<{
|
|
14
|
+
http: "http";
|
|
15
|
+
info: "info";
|
|
16
|
+
error: "error";
|
|
17
|
+
log: "log";
|
|
18
|
+
warn: "warn";
|
|
19
|
+
}>>;
|
|
20
|
+
}, z.core.$strip>> | undefined;
|
|
21
|
+
resolveOutputSchema: import("@strapi/types/dist/modules/mcp").McpToolSchemaResolver<z.ZodObject<{
|
|
22
|
+
status: z.ZodString;
|
|
23
|
+
message: z.ZodString;
|
|
24
|
+
level: z.ZodString;
|
|
25
|
+
timestamp: z.ZodString;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
createHandler: (strapi: import("@strapi/types/dist/core").Strapi, context: import("@strapi/types/dist/modules/mcp").McpHandlerContext) => import("@strapi/types/dist/modules/mcp").McpToolHandler<NoInfer<z.ZodObject<{
|
|
28
|
+
message: z.ZodString;
|
|
29
|
+
level: z.ZodDefault<z.ZodEnum<{
|
|
30
|
+
http: "http";
|
|
31
|
+
info: "info";
|
|
32
|
+
error: "error";
|
|
33
|
+
log: "log";
|
|
34
|
+
warn: "warn";
|
|
35
|
+
}>>;
|
|
36
|
+
}, z.core.$strip>>, NoInfer<z.ZodObject<{
|
|
37
|
+
status: z.ZodString;
|
|
38
|
+
message: z.ZodString;
|
|
39
|
+
level: z.ZodString;
|
|
40
|
+
timestamp: z.ZodString;
|
|
41
|
+
}, z.core.$strip>>>;
|
|
42
|
+
} & {
|
|
43
|
+
name: "log";
|
|
44
|
+
title: "Strapi Log";
|
|
45
|
+
description: "Logs a message to the Strapi logger with specified level";
|
|
46
|
+
resolveInputSchema: () => z.ZodObject<{
|
|
47
|
+
message: z.ZodString;
|
|
48
|
+
level: z.ZodDefault<z.ZodEnum<{
|
|
49
|
+
http: "http";
|
|
50
|
+
info: "info";
|
|
51
|
+
error: "error";
|
|
52
|
+
log: "log";
|
|
53
|
+
warn: "warn";
|
|
54
|
+
}>>;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
resolveOutputSchema: () => z.ZodObject<{
|
|
57
|
+
status: z.ZodString;
|
|
58
|
+
message: z.ZodString;
|
|
59
|
+
level: z.ZodString;
|
|
60
|
+
timestamp: z.ZodString;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
telemetry: {
|
|
63
|
+
source: string;
|
|
64
|
+
name: string;
|
|
65
|
+
};
|
|
66
|
+
devModeOnly: true;
|
|
67
|
+
createHandler: (strapi: import("@strapi/types/dist/core").Strapi) => ({ args }: {
|
|
68
|
+
extra: import("@modelcontextprotocol/sdk/shared/protocol").RequestHandlerExtra<import("@modelcontextprotocol/sdk/types").ServerRequest, import("@modelcontextprotocol/sdk/types").ServerNotification>;
|
|
69
|
+
} & {
|
|
70
|
+
args: {
|
|
71
|
+
message: string;
|
|
72
|
+
level: "http" | "info" | "error" | "log" | "warn";
|
|
73
|
+
};
|
|
74
|
+
}) => Promise<{
|
|
75
|
+
content: {
|
|
76
|
+
type: "text";
|
|
77
|
+
text: string;
|
|
78
|
+
}[];
|
|
79
|
+
structuredContent: {
|
|
80
|
+
status: string;
|
|
81
|
+
message: string;
|
|
82
|
+
level: "http" | "info" | "error" | "log" | "warn";
|
|
83
|
+
timestamp: string;
|
|
84
|
+
};
|
|
85
|
+
}>;
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../../../src/services/mcp/tools/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAmBlC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwE5B,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var strapiUtils = require('@strapi/utils');
|
|
4
|
+
var toolRegistry = require('../tool-registry.js');
|
|
5
|
+
|
|
6
|
+
const inputSchema = strapiUtils.z.object({
|
|
7
|
+
message: strapiUtils.z.string().describe('Message to log'),
|
|
8
|
+
level: strapiUtils.z.enum([
|
|
9
|
+
'info',
|
|
10
|
+
'http',
|
|
11
|
+
'warn',
|
|
12
|
+
'error',
|
|
13
|
+
'log'
|
|
14
|
+
]).default('info').describe('Log level (default: info)')
|
|
15
|
+
});
|
|
16
|
+
const outputSchema = strapiUtils.z.object({
|
|
17
|
+
status: strapiUtils.z.string(),
|
|
18
|
+
message: strapiUtils.z.string(),
|
|
19
|
+
level: strapiUtils.z.string(),
|
|
20
|
+
timestamp: strapiUtils.z.string()
|
|
21
|
+
});
|
|
22
|
+
const logToolDefinition = toolRegistry.makeMcpToolDefinition({
|
|
23
|
+
name: 'log',
|
|
24
|
+
title: 'Strapi Log',
|
|
25
|
+
description: 'Logs a message to the Strapi logger with specified level',
|
|
26
|
+
resolveInputSchema: ()=>inputSchema,
|
|
27
|
+
resolveOutputSchema: ()=>outputSchema,
|
|
28
|
+
telemetry: {
|
|
29
|
+
source: 'core',
|
|
30
|
+
name: 'log'
|
|
31
|
+
},
|
|
32
|
+
devModeOnly: true,
|
|
33
|
+
createHandler: (strapi)=>async ({ args })=>{
|
|
34
|
+
const { message, level } = args;
|
|
35
|
+
// Security: Sanitize message to prevent log injection
|
|
36
|
+
// 1. Limit length to prevent log spam (10KB max)
|
|
37
|
+
const MAX_MESSAGE_LENGTH = 10 * 1024;
|
|
38
|
+
let sanitizedMessage = message.length > MAX_MESSAGE_LENGTH ? `${message.substring(0, MAX_MESSAGE_LENGTH)}...[truncated]` : message;
|
|
39
|
+
// 2. Remove control characters (including ANSI escape codes)
|
|
40
|
+
// This regex matches: \x00-\x1F (C0 controls), \x7F (DEL), \x80-\x9F (C1 controls)
|
|
41
|
+
// and ANSI escape sequences (\x1B[ followed by parameters and command)
|
|
42
|
+
sanitizedMessage = sanitizedMessage// eslint-disable-next-line no-control-regex
|
|
43
|
+
.replace(/\x1B\[[0-9;]*[A-Za-z]/g, '') // Remove ANSI escape sequences
|
|
44
|
+
// eslint-disable-next-line no-control-regex
|
|
45
|
+
.replace(/[\x00-\x1F\x7F-\x9F]/g, ''); // Remove control characters
|
|
46
|
+
// 3. Replace newlines with spaces to prevent fake log entry injection
|
|
47
|
+
sanitizedMessage = sanitizedMessage.replace(/[\r\n]+/g, ' ');
|
|
48
|
+
// 4. Trim whitespace
|
|
49
|
+
sanitizedMessage = sanitizedMessage.trim();
|
|
50
|
+
// Map level to appropriate logger method
|
|
51
|
+
switch(level){
|
|
52
|
+
case 'http':
|
|
53
|
+
strapi.log.http(`[MCP] ${sanitizedMessage}`);
|
|
54
|
+
break;
|
|
55
|
+
case 'warn':
|
|
56
|
+
strapi.log.warn(`[MCP] ${sanitizedMessage}`);
|
|
57
|
+
break;
|
|
58
|
+
case 'error':
|
|
59
|
+
strapi.log.error(`[MCP] ${sanitizedMessage}`);
|
|
60
|
+
break;
|
|
61
|
+
case 'log':
|
|
62
|
+
strapi.log.info(`[MCP] ${sanitizedMessage}`);
|
|
63
|
+
break;
|
|
64
|
+
case 'info':
|
|
65
|
+
default:
|
|
66
|
+
strapi.log.info(`[MCP] ${sanitizedMessage}`);
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
const result = {
|
|
70
|
+
status: 'logged',
|
|
71
|
+
message: sanitizedMessage,
|
|
72
|
+
level,
|
|
73
|
+
timestamp: new Date().toISOString()
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: JSON.stringify(result, null, 2)
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
structuredContent: result
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
exports.logToolDefinition = logToolDefinition;
|
|
88
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sources":["../../../../src/services/mcp/tools/log.ts"],"sourcesContent":["import { z } from '@strapi/utils';\n\nimport { makeMcpToolDefinition } from '../tool-registry';\n\nconst inputSchema = z.object({\n message: z.string().describe('Message to log'),\n level: z\n .enum(['info', 'http', 'warn', 'error', 'log'])\n .default('info')\n .describe('Log level (default: info)'),\n});\n\nconst outputSchema = z.object({\n status: z.string(),\n message: z.string(),\n level: z.string(),\n timestamp: z.string(),\n});\n\nexport const logToolDefinition = makeMcpToolDefinition({\n name: 'log',\n title: 'Strapi Log',\n description: 'Logs a message to the Strapi logger with specified level',\n resolveInputSchema: () => inputSchema,\n resolveOutputSchema: () => outputSchema,\n telemetry: { source: 'core', name: 'log' },\n devModeOnly: true,\n createHandler:\n (strapi) =>\n async ({ args }) => {\n const { message, level } = args;\n\n // Security: Sanitize message to prevent log injection\n // 1. Limit length to prevent log spam (10KB max)\n const MAX_MESSAGE_LENGTH = 10 * 1024;\n let sanitizedMessage =\n message.length > MAX_MESSAGE_LENGTH\n ? `${message.substring(0, MAX_MESSAGE_LENGTH)}...[truncated]`\n : message;\n\n // 2. Remove control characters (including ANSI escape codes)\n // This regex matches: \\x00-\\x1F (C0 controls), \\x7F (DEL), \\x80-\\x9F (C1 controls)\n // and ANSI escape sequences (\\x1B[ followed by parameters and command)\n sanitizedMessage = sanitizedMessage\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1B\\[[0-9;]*[A-Za-z]/g, '') // Remove ANSI escape sequences\n // eslint-disable-next-line no-control-regex\n .replace(/[\\x00-\\x1F\\x7F-\\x9F]/g, ''); // Remove control characters\n\n // 3. Replace newlines with spaces to prevent fake log entry injection\n sanitizedMessage = sanitizedMessage.replace(/[\\r\\n]+/g, ' ');\n\n // 4. Trim whitespace\n sanitizedMessage = sanitizedMessage.trim();\n\n // Map level to appropriate logger method\n switch (level) {\n case 'http':\n strapi.log.http(`[MCP] ${sanitizedMessage}`);\n break;\n case 'warn':\n strapi.log.warn(`[MCP] ${sanitizedMessage}`);\n break;\n case 'error':\n strapi.log.error(`[MCP] ${sanitizedMessage}`);\n break;\n case 'log':\n strapi.log.info(`[MCP] ${sanitizedMessage}`);\n break;\n case 'info':\n default:\n strapi.log.info(`[MCP] ${sanitizedMessage}`);\n break;\n }\n\n const result = {\n status: 'logged',\n message: sanitizedMessage,\n level,\n timestamp: new Date().toISOString(),\n };\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n structuredContent: result,\n };\n },\n});\n"],"names":["inputSchema","z","object","message","string","describe","level","enum","default","outputSchema","status","timestamp","logToolDefinition","makeMcpToolDefinition","name","title","description","resolveInputSchema","resolveOutputSchema","telemetry","source","devModeOnly","createHandler","strapi","args","MAX_MESSAGE_LENGTH","sanitizedMessage","length","substring","replace","trim","log","http","warn","error","info","result","Date","toISOString","content","type","text","JSON","stringify","structuredContent"],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from '@strapi/utils';
|
|
2
|
+
import { makeMcpToolDefinition } from '../tool-registry.mjs';
|
|
3
|
+
|
|
4
|
+
const inputSchema = z.object({
|
|
5
|
+
message: z.string().describe('Message to log'),
|
|
6
|
+
level: z.enum([
|
|
7
|
+
'info',
|
|
8
|
+
'http',
|
|
9
|
+
'warn',
|
|
10
|
+
'error',
|
|
11
|
+
'log'
|
|
12
|
+
]).default('info').describe('Log level (default: info)')
|
|
13
|
+
});
|
|
14
|
+
const outputSchema = z.object({
|
|
15
|
+
status: z.string(),
|
|
16
|
+
message: z.string(),
|
|
17
|
+
level: z.string(),
|
|
18
|
+
timestamp: z.string()
|
|
19
|
+
});
|
|
20
|
+
const logToolDefinition = makeMcpToolDefinition({
|
|
21
|
+
name: 'log',
|
|
22
|
+
title: 'Strapi Log',
|
|
23
|
+
description: 'Logs a message to the Strapi logger with specified level',
|
|
24
|
+
resolveInputSchema: ()=>inputSchema,
|
|
25
|
+
resolveOutputSchema: ()=>outputSchema,
|
|
26
|
+
telemetry: {
|
|
27
|
+
source: 'core',
|
|
28
|
+
name: 'log'
|
|
29
|
+
},
|
|
30
|
+
devModeOnly: true,
|
|
31
|
+
createHandler: (strapi)=>async ({ args })=>{
|
|
32
|
+
const { message, level } = args;
|
|
33
|
+
// Security: Sanitize message to prevent log injection
|
|
34
|
+
// 1. Limit length to prevent log spam (10KB max)
|
|
35
|
+
const MAX_MESSAGE_LENGTH = 10 * 1024;
|
|
36
|
+
let sanitizedMessage = message.length > MAX_MESSAGE_LENGTH ? `${message.substring(0, MAX_MESSAGE_LENGTH)}...[truncated]` : message;
|
|
37
|
+
// 2. Remove control characters (including ANSI escape codes)
|
|
38
|
+
// This regex matches: \x00-\x1F (C0 controls), \x7F (DEL), \x80-\x9F (C1 controls)
|
|
39
|
+
// and ANSI escape sequences (\x1B[ followed by parameters and command)
|
|
40
|
+
sanitizedMessage = sanitizedMessage// eslint-disable-next-line no-control-regex
|
|
41
|
+
.replace(/\x1B\[[0-9;]*[A-Za-z]/g, '') // Remove ANSI escape sequences
|
|
42
|
+
// eslint-disable-next-line no-control-regex
|
|
43
|
+
.replace(/[\x00-\x1F\x7F-\x9F]/g, ''); // Remove control characters
|
|
44
|
+
// 3. Replace newlines with spaces to prevent fake log entry injection
|
|
45
|
+
sanitizedMessage = sanitizedMessage.replace(/[\r\n]+/g, ' ');
|
|
46
|
+
// 4. Trim whitespace
|
|
47
|
+
sanitizedMessage = sanitizedMessage.trim();
|
|
48
|
+
// Map level to appropriate logger method
|
|
49
|
+
switch(level){
|
|
50
|
+
case 'http':
|
|
51
|
+
strapi.log.http(`[MCP] ${sanitizedMessage}`);
|
|
52
|
+
break;
|
|
53
|
+
case 'warn':
|
|
54
|
+
strapi.log.warn(`[MCP] ${sanitizedMessage}`);
|
|
55
|
+
break;
|
|
56
|
+
case 'error':
|
|
57
|
+
strapi.log.error(`[MCP] ${sanitizedMessage}`);
|
|
58
|
+
break;
|
|
59
|
+
case 'log':
|
|
60
|
+
strapi.log.info(`[MCP] ${sanitizedMessage}`);
|
|
61
|
+
break;
|
|
62
|
+
case 'info':
|
|
63
|
+
default:
|
|
64
|
+
strapi.log.info(`[MCP] ${sanitizedMessage}`);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
const result = {
|
|
68
|
+
status: 'logged',
|
|
69
|
+
message: sanitizedMessage,
|
|
70
|
+
level,
|
|
71
|
+
timestamp: new Date().toISOString()
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{
|
|
76
|
+
type: 'text',
|
|
77
|
+
text: JSON.stringify(result, null, 2)
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
structuredContent: result
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export { logToolDefinition };
|
|
86
|
+
//# sourceMappingURL=log.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.mjs","sources":["../../../../src/services/mcp/tools/log.ts"],"sourcesContent":["import { z } from '@strapi/utils';\n\nimport { makeMcpToolDefinition } from '../tool-registry';\n\nconst inputSchema = z.object({\n message: z.string().describe('Message to log'),\n level: z\n .enum(['info', 'http', 'warn', 'error', 'log'])\n .default('info')\n .describe('Log level (default: info)'),\n});\n\nconst outputSchema = z.object({\n status: z.string(),\n message: z.string(),\n level: z.string(),\n timestamp: z.string(),\n});\n\nexport const logToolDefinition = makeMcpToolDefinition({\n name: 'log',\n title: 'Strapi Log',\n description: 'Logs a message to the Strapi logger with specified level',\n resolveInputSchema: () => inputSchema,\n resolveOutputSchema: () => outputSchema,\n telemetry: { source: 'core', name: 'log' },\n devModeOnly: true,\n createHandler:\n (strapi) =>\n async ({ args }) => {\n const { message, level } = args;\n\n // Security: Sanitize message to prevent log injection\n // 1. Limit length to prevent log spam (10KB max)\n const MAX_MESSAGE_LENGTH = 10 * 1024;\n let sanitizedMessage =\n message.length > MAX_MESSAGE_LENGTH\n ? `${message.substring(0, MAX_MESSAGE_LENGTH)}...[truncated]`\n : message;\n\n // 2. Remove control characters (including ANSI escape codes)\n // This regex matches: \\x00-\\x1F (C0 controls), \\x7F (DEL), \\x80-\\x9F (C1 controls)\n // and ANSI escape sequences (\\x1B[ followed by parameters and command)\n sanitizedMessage = sanitizedMessage\n // eslint-disable-next-line no-control-regex\n .replace(/\\x1B\\[[0-9;]*[A-Za-z]/g, '') // Remove ANSI escape sequences\n // eslint-disable-next-line no-control-regex\n .replace(/[\\x00-\\x1F\\x7F-\\x9F]/g, ''); // Remove control characters\n\n // 3. Replace newlines with spaces to prevent fake log entry injection\n sanitizedMessage = sanitizedMessage.replace(/[\\r\\n]+/g, ' ');\n\n // 4. Trim whitespace\n sanitizedMessage = sanitizedMessage.trim();\n\n // Map level to appropriate logger method\n switch (level) {\n case 'http':\n strapi.log.http(`[MCP] ${sanitizedMessage}`);\n break;\n case 'warn':\n strapi.log.warn(`[MCP] ${sanitizedMessage}`);\n break;\n case 'error':\n strapi.log.error(`[MCP] ${sanitizedMessage}`);\n break;\n case 'log':\n strapi.log.info(`[MCP] ${sanitizedMessage}`);\n break;\n case 'info':\n default:\n strapi.log.info(`[MCP] ${sanitizedMessage}`);\n break;\n }\n\n const result = {\n status: 'logged',\n message: sanitizedMessage,\n level,\n timestamp: new Date().toISOString(),\n };\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n structuredContent: result,\n };\n },\n});\n"],"names":["inputSchema","z","object","message","string","describe","level","enum","default","outputSchema","status","timestamp","logToolDefinition","makeMcpToolDefinition","name","title","description","resolveInputSchema","resolveOutputSchema","telemetry","source","devModeOnly","createHandler","strapi","args","MAX_MESSAGE_LENGTH","sanitizedMessage","length","substring","replace","trim","log","http","warn","error","info","result","Date","toISOString","content","type","text","JSON","stringify","structuredContent"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Core } from '@strapi/types';
|
|
2
|
+
import type { RegisteredCapability } from '../internal/McpCapabilityRegistry';
|
|
3
|
+
/**
|
|
4
|
+
* A no-op registered capability used as fallback when SDK registration fails.
|
|
5
|
+
*
|
|
6
|
+
* This prevents one broken capability from aborting the entire registration loop.
|
|
7
|
+
* The capability will appear as "disabled" and cannot be enabled.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FAILED_REGISTERED_CAPABILITY: RegisteredCapability;
|
|
10
|
+
/**
|
|
11
|
+
* Configuration for creating a safe capability registration
|
|
12
|
+
*/
|
|
13
|
+
export type SafeCapabilityRegistrationConfig<THandler, TErrorResult, TRegistered> = {
|
|
14
|
+
strapi: Core.Strapi;
|
|
15
|
+
capabilityType: string;
|
|
16
|
+
name: string;
|
|
17
|
+
createHandler: (strapi: Core.Strapi) => THandler;
|
|
18
|
+
createFallbackHandler: (errorMessage: string) => NoInfer<THandler>;
|
|
19
|
+
createErrorResult: (error: Error, args: unknown[]) => TErrorResult;
|
|
20
|
+
registerWithSdk: (safeHandler: THandler) => TRegistered;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Creates a safe capability registration that protects Strapi core from user callback errors
|
|
24
|
+
* at three levels:
|
|
25
|
+
*
|
|
26
|
+
* - Level 1: Catch factory invocation errors (createHandler throws)
|
|
27
|
+
* - Level 2: Catch runtime execution errors (handler throws during invocation)
|
|
28
|
+
* - Level 3: Catch MCP SDK registration errors (SDK rejects the registration)
|
|
29
|
+
*
|
|
30
|
+
* This prevents one broken capability from:
|
|
31
|
+
* - Aborting the entire registration loop
|
|
32
|
+
* - Crashing the MCP server
|
|
33
|
+
* - Leaking unhandled errors to the user
|
|
34
|
+
*/
|
|
35
|
+
export declare const createSafeCapabilityRegistration: <THandler, TErrorResult, TRegistered>(config: SafeCapabilityRegistrationConfig<THandler, TErrorResult, TRegistered>) => TRegistered;
|
|
36
|
+
//# sourceMappingURL=createSafeCapabilityRegistration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createSafeCapabilityRegistration.d.ts","sourceRoot":"","sources":["../../../../src/services/mcp/utils/createSafeCapabilityRegistration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAG9E;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,EAAE,oBAKzC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,gCAAgC,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,IAAI;IAClF,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC;IACjD,qBAAqB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnE,iBAAiB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,YAAY,CAAC;IACnE,eAAe,EAAE,CAAC,WAAW,EAAE,QAAQ,KAAK,WAAW,CAAC;CACzD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gCAAgC,gDACnC,iCAAiC,QAAQ,EAAE,YAAY,EAAE,WAAW,CAAC,KAC5E,WA4CF,CAAC"}
|