@webpieces/core-util 0.4.885 → 0.4.887

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 CHANGED
@@ -153,3 +153,12 @@ is reported locally as `StreamTransportError`.
153
153
  ## License
154
154
 
155
155
  Apache-2.0
156
+
157
+ ### MCP profile membership
158
+
159
+ `Mcp.DEFAULT` is the reserved base tool group. `@WpMcpTool(name, title)` and an omitted
160
+ `profiles` option select only that group. `{ profiles: ['admin'] }` selects only admin;
161
+ `{ profiles: [Mcp.DEFAULT, 'admin'] }` explicitly shares a tool between both groups. Membership is
162
+ independent of `@WpAuthorization` roles and never grants account permissions. Identifiers match
163
+ `[a-z][a-z0-9-]{0,63}`; empty lists, duplicates and malformed options are rejected.
164
+ See `@webpieces/mcp-server` for independent endpoint/resource configuration and union selection.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/core-util",
3
- "version": "0.4.885",
3
+ "version": "0.4.887",
4
4
  "description": "Utility functions for WebPieces - works in browser and Node.js",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
package/src/index.d.ts CHANGED
@@ -108,3 +108,5 @@ export { OAuthBearerChallenge } from './oauth/OAuthBearerChallenge';
108
108
  export { OAuthErrorBody, OAuthErrorResponse } from './oauth/OAuthErrorResponse';
109
109
  export { OAuthAuthorizationErrorRedirect } from './oauth/OAuthAuthorizationErrorRedirect';
110
110
  export type { PublishedKind, PublishedApiError } from './http/ApiErrorHttpStatus';
111
+ export { Mcp, McpToolProfilesOptions } from './mcp/Mcp';
112
+ export type { McpToolProfiles } from './mcp/Mcp';
package/src/index.js CHANGED
@@ -12,7 +12,7 @@ exports.MCP = exports.EXTERNAL_CUSTOMER = exports.SVC_TO_SVC = exports.ApiType =
12
12
  exports.InvalidEndpointForMcp = exports.WRITE = exports.WRITE_IDEMPOTENT = exports.READ = exports.EXTERNAL = exports.CRON = exports.CLOUDTASKS = exports.RPC = exports.POST = exports.GET = exports.registerStreamingSchemas = exports.getStreamingEndpoint = exports.WpStream = exports.StreamDirection = exports.StreamWriter = exports.StreamTransportError = exports.StreamEventValidator = exports.StreamingEndpointMetadata = exports.StreamEnvelope = exports.StreamCorrelation = exports.HttpParameterDeclaration = exports.HttpParameterBinding = exports.HttpContractMapper = exports.BoundHttpRequest = exports.StreamDisconnectedError = exports.StreamProtocolError = exports.StreamErrorControl = exports.registerStreamingCatalog = exports.StreamingSchemaCatalog = exports.getAuthorization = exports.WpAuthorization = exports.AuthorizationDeclaration = exports.AuthorizationType = exports.RouteMetadataFactory = exports.RouteMetadata = exports.IPC_METADATA_KEYS = exports.assertNotInternalApi = exports.assertInternalApi = exports.getIpcMaskSpec = exports.getIpcEndpointKind = exports.getIpcEndpoints = exports.getIpcApiId = exports.isInternalApi = exports.WpIpcEndpoint = exports.WpInternal = exports.assertApiTypeMatchesMcpTools = exports.getApiTypeEndpointNames = exports.getApiTypes = exports.DEFAULT_API_TYPES = exports.API_TYPE_METADATA_KEY = void 0;
13
13
  exports.NetworkRejectClassifier = exports.NO_REG_CODE = exports.WRONG_COMPANY = exports.WRONG_DOMAIN = exports.EMAIL_NOT_CONFIRMED = exports.NOT_APPROVED = exports.WRONG_LOGIN = exports.WRONG_LOGIN_TYPE = exports.ENTITY_NOT_FOUND = exports.SECRETS = exports.Secrets = exports.getEndpointCaller = exports.isExternalSystemKind = exports.ExternalCaller = exports.DEFAULT_CALLER_KIND = exports.EXTERNAL_SYSTEM_KINDS = exports.getQueueName = exports.assertPubSubConventions = exports.assertApiKind = exports.getApiKind = exports.ENDPOINT_KINDS_BY_API_KIND = exports.Queue = exports.PubSub = exports.Rpc = exports.apiKey = exports.webhook = exports.sharedSecret = exports.oidc = exports.jwt = exports.AuthDeclaration = exports.AuthMeta = exports.GenerateOutputTarget = exports.GenerateOutputLookup = exports.GenerateLayoutProblem = exports.GeneratedApiDocsLayout = exports.McpToolDefinition = exports.McpToolCatalogError = exports.McpToolCatalogFile = exports.ObjectSchemaBuilder = exports.DtoValidationFailure = exports.ApiJsonSchemaValidator = exports.ApiJsonSchemaDiscriminator = exports.ApiJsonSchema = exports.mcpHintsForOperation = exports.getWpMcpTools = exports.getInvalidEndpointsForMcp = exports.WpMcpToolMetadata = exports.WpMcpToolHints = exports.WpMcpTool = exports.InvalidEndpointForMcpMetadata = void 0;
14
14
  exports.ApiDependencyTimeoutError = exports.ApiUnavailableError = exports.ApiBadGatewayError = exports.ApiDependencyError = exports.ApiNotFoundError = exports.ApiError = exports.FilterChain = exports.Filter = exports.SerializedError = exports.SerializedMap = exports.RecordSerializer = exports.getDoNotRecordFields = exports.DoNotRecord = exports.RecordedTestCase = exports.RecordedError = exports.RecordedEndpoint = exports.RecorderKeys = exports.ApiMethodInfo = exports.LOG_API_CALL_LOGGER_NAME = exports.ApiCallLogNameImpl = exports.ApiCallLogName = exports.ApiCallInfo = exports.MaskSpec = exports.LogApiCallImpl = exports.ContextMgr = exports.DestinationTrust = exports.WebpiecesCoreHeaders = exports.templateDeriver = exports.WEBPIECES_DEFAULT_FAILURE_CLASSIFIER = exports.WebpiecesDefaultFailureClassifier = exports.KeyedFailureClassifier = exports.ReceivedApiErrorRule = exports.SurfaceEndUserStatus = exports.WEBPIECES_DEFAULT_ERROR_TRANSLATOR = exports.WebpiecesDefaultErrorTranslator = exports.HttpResponseDto = exports.HttpResponseStatus = exports.HttpHeader = exports.RuntimeLocality = exports.ServiceInfo = exports.ApiCallTimeoutError = exports.CallContext = exports.CallDeadline = exports.CallRegistry = exports.ClientRegistry = exports.HeaderRegistry = exports.DateTimeUtil = exports.TimeUtil = exports.DateUtil = exports.InstantUtil = void 0;
15
- exports.OAuthAuthorizationErrorRedirect = exports.OAuthErrorResponse = exports.OAuthErrorBody = exports.OAuthBearerChallenge = exports.OAuthErrorExtras = exports.OAuthProtocolError = exports.OAuthText = exports.OAuthErrorStatus = exports.OAuthErrorCode = exports.ApiErrorHttpStatus = exports.RpcCallFailed = exports.ReportableApiFailure = exports.ApiCallSite = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ClientRole = exports.EndUserErrorRegistry = exports.EndUserErrorCode = exports.ApiEndUserBadRequestError = exports.ApiEndUserForbiddenError = exports.ApiEndUserNotFoundError = exports.ApiClientTooOldError = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = void 0;
15
+ exports.McpToolProfilesOptions = exports.Mcp = exports.OAuthAuthorizationErrorRedirect = exports.OAuthErrorResponse = exports.OAuthErrorBody = exports.OAuthBearerChallenge = exports.OAuthErrorExtras = exports.OAuthProtocolError = exports.OAuthText = exports.OAuthErrorStatus = exports.OAuthErrorCode = exports.ApiErrorHttpStatus = exports.RpcCallFailed = exports.ReportableApiFailure = exports.ApiCallSite = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ClientRole = exports.EndUserErrorRegistry = exports.EndUserErrorCode = exports.ApiEndUserBadRequestError = exports.ApiEndUserForbiddenError = exports.ApiEndUserNotFoundError = exports.ApiClientTooOldError = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = void 0;
16
16
  var errorUtils_1 = require("./lib/errorUtils");
17
17
  Object.defineProperty(exports, "toError", { enumerable: true, get: function () { return errorUtils_1.toError; } });
18
18
  var ContextKey_1 = require("./ContextKey");
@@ -375,4 +375,7 @@ Object.defineProperty(exports, "OAuthErrorBody", { enumerable: true, get: functi
375
375
  Object.defineProperty(exports, "OAuthErrorResponse", { enumerable: true, get: function () { return OAuthErrorResponse_1.OAuthErrorResponse; } });
376
376
  var OAuthAuthorizationErrorRedirect_1 = require("./oauth/OAuthAuthorizationErrorRedirect");
377
377
  Object.defineProperty(exports, "OAuthAuthorizationErrorRedirect", { enumerable: true, get: function () { return OAuthAuthorizationErrorRedirect_1.OAuthAuthorizationErrorRedirect; } });
378
+ var Mcp_1 = require("./mcp/Mcp");
379
+ Object.defineProperty(exports, "Mcp", { enumerable: true, get: function () { return Mcp_1.Mcp; } });
380
+ Object.defineProperty(exports, "McpToolProfilesOptions", { enumerable: true, get: function () { return Mcp_1.McpToolProfilesOptions; } });
378
381
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/core/core-util/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @webpieces/core-util\n *\n * Utility functions for WebPieces applications.\n * This package works in both browser and Node.js environments.\n *\n * @packageDocumentation\n */\n\nexport { toError } from './lib/errorUtils';\nexport { ContextKey } from './ContextKey';\nexport type {\n AnyContextKey,\n AnyTrustedContextKey,\n AnyUntrustedContextKey,\n Trust,\n} from './ContextKey';\nexport { ContextTuple } from './ContextTuple';\n\n// @DocumentDesign — DI-design-root marker. Applies to ANY project kind (server\n// controllers AND library impl classes), so it lives here (browser + Node) rather\n// than in a server-only routing package.\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './DocumentDesign';\n\n// Logging (merged from former @webpieces/wp-logging).\n// Pluggable logging interface + a browser-safe console default; apps plug in\n// bunyan/winston/pino/etc. via LogManager.setFactory(...). Browser + Node.\nexport type { Logger, LogLevel } from './logging/Logger';\nexport type { LoggerFactory } from './logging/LoggerFactory';\nexport { ConsoleLogger } from './logging/ConsoleLogger';\nexport { ConsoleLoggerFactory } from './logging/ConsoleLoggerFactory';\nexport { LogManager } from './logging/LogManager';\nexport {\n LogChunker,\n LogChunkerImpl,\n LogChunkInfo,\n MAX_GCP_LOG_BYTES,\n GCP_LOG_BUDGET_BYTES,\n} from './logging/LogChunker';\n\n// HTTP API contract (merged from former @webpieces/http-api).\n// Shared HTTP API definition consumed by both client and server: REST\n// decorators, the API error taxonomy, datetime DTOs, platform-header\n// registry/readers, ValidateImplementation, and the test-case recorder\n// contract. Pure definitions — express-free, browser + Node safe.\n\n// API definition decorators\nexport {\n ApiPath,\n Endpoint,\n // Auth mode decorators (clean service-to-service + user JWT model)\n WpAuthPublic,\n WpAuth,\n MISSING_AUTH_DECORATOR_FIX,\n WpLocalOnly,\n isLocalOnly,\n MaskLog,\n getApiPath,\n getEndpoints,\n getEndpointHttpMethod,\n getEndpointOptions,\n getEndpointOperation,\n getEndpointKind,\n getEndpointKinds,\n getMaskSpec,\n isFormPost,\n isRawBody,\n isApiPath,\n getAuthMeta,\n assertEveryEndpointHasAuthMode,\n assertEveryExternalEndpointDeclaresCaller,\n assertEveryWebhookEndpointRetainsRawBody,\n validateNoConflictingDecorators,\n METADATA_KEYS,\n} from './http/decorators';\nexport {\n PathParam,\n QueryParam,\n getHttpParameterDeclarations,\n} from './http/http-parameter-decorators';\nexport { WpInt, WpMin, WpMax, NUMERIC_METADATA_KEYS } from './http/numeric-field-decorators';\nexport type { Integer } from './http/numeric-field-decorators';\nexport {\n ApiType,\n SVC_TO_SVC,\n EXTERNAL_CUSTOMER,\n MCP,\n API_TYPE_METADATA_KEY,\n DEFAULT_API_TYPES,\n getApiTypes,\n getApiTypeEndpointNames,\n assertApiTypeMatchesMcpTools,\n} from './http/api-type';\nexport type { ApiTypeKind } from './http/api-type';\nexport {\n WpInternal,\n WpIpcEndpoint,\n isInternalApi,\n getIpcApiId,\n getIpcEndpoints,\n getIpcEndpointKind,\n getIpcMaskSpec,\n assertInternalApi,\n assertNotInternalApi,\n IPC_METADATA_KEYS,\n} from './ipc/IpcDecorators';\nexport type { IpcApiType, IpcEndpointKind, IpcEndpointOptions } from './ipc/IpcDecorators';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport { RouteMetadataFactory } from './http/RouteMetadataFactory';\nexport { AuthorizationType, AuthorizationDeclaration, WpAuthorization, getAuthorization } from './http/authorization';\nexport type { AuthorizationRequirement } from './http/authorization';\nexport { StreamingSchemaCatalog, registerStreamingCatalog } from './http/StreamingSchemaCatalog';\nexport {\n StreamErrorControl,\n StreamProtocolError,\n StreamDisconnectedError,\n} from './http/StreamErrorControl';\nexport {\n BoundHttpRequest,\n HttpContractMapper,\n HttpParameterBinding,\n HttpParameterDeclaration,\n} from './http/HttpContract';\nexport {\n StreamCorrelation,\n StreamEnvelope,\n StreamingEndpointMetadata,\n StreamEventValidator,\n StreamTransportError,\n StreamWriter,\n StreamDirection,\n WpStream,\n getStreamingEndpoint,\n registerStreamingSchemas,\n} from './http/StreamingContract';\nexport type { RequestStream, ResponseStream, StreamEnvelopeKind } from './http/StreamingContract';\nexport type {\n EndpointResponseType,\n HttpMethod,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport { GET, POST } from './http/HttpContract';\nexport type {\n EndpointKind,\n EndpointOperation,\n EndpointOptions,\n ExternalEndpointOptions,\n} from './http/decorators';\nexport { RPC, CLOUDTASKS, CRON, EXTERNAL, READ, WRITE_IDEMPOTENT, WRITE } from './http/decorators';\nexport {\n InvalidEndpointForMcp,\n InvalidEndpointForMcpMetadata,\n WpMcpTool,\n WpMcpToolHints,\n WpMcpToolMetadata,\n getInvalidEndpointsForMcp,\n getWpMcpTools,\n mcpHintsForOperation,\n} from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator } from './mcp/McpMetadata';\nexport {\n ApiJsonSchema,\n ApiJsonSchemaDiscriminator,\n ApiJsonSchemaValidator,\n DtoValidationFailure,\n ObjectSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { ApiJsonSchemaType, DtoValue } from './mcp/DtoSchema';\nexport {\n McpToolCatalogFile,\n McpToolCatalogError,\n McpToolDefinition,\n} from './mcp/McpToolCatalogFile';\nexport {\n GeneratedApiDocsLayout,\n GenerateLayoutProblem,\n GenerateOutputLookup,\n GenerateOutputTarget,\n} from './mcp/GeneratedApiDocsLayout';\nexport type {\n LayoutDependsOn,\n LayoutDependsOnObject,\n LayoutTarget,\n LayoutTargets,\n} from './mcp/GeneratedApiDocsLayout';\n// The TYPE layer of the auth surface — likewise split out of decorators.ts for file size only.\nexport { AuthMeta, AuthDeclaration, jwt, oidc, sharedSecret, webhook, apiKey } from './http/auth-mode';\nexport type {\n AuthMode,\n ApiKeyCredential,\n ApiKeyCredentials,\n AuthMethod,\n AuthMethods,\n} from './http/auth-mode';\n// API kind (RPC vs PubSub/Cloud Tasks) + queue naming. Split out of decorators.ts for file size only;\n// one-way dependency api-kind -> decorators, and the barrel keeps the surface identical.\nexport {\n Rpc,\n PubSub,\n Queue,\n ENDPOINT_KINDS_BY_API_KIND,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n} from './http/api-kind';\nexport type { ApiKind } from './http/api-kind';\n// WHO calls an `external` endpoint — the caller declaration\n// @Endpoint(POST, ..., WRITE, EXTERNAL, { calledBy })\n// requires, and the reader for it.\nexport {\n EXTERNAL_SYSTEM_KINDS,\n DEFAULT_CALLER_KIND,\n ExternalCaller,\n isExternalSystemKind,\n getEndpointCaller,\n} from './http/external-caller';\nexport type { ExternalSystemKind } from './http/external-caller';\n// Client-side shared-secret store (the value THIS service sends per sharedSecret(...) key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// Authentication subtype constants.\nexport {\n ENTITY_NOT_FOUND,\n WRONG_LOGIN_TYPE,\n WRONG_LOGIN,\n NOT_APPROVED,\n EMAIL_NOT_CONFIRMED,\n WRONG_DOMAIN,\n WRONG_COMPANY,\n NO_REG_CODE,\n} from './errors';\n\nexport { NetworkRejectClassifier } from './http/networkReject';\n\n// Date/Time DTOs and Utilities (inspired by Java Time / JSR-310)\nexport {\n InstantDto,\n DateDto,\n TimeDto,\n DateTimeDto,\n InstantUtil,\n DateUtil,\n TimeUtil,\n DateTimeUtil,\n} from './http/datetime';\n\n// Context keys + registry (the global magic-context header system)\nexport { HeaderRegistry } from './http/HeaderRegistry';\nexport { ClientRegistry } from './http/ClientRegistry';\nexport { CallRegistry } from './http/CallRegistry';\nexport { CallDeadline } from './http/CallDeadline';\nexport { CallContext } from './http/CallStrategy';\nexport type { Attempt, CallStrategy } from './http/CallStrategy';\nexport { ApiCallTimeoutError } from './http/ApiCallTimeoutError';\nexport type { ServiceUrlDeriver } from './http/ClientRegistry';\n\n// \"What service am I\" — set once at startup, read by the logging backends and by\n// RequestContextHeaders (to stamp requestIdSource on ids this service mints).\nexport { ServiceInfo } from './http/ServiceInfo';\n// \"Where am I running\" — declared once at startup (setupRuntime, from RuntimeSetupOptions.locality).\n// The ONE input to @WpLocalOnly enforcement. Undeclared reads as DEPLOYED (fail safe).\nexport { RuntimeLocality } from './http/RuntimeLocality';\nexport type { Locality } from './http/RuntimeLocality';\n// The ENTIRE HTTP response as pure data — the ONE form both transports (express, fetch) are\n// normalised into, so an ErrorTranslator implementation is written once and serves both.\nexport { HttpHeader, HttpResponseStatus, HttpResponseDto } from './http/HttpResponseDto';\n// Pluggable, bidirectional error translation (app exception <-> the WHOLE response). Set on\n// ClientRegistry at startup; consulted before the built-in webpieces mapping on BOTH sides.\nexport type { ErrorTranslator } from './http/ErrorTranslator';\n// THE webpieces default translator — always installed, and what an app's own translator delegates to\n// in order to decline an error. ONE class, both halves, node and browser alike.\nexport {\n WebpiecesDefaultErrorTranslator,\n WEBPIECES_DEFAULT_ERROR_TRANSLATOR,\n} from './http/WebpiecesDefaultErrorTranslator';\n// WHICH KIND OF CALLER drove this request (gui / llm / public-api), and the per-request end-user\n// status derived from it — the replacement for the deleted per-router EndUserStatus.\nexport { SurfaceEndUserStatus } from './http/Surface';\nexport type { Surface } from './http/Surface';\n// The ONE rule for an error RECEIVED from another process, shared verbatim by HTTP and IPC.\nexport { ReceivedApiErrorRule } from './errors/ReceivedApiErrorRule';\n// Pluggable per-client failure classification (is a thrown API-call error a real failure or an\n// expected non-failure?). Registered on ClientRegistry at startup; consulted by LogApiCall.\nexport type { FailureClassifier } from './http/FailureClassifier';\nexport { KeyedFailureClassifier } from './http/FailureClassifier';\nexport {\n WebpiecesDefaultFailureClassifier,\n WEBPIECES_DEFAULT_FAILURE_CLASSIFIER,\n} from './http/WebpiecesDefaultFailureClassifier';\nexport { templateDeriver } from './http/templateDeriver';\nexport { WebpiecesCoreHeaders } from './http/WebpiecesCoreHeaders';\nexport { ContextReader } from './http/ContextReader';\nexport { ContextWriter, ContextStore } from './http/ContextWriter';\n\n// The OUTBOUND half of the trust model: whether a TRUSTED context key may ride to the endpoint being\n// called. Built ONLY from the destination endpoint's AuthMode — see the class doc.\nexport { DestinationTrust } from './http/DestinationTrust';\n\n// BROWSER-ONLY outbound-header propagation (app-held store + registry -> outbound HTTP headers).\n// Only @webpieces/http-client-browser may name it; the server reads RequestContext directly via\n// RequestContextHeaders in the Node-only @webpieces/core-context.\nexport { ContextMgr } from './http/ContextMgr';\n\n// API-call logging helper (uses LogManager above). NOT a singleton: construct one per environment\n// with that environment's ApiCallContext — `new LogApiCallImpl(new RequestContextApiCallContext())`\n// on node, `new LogApiCallImpl(new BrowserApiCallContext())` in a browser.\nexport { LogApiCallImpl } from './http/LogApiCall';\n\n// Opt-in field masking for the LogApiCall log path — declare per-api sensitive fields so secrets\n// (OAuth refresh tokens, id-token JWTs) are masked in the logs while the real value stays on the wire.\nexport { MaskSpec } from './http/LogFieldMask';\nexport type { MaskMode } from './http/LogFieldMask';\n\n// The structured `api` tag + the context-writer seam LogApiCall stamps through. The Node\n// RequestContext-backed impl lives in @webpieces/core-context, the browser one in\n// @webpieces/http-client-browser; each is CONSTRUCTED by its package, never installed globally.\nexport { ApiCallInfo } from './http/ApiCallInfo';\nexport type { ApiCallDirection, ApiResult } from './http/ApiCallInfo';\n// Console-render bridge: turns LogApiCall's [LogApiCall] bracket into [API.{side}.{phase}] locally.\nexport {\n ApiCallLogName,\n ApiCallLogNameImpl,\n LOG_API_CALL_LOGGER_NAME,\n} from './http/ApiCallLogName';\nexport { ApiMethodInfo } from './http/ApiMethodInfo';\nexport type { ApiSide } from './http/ApiMethodInfo';\nexport type { ApiCallContext } from './http/ApiCallContext';\n\n// Test-case recording contract (impl lives in http-server; hooks in http-client)\nexport { TestCaseRecorder, RecorderKeys } from './http/recorder/TestCaseRecorder';\nexport {\n RecordedEndpoint,\n RecordedError,\n RecordedTestCase,\n} from './http/recorder/RecordedEndpoint';\nexport { DoNotRecord, getDoNotRecordFields } from './http/recorder/DoNotRecord';\nexport { RecordSerializer, SerializedMap, SerializedError } from './http/recorder/RecordSerializer';\n\n// ---------------------------------------------------------------------------------------------\n// Filter-chain primitives, shared by BOTH chains: the inbound server chain\n// (`Filter<MethodMeta, WpResponse<unknown>>`, @webpieces/http-routing) and the outbound client\n// chain (`Filter<ClientRequest, Response>`, @webpieces/http-client-core). Declared once, here, in\n// the package both depend on — see the class doc for why a second pair would be a shim.\nexport { Filter } from './filters/Filter';\nexport type { Service } from './filters/Filter';\nexport { FilterChain } from './filters/FilterChain';\n\nexport {\n ApiError,\n ApiNotFoundError,\n ApiDependencyError,\n ApiBadGatewayError,\n ApiUnavailableError,\n ApiDependencyTimeoutError,\n ApiImplementationError,\n ApiRateLimitedError,\n ApiForbiddenError,\n ApiRequestTimeoutError,\n ApiEndUserError,\n ApiBadRequestError,\n ApiUnauthorizedError,\n ApiDependencyBackoffError,\n ApiConnectionError,\n ApiEndpointNotFoundError,\n ApiConflictError,\n ApiUnprocessableError,\n ApiPreconditionFailedError,\n ApiUnsupportedMediaTypeError,\n ApiNotImplementedError,\n ApiCodedError,\n ApiClientTooOldError,\n ApiEndUserNotFoundError,\n ApiEndUserForbiddenError,\n ApiEndUserBadRequestError,\n EndUserErrorCode,\n EndUserErrorRegistry,\n ClientRole,\n ApiErrorCodec,\n ApiErrorPayload,\n ApiErrorBoundary,\n ApiCallSite,\n ReportableApiFailure,\n RpcCallFailed,\n} from './errors';\nexport type {\n ApiErrorKind,\n ApiStatusCode,\n EdgeHttpStatus,\n EndUserErrorFactory,\n CallSiteBoundary,\n} from './errors';\nexport { ApiErrorHttpStatus } from './http/ApiErrorHttpStatus';\n\n// RFC 6749 / 6750 / 7591 OAuth refusals for app-hosted OAuth endpoints (#1176): the typed error,\n// its one renderer, the Bearer challenge builder and the authorization-endpoint error redirect.\nexport { OAuthErrorCode, OAuthErrorStatus, OAuthText } from './oauth/OAuthErrorCode';\nexport type {\n OAuthHttpStatus,\n InvalidClientStatus,\n OAuthFixedStatusErrorCode,\n BearerErrorCode,\n AuthorizationEndpointErrorCode,\n} from './oauth/OAuthErrorCode';\nexport { OAuthProtocolError, OAuthErrorExtras } from './oauth/OAuthProtocolError';\nexport { OAuthBearerChallenge } from './oauth/OAuthBearerChallenge';\nexport { OAuthErrorBody, OAuthErrorResponse } from './oauth/OAuthErrorResponse';\nexport { OAuthAuthorizationErrorRedirect } from './oauth/OAuthAuthorizationErrorRedirect';\nexport type { PublishedKind, PublishedApiError } from './http/ApiErrorHttpStatus';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/core/core-util/src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @webpieces/core-util\n *\n * Utility functions for WebPieces applications.\n * This package works in both browser and Node.js environments.\n *\n * @packageDocumentation\n */\n\nexport { toError } from './lib/errorUtils';\nexport { ContextKey } from './ContextKey';\nexport type {\n AnyContextKey,\n AnyTrustedContextKey,\n AnyUntrustedContextKey,\n Trust,\n} from './ContextKey';\nexport { ContextTuple } from './ContextTuple';\n\n// @DocumentDesign — DI-design-root marker. Applies to ANY project kind (server\n// controllers AND library impl classes), so it lives here (browser + Node) rather\n// than in a server-only routing package.\nexport { DocumentDesign, isDocumentDesign, DESIGN_METADATA_KEYS } from './DocumentDesign';\n\n// Logging (merged from former @webpieces/wp-logging).\n// Pluggable logging interface + a browser-safe console default; apps plug in\n// bunyan/winston/pino/etc. via LogManager.setFactory(...). Browser + Node.\nexport type { Logger, LogLevel } from './logging/Logger';\nexport type { LoggerFactory } from './logging/LoggerFactory';\nexport { ConsoleLogger } from './logging/ConsoleLogger';\nexport { ConsoleLoggerFactory } from './logging/ConsoleLoggerFactory';\nexport { LogManager } from './logging/LogManager';\nexport {\n LogChunker,\n LogChunkerImpl,\n LogChunkInfo,\n MAX_GCP_LOG_BYTES,\n GCP_LOG_BUDGET_BYTES,\n} from './logging/LogChunker';\n\n// HTTP API contract (merged from former @webpieces/http-api).\n// Shared HTTP API definition consumed by both client and server: REST\n// decorators, the API error taxonomy, datetime DTOs, platform-header\n// registry/readers, ValidateImplementation, and the test-case recorder\n// contract. Pure definitions — express-free, browser + Node safe.\n\n// API definition decorators\nexport {\n ApiPath,\n Endpoint,\n // Auth mode decorators (clean service-to-service + user JWT model)\n WpAuthPublic,\n WpAuth,\n MISSING_AUTH_DECORATOR_FIX,\n WpLocalOnly,\n isLocalOnly,\n MaskLog,\n getApiPath,\n getEndpoints,\n getEndpointHttpMethod,\n getEndpointOptions,\n getEndpointOperation,\n getEndpointKind,\n getEndpointKinds,\n getMaskSpec,\n isFormPost,\n isRawBody,\n isApiPath,\n getAuthMeta,\n assertEveryEndpointHasAuthMode,\n assertEveryExternalEndpointDeclaresCaller,\n assertEveryWebhookEndpointRetainsRawBody,\n validateNoConflictingDecorators,\n METADATA_KEYS,\n} from './http/decorators';\nexport {\n PathParam,\n QueryParam,\n getHttpParameterDeclarations,\n} from './http/http-parameter-decorators';\nexport { WpInt, WpMin, WpMax, NUMERIC_METADATA_KEYS } from './http/numeric-field-decorators';\nexport type { Integer } from './http/numeric-field-decorators';\nexport {\n ApiType,\n SVC_TO_SVC,\n EXTERNAL_CUSTOMER,\n MCP,\n API_TYPE_METADATA_KEY,\n DEFAULT_API_TYPES,\n getApiTypes,\n getApiTypeEndpointNames,\n assertApiTypeMatchesMcpTools,\n} from './http/api-type';\nexport type { ApiTypeKind } from './http/api-type';\nexport {\n WpInternal,\n WpIpcEndpoint,\n isInternalApi,\n getIpcApiId,\n getIpcEndpoints,\n getIpcEndpointKind,\n getIpcMaskSpec,\n assertInternalApi,\n assertNotInternalApi,\n IPC_METADATA_KEYS,\n} from './ipc/IpcDecorators';\nexport type { IpcApiType, IpcEndpointKind, IpcEndpointOptions } from './ipc/IpcDecorators';\n// The runtime representation of ONE route (split out of decorators.ts for file size only).\nexport { RouteMetadata } from './http/RouteMetadata';\nexport { RouteMetadataFactory } from './http/RouteMetadataFactory';\nexport { AuthorizationType, AuthorizationDeclaration, WpAuthorization, getAuthorization } from './http/authorization';\nexport type { AuthorizationRequirement } from './http/authorization';\nexport { StreamingSchemaCatalog, registerStreamingCatalog } from './http/StreamingSchemaCatalog';\nexport {\n StreamErrorControl,\n StreamProtocolError,\n StreamDisconnectedError,\n} from './http/StreamErrorControl';\nexport {\n BoundHttpRequest,\n HttpContractMapper,\n HttpParameterBinding,\n HttpParameterDeclaration,\n} from './http/HttpContract';\nexport {\n StreamCorrelation,\n StreamEnvelope,\n StreamingEndpointMetadata,\n StreamEventValidator,\n StreamTransportError,\n StreamWriter,\n StreamDirection,\n WpStream,\n getStreamingEndpoint,\n registerStreamingSchemas,\n} from './http/StreamingContract';\nexport type { RequestStream, ResponseStream, StreamEnvelopeKind } from './http/StreamingContract';\nexport type {\n EndpointResponseType,\n HttpMethod,\n HttpParameterSource,\n HttpParameterValueType,\n} from './http/HttpContract';\nexport { GET, POST } from './http/HttpContract';\nexport type {\n EndpointKind,\n EndpointOperation,\n EndpointOptions,\n ExternalEndpointOptions,\n} from './http/decorators';\nexport { RPC, CLOUDTASKS, CRON, EXTERNAL, READ, WRITE_IDEMPOTENT, WRITE } from './http/decorators';\nexport {\n InvalidEndpointForMcp,\n InvalidEndpointForMcpMetadata,\n WpMcpTool,\n WpMcpToolHints,\n WpMcpToolMetadata,\n getInvalidEndpointsForMcp,\n getWpMcpTools,\n mcpHintsForOperation,\n} from './mcp/McpMetadata';\nexport type { WpMcpMethodDecorator } from './mcp/McpMetadata';\nexport {\n ApiJsonSchema,\n ApiJsonSchemaDiscriminator,\n ApiJsonSchemaValidator,\n DtoValidationFailure,\n ObjectSchemaBuilder,\n} from './mcp/DtoSchema';\nexport type { ApiJsonSchemaType, DtoValue } from './mcp/DtoSchema';\nexport {\n McpToolCatalogFile,\n McpToolCatalogError,\n McpToolDefinition,\n} from './mcp/McpToolCatalogFile';\nexport {\n GeneratedApiDocsLayout,\n GenerateLayoutProblem,\n GenerateOutputLookup,\n GenerateOutputTarget,\n} from './mcp/GeneratedApiDocsLayout';\nexport type {\n LayoutDependsOn,\n LayoutDependsOnObject,\n LayoutTarget,\n LayoutTargets,\n} from './mcp/GeneratedApiDocsLayout';\n// The TYPE layer of the auth surface — likewise split out of decorators.ts for file size only.\nexport { AuthMeta, AuthDeclaration, jwt, oidc, sharedSecret, webhook, apiKey } from './http/auth-mode';\nexport type {\n AuthMode,\n ApiKeyCredential,\n ApiKeyCredentials,\n AuthMethod,\n AuthMethods,\n} from './http/auth-mode';\n// API kind (RPC vs PubSub/Cloud Tasks) + queue naming. Split out of decorators.ts for file size only;\n// one-way dependency api-kind -> decorators, and the barrel keeps the surface identical.\nexport {\n Rpc,\n PubSub,\n Queue,\n ENDPOINT_KINDS_BY_API_KIND,\n getApiKind,\n assertApiKind,\n assertPubSubConventions,\n getQueueName,\n} from './http/api-kind';\nexport type { ApiKind } from './http/api-kind';\n// WHO calls an `external` endpoint — the caller declaration\n// @Endpoint(POST, ..., WRITE, EXTERNAL, { calledBy })\n// requires, and the reader for it.\nexport {\n EXTERNAL_SYSTEM_KINDS,\n DEFAULT_CALLER_KIND,\n ExternalCaller,\n isExternalSystemKind,\n getEndpointCaller,\n} from './http/external-caller';\nexport type { ExternalSystemKind } from './http/external-caller';\n// Client-side shared-secret store (the value THIS service sends per sharedSecret(...) key).\nexport { Secrets, SECRETS } from './http/Secrets';\n\n// Type validators\nexport { ValidateImplementation } from './http/validators';\n\n// Authentication subtype constants.\nexport {\n ENTITY_NOT_FOUND,\n WRONG_LOGIN_TYPE,\n WRONG_LOGIN,\n NOT_APPROVED,\n EMAIL_NOT_CONFIRMED,\n WRONG_DOMAIN,\n WRONG_COMPANY,\n NO_REG_CODE,\n} from './errors';\n\nexport { NetworkRejectClassifier } from './http/networkReject';\n\n// Date/Time DTOs and Utilities (inspired by Java Time / JSR-310)\nexport {\n InstantDto,\n DateDto,\n TimeDto,\n DateTimeDto,\n InstantUtil,\n DateUtil,\n TimeUtil,\n DateTimeUtil,\n} from './http/datetime';\n\n// Context keys + registry (the global magic-context header system)\nexport { HeaderRegistry } from './http/HeaderRegistry';\nexport { ClientRegistry } from './http/ClientRegistry';\nexport { CallRegistry } from './http/CallRegistry';\nexport { CallDeadline } from './http/CallDeadline';\nexport { CallContext } from './http/CallStrategy';\nexport type { Attempt, CallStrategy } from './http/CallStrategy';\nexport { ApiCallTimeoutError } from './http/ApiCallTimeoutError';\nexport type { ServiceUrlDeriver } from './http/ClientRegistry';\n\n// \"What service am I\" — set once at startup, read by the logging backends and by\n// RequestContextHeaders (to stamp requestIdSource on ids this service mints).\nexport { ServiceInfo } from './http/ServiceInfo';\n// \"Where am I running\" — declared once at startup (setupRuntime, from RuntimeSetupOptions.locality).\n// The ONE input to @WpLocalOnly enforcement. Undeclared reads as DEPLOYED (fail safe).\nexport { RuntimeLocality } from './http/RuntimeLocality';\nexport type { Locality } from './http/RuntimeLocality';\n// The ENTIRE HTTP response as pure data — the ONE form both transports (express, fetch) are\n// normalised into, so an ErrorTranslator implementation is written once and serves both.\nexport { HttpHeader, HttpResponseStatus, HttpResponseDto } from './http/HttpResponseDto';\n// Pluggable, bidirectional error translation (app exception <-> the WHOLE response). Set on\n// ClientRegistry at startup; consulted before the built-in webpieces mapping on BOTH sides.\nexport type { ErrorTranslator } from './http/ErrorTranslator';\n// THE webpieces default translator — always installed, and what an app's own translator delegates to\n// in order to decline an error. ONE class, both halves, node and browser alike.\nexport {\n WebpiecesDefaultErrorTranslator,\n WEBPIECES_DEFAULT_ERROR_TRANSLATOR,\n} from './http/WebpiecesDefaultErrorTranslator';\n// WHICH KIND OF CALLER drove this request (gui / llm / public-api), and the per-request end-user\n// status derived from it — the replacement for the deleted per-router EndUserStatus.\nexport { SurfaceEndUserStatus } from './http/Surface';\nexport type { Surface } from './http/Surface';\n// The ONE rule for an error RECEIVED from another process, shared verbatim by HTTP and IPC.\nexport { ReceivedApiErrorRule } from './errors/ReceivedApiErrorRule';\n// Pluggable per-client failure classification (is a thrown API-call error a real failure or an\n// expected non-failure?). Registered on ClientRegistry at startup; consulted by LogApiCall.\nexport type { FailureClassifier } from './http/FailureClassifier';\nexport { KeyedFailureClassifier } from './http/FailureClassifier';\nexport {\n WebpiecesDefaultFailureClassifier,\n WEBPIECES_DEFAULT_FAILURE_CLASSIFIER,\n} from './http/WebpiecesDefaultFailureClassifier';\nexport { templateDeriver } from './http/templateDeriver';\nexport { WebpiecesCoreHeaders } from './http/WebpiecesCoreHeaders';\nexport { ContextReader } from './http/ContextReader';\nexport { ContextWriter, ContextStore } from './http/ContextWriter';\n\n// The OUTBOUND half of the trust model: whether a TRUSTED context key may ride to the endpoint being\n// called. Built ONLY from the destination endpoint's AuthMode — see the class doc.\nexport { DestinationTrust } from './http/DestinationTrust';\n\n// BROWSER-ONLY outbound-header propagation (app-held store + registry -> outbound HTTP headers).\n// Only @webpieces/http-client-browser may name it; the server reads RequestContext directly via\n// RequestContextHeaders in the Node-only @webpieces/core-context.\nexport { ContextMgr } from './http/ContextMgr';\n\n// API-call logging helper (uses LogManager above). NOT a singleton: construct one per environment\n// with that environment's ApiCallContext — `new LogApiCallImpl(new RequestContextApiCallContext())`\n// on node, `new LogApiCallImpl(new BrowserApiCallContext())` in a browser.\nexport { LogApiCallImpl } from './http/LogApiCall';\n\n// Opt-in field masking for the LogApiCall log path — declare per-api sensitive fields so secrets\n// (OAuth refresh tokens, id-token JWTs) are masked in the logs while the real value stays on the wire.\nexport { MaskSpec } from './http/LogFieldMask';\nexport type { MaskMode } from './http/LogFieldMask';\n\n// The structured `api` tag + the context-writer seam LogApiCall stamps through. The Node\n// RequestContext-backed impl lives in @webpieces/core-context, the browser one in\n// @webpieces/http-client-browser; each is CONSTRUCTED by its package, never installed globally.\nexport { ApiCallInfo } from './http/ApiCallInfo';\nexport type { ApiCallDirection, ApiResult } from './http/ApiCallInfo';\n// Console-render bridge: turns LogApiCall's [LogApiCall] bracket into [API.{side}.{phase}] locally.\nexport {\n ApiCallLogName,\n ApiCallLogNameImpl,\n LOG_API_CALL_LOGGER_NAME,\n} from './http/ApiCallLogName';\nexport { ApiMethodInfo } from './http/ApiMethodInfo';\nexport type { ApiSide } from './http/ApiMethodInfo';\nexport type { ApiCallContext } from './http/ApiCallContext';\n\n// Test-case recording contract (impl lives in http-server; hooks in http-client)\nexport { TestCaseRecorder, RecorderKeys } from './http/recorder/TestCaseRecorder';\nexport {\n RecordedEndpoint,\n RecordedError,\n RecordedTestCase,\n} from './http/recorder/RecordedEndpoint';\nexport { DoNotRecord, getDoNotRecordFields } from './http/recorder/DoNotRecord';\nexport { RecordSerializer, SerializedMap, SerializedError } from './http/recorder/RecordSerializer';\n\n// ---------------------------------------------------------------------------------------------\n// Filter-chain primitives, shared by BOTH chains: the inbound server chain\n// (`Filter<MethodMeta, WpResponse<unknown>>`, @webpieces/http-routing) and the outbound client\n// chain (`Filter<ClientRequest, Response>`, @webpieces/http-client-core). Declared once, here, in\n// the package both depend on — see the class doc for why a second pair would be a shim.\nexport { Filter } from './filters/Filter';\nexport type { Service } from './filters/Filter';\nexport { FilterChain } from './filters/FilterChain';\n\nexport {\n ApiError,\n ApiNotFoundError,\n ApiDependencyError,\n ApiBadGatewayError,\n ApiUnavailableError,\n ApiDependencyTimeoutError,\n ApiImplementationError,\n ApiRateLimitedError,\n ApiForbiddenError,\n ApiRequestTimeoutError,\n ApiEndUserError,\n ApiBadRequestError,\n ApiUnauthorizedError,\n ApiDependencyBackoffError,\n ApiConnectionError,\n ApiEndpointNotFoundError,\n ApiConflictError,\n ApiUnprocessableError,\n ApiPreconditionFailedError,\n ApiUnsupportedMediaTypeError,\n ApiNotImplementedError,\n ApiCodedError,\n ApiClientTooOldError,\n ApiEndUserNotFoundError,\n ApiEndUserForbiddenError,\n ApiEndUserBadRequestError,\n EndUserErrorCode,\n EndUserErrorRegistry,\n ClientRole,\n ApiErrorCodec,\n ApiErrorPayload,\n ApiErrorBoundary,\n ApiCallSite,\n ReportableApiFailure,\n RpcCallFailed,\n} from './errors';\nexport type {\n ApiErrorKind,\n ApiStatusCode,\n EdgeHttpStatus,\n EndUserErrorFactory,\n CallSiteBoundary,\n} from './errors';\nexport { ApiErrorHttpStatus } from './http/ApiErrorHttpStatus';\n\n// RFC 6749 / 6750 / 7591 OAuth refusals for app-hosted OAuth endpoints (#1176): the typed error,\n// its one renderer, the Bearer challenge builder and the authorization-endpoint error redirect.\nexport { OAuthErrorCode, OAuthErrorStatus, OAuthText } from './oauth/OAuthErrorCode';\nexport type {\n OAuthHttpStatus,\n InvalidClientStatus,\n OAuthFixedStatusErrorCode,\n BearerErrorCode,\n AuthorizationEndpointErrorCode,\n} from './oauth/OAuthErrorCode';\nexport { OAuthProtocolError, OAuthErrorExtras } from './oauth/OAuthProtocolError';\nexport { OAuthBearerChallenge } from './oauth/OAuthBearerChallenge';\nexport { OAuthErrorBody, OAuthErrorResponse } from './oauth/OAuthErrorResponse';\nexport { OAuthAuthorizationErrorRedirect } from './oauth/OAuthAuthorizationErrorRedirect';\nexport type { PublishedKind, PublishedApiError } from './http/ApiErrorHttpStatus';\n\nexport { Mcp, McpToolProfilesOptions } from './mcp/Mcp';\nexport type { McpToolProfiles } from './mcp/Mcp';\n"]}
@@ -0,0 +1,12 @@
1
+ /** Explicit selections contain at least one profile; runtime validation handles dynamic data. */
2
+ export type McpToolProfiles = readonly [string, ...string[]];
3
+ /** Profile identifiers are application groups, independent of paths and account roles. */
4
+ export declare class Mcp {
5
+ static readonly DEFAULT = "default";
6
+ /** Validate and snapshot authored membership; never broaden an invalid selection. */
7
+ static profiles(profiles: readonly string[], source: string, failure?: (message: string) => Error): McpToolProfiles;
8
+ }
9
+ /** Optional membership for @WpMcpTool; omission means only Mcp.DEFAULT. */
10
+ export declare class McpToolProfilesOptions {
11
+ readonly profiles?: McpToolProfiles;
12
+ }
package/src/mcp/Mcp.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpToolProfilesOptions = exports.Mcp = void 0;
4
+ /** Profile identifiers are application groups, independent of paths and account roles. */
5
+ class Mcp {
6
+ static DEFAULT = 'default';
7
+ /** Validate and snapshot authored membership; never broaden an invalid selection. */
8
+ // webpieces-disable no-function-outside-class -- pure browser-safe membership validator shared across runtime and compiler
9
+ static profiles(profiles, source, failure = (message) => new Error(message)) {
10
+ if (!Array.isArray(profiles) || profiles.length === 0) {
11
+ throw failure(`${source} requires a non-empty profiles array, e.g. [Mcp.DEFAULT].`);
12
+ }
13
+ const seen = new Set();
14
+ for (const profile of profiles) {
15
+ if (typeof profile !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(profile)) {
16
+ throw failure(`${source}: profile identifiers must match [a-z][a-z0-9-]{0,63}.`);
17
+ }
18
+ if (seen.has(profile))
19
+ throw failure(`${source}: duplicate profile '${profile}'.`);
20
+ seen.add(profile);
21
+ }
22
+ return Object.freeze([...profiles].sort());
23
+ }
24
+ }
25
+ exports.Mcp = Mcp;
26
+ /** Optional membership for @WpMcpTool; omission means only Mcp.DEFAULT. */
27
+ class McpToolProfilesOptions {
28
+ profiles;
29
+ }
30
+ exports.McpToolProfilesOptions = McpToolProfilesOptions;
31
+ //# sourceMappingURL=Mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Mcp.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/Mcp.ts"],"names":[],"mappings":";;;AAGA,0FAA0F;AAC1F,MAAa,GAAG;IACZ,MAAM,CAAU,OAAO,GAAG,SAAS,CAAC;IAEpC,qFAAqF;IACrF,2HAA2H;IAC3H,MAAM,CAAC,QAAQ,CACX,QAA2B,EAC3B,MAAc,EACd,UAAsC,CAAC,OAAe,EAAS,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC;QAEpF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,OAAO,CAAC,GAAG,MAAM,2DAA2D,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBACzE,MAAM,OAAO,CAAC,GAAG,MAAM,wDAAwD,CAAC,CAAC;YACrF,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,MAAM,OAAO,CAAC,GAAG,MAAM,wBAAwB,OAAO,IAAI,CAAC,CAAC;YACnF,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAoB,CAAC;IAClE,CAAC;;AAtBL,kBAuBC;AAED,2EAA2E;AAC3E,MAAa,sBAAsB;IACtB,QAAQ,CAAmB;CACvC;AAFD,wDAEC","sourcesContent":["/** Explicit selections contain at least one profile; runtime validation handles dynamic data. */\nexport type McpToolProfiles = readonly [string, ...string[]];\n\n/** Profile identifiers are application groups, independent of paths and account roles. */\nexport class Mcp {\n static readonly DEFAULT = 'default';\n\n /** Validate and snapshot authored membership; never broaden an invalid selection. */\n // webpieces-disable no-function-outside-class -- pure browser-safe membership validator shared across runtime and compiler\n static profiles(\n profiles: readonly string[],\n source: string,\n failure: (message: string) => Error = (message: string): Error => new Error(message),\n ): McpToolProfiles {\n if (!Array.isArray(profiles) || profiles.length === 0) {\n throw failure(`${source} requires a non-empty profiles array, e.g. [Mcp.DEFAULT].`);\n }\n const seen = new Set<string>();\n for (const profile of profiles) {\n if (typeof profile !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(profile)) {\n throw failure(`${source}: profile identifiers must match [a-z][a-z0-9-]{0,63}.`);\n }\n if (seen.has(profile)) throw failure(`${source}: duplicate profile '${profile}'.`);\n seen.add(profile);\n }\n return Object.freeze([...profiles].sort()) as McpToolProfiles;\n }\n}\n\n/** Optional membership for @WpMcpTool; omission means only Mcp.DEFAULT. */\nexport class McpToolProfilesOptions {\n readonly profiles?: McpToolProfiles;\n}\n"]}
@@ -41,6 +41,10 @@ tslib_1.__decorate([
41
41
  tslib_1.__metadata("design:returntype", Promise)
42
42
  ], InvalidMcpContract.prototype, "hints", null);
43
43
  class InvalidMcpArities {
44
+ // @ts-expect-error explicit profile membership is nonempty; omit options for Mcp.DEFAULT
45
+ emptyProfiles(_request) {
46
+ throw new Error('contract only');
47
+ }
44
48
  // @ts-expect-error MCP tools require exactly one request DTO
45
49
  zero() {
46
50
  throw new Error('contract only');
@@ -50,6 +54,12 @@ class InvalidMcpArities {
50
54
  throw new Error('contract only');
51
55
  }
52
56
  }
57
+ tslib_1.__decorate([
58
+ (0, McpMetadata_1.WpMcpTool)('empty_profiles', 'Empty profiles', { profiles: [] }),
59
+ tslib_1.__metadata("design:type", Function),
60
+ tslib_1.__metadata("design:paramtypes", [Object]),
61
+ tslib_1.__metadata("design:returntype", Promise)
62
+ ], InvalidMcpArities.prototype, "emptyProfiles", null);
53
63
  tslib_1.__decorate([
54
64
  (0, McpMetadata_1.WpMcpTool)('zero-arity', 'Zero arity'),
55
65
  tslib_1.__metadata("design:type", Function),
@@ -1 +1 @@
1
- {"version":3,"file":"McpCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpCompileAssertions.ts"],"names":[],"mappings":";;;AAAA,+CAA0C;AAE1C;;;;;GAKG;AACH,MAAe,kBAAkB;IAC7B,gGAAgG;IAEhG,OAAO,CAAC,QAAgB;QACpB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,mGAAmG;IAEnG,QAAQ,CAAC,QAAgB;QACrB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,sFAAsF;IAEtF,KAAK,CAAC,QAAgB;QAClB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;CACJ;AAfG;IADC,IAAA,uBAAS,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;;;iDAG9B;AAID;IADC,IAAA,uBAAS,EAAC,eAAe,CAAC;;;;kDAG1B;AAID;IADC,IAAA,uBAAS,EAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC;;;;+CAG1C;AAGL,MAAe,iBAAiB;IAC5B,6DAA6D;IAE7D,IAAI;QACA,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,6DAA6D;IAE7D,KAAK,CAAC,MAAc,EAAE,OAAe;QACjC,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;CACJ;AATG;IADC,IAAA,uBAAS,EAAC,YAAY,EAAE,YAAY,CAAC;;;;6CAGrC;AAID;IADC,IAAA,uBAAS,EAAC,aAAa,EAAE,aAAa,CAAC;;;;8CAGvC;AAGL,KAAK,kBAAkB,CAAC;AACxB,KAAK,iBAAiB,CAAC","sourcesContent":["import { WpMcpTool } from './McpMetadata';\n\n/**\n * Compile-time pins for `@WpMcpTool`. These live in a COMPILED file rather than a `.spec.ts` because\n * vitest strips types with esbuild and `tsconfig.lib.json` excludes specs, so a `@ts-expect-error` in\n * a spec is inert (`.claude/rules/no-backwards-compat.md` shim shape #4). Here, tsc fails the build\n * with TS2578 the moment one of these starts compiling.\n */\nabstract class InvalidMcpContract {\n // @ts-expect-error @WpMcpTool takes the stable protocol NAME and a TITLE, not an options object\n @WpMcpTool({ name: 'invalid' })\n options(_request: object): Promise<object> {\n throw new Error('contract only');\n }\n\n // @ts-expect-error the title is REQUIRED (#1180) — the one-argument spelling is gone, not optional\n @WpMcpTool('missing_title')\n untitled(_request: object): Promise<object> {\n throw new Error('contract only');\n }\n\n // @ts-expect-error side-effect claims belong on @Endpoint.operation, never @WpMcpTool\n @WpMcpTool('invalid', 'Invalid tool', true)\n hints(_request: object): Promise<object> {\n throw new Error('contract only');\n }\n}\n\nabstract class InvalidMcpArities {\n // @ts-expect-error MCP tools require exactly one request DTO\n @WpMcpTool('zero-arity', 'Zero arity')\n zero(): Promise<object> {\n throw new Error('contract only');\n }\n\n // @ts-expect-error MCP tools require exactly one request DTO\n @WpMcpTool('multi-arity', 'Multi arity')\n multi(_first: object, _second: object): Promise<object> {\n throw new Error('contract only');\n }\n}\n\nvoid InvalidMcpContract;\nvoid InvalidMcpArities;\n"]}
1
+ {"version":3,"file":"McpCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpCompileAssertions.ts"],"names":[],"mappings":";;;AAAA,+CAA0C;AAE1C;;;;;GAKG;AACH,MAAe,kBAAkB;IAC7B,gGAAgG;IAEhG,OAAO,CAAC,QAAgB;QACpB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,mGAAmG;IAEnG,QAAQ,CAAC,QAAgB;QACrB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,sFAAsF;IAEtF,KAAK,CAAC,QAAgB;QAClB,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;CACJ;AAfG;IADC,IAAA,uBAAS,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;;;iDAG9B;AAID;IADC,IAAA,uBAAS,EAAC,eAAe,CAAC;;;;kDAG1B;AAID;IADC,IAAA,uBAAS,EAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC;;;;+CAG1C;AAGL,MAAe,iBAAiB;IAC5B,yFAAyF;IAEzF,aAAa,CAAC,QAAgB;QAC1B,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,6DAA6D;IAE7D,IAAI;QACA,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,6DAA6D;IAE7D,KAAK,CAAC,MAAc,EAAE,OAAe;QACjC,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;CACJ;AAfG;IADC,IAAA,uBAAS,EAAC,gBAAgB,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;;;;sDAG/D;AAID;IADC,IAAA,uBAAS,EAAC,YAAY,EAAE,YAAY,CAAC;;;;6CAGrC;AAID;IADC,IAAA,uBAAS,EAAC,aAAa,EAAE,aAAa,CAAC;;;;8CAGvC;AAGL,KAAK,kBAAkB,CAAC;AACxB,KAAK,iBAAiB,CAAC","sourcesContent":["import { WpMcpTool } from './McpMetadata';\n\n/**\n * Compile-time pins for `@WpMcpTool`. These live in a COMPILED file rather than a `.spec.ts` because\n * vitest strips types with esbuild and `tsconfig.lib.json` excludes specs, so a `@ts-expect-error` in\n * a spec is inert (`.claude/rules/no-backwards-compat.md` shim shape #4). Here, tsc fails the build\n * with TS2578 the moment one of these starts compiling.\n */\nabstract class InvalidMcpContract {\n // @ts-expect-error @WpMcpTool takes the stable protocol NAME and a TITLE, not an options object\n @WpMcpTool({ name: 'invalid' })\n options(_request: object): Promise<object> {\n throw new Error('contract only');\n }\n\n // @ts-expect-error the title is REQUIRED (#1180) — the one-argument spelling is gone, not optional\n @WpMcpTool('missing_title')\n untitled(_request: object): Promise<object> {\n throw new Error('contract only');\n }\n\n // @ts-expect-error side-effect claims belong on @Endpoint.operation, never @WpMcpTool\n @WpMcpTool('invalid', 'Invalid tool', true)\n hints(_request: object): Promise<object> {\n throw new Error('contract only');\n }\n}\n\nabstract class InvalidMcpArities {\n // @ts-expect-error explicit profile membership is nonempty; omit options for Mcp.DEFAULT\n @WpMcpTool('empty_profiles', 'Empty profiles', { profiles: [] })\n emptyProfiles(_request: object): Promise<object> {\n throw new Error('contract only');\n }\n\n // @ts-expect-error MCP tools require exactly one request DTO\n @WpMcpTool('zero-arity', 'Zero arity')\n zero(): Promise<object> {\n throw new Error('contract only');\n }\n\n // @ts-expect-error MCP tools require exactly one request DTO\n @WpMcpTool('multi-arity', 'Multi arity')\n multi(_first: object, _second: object): Promise<object> {\n throw new Error('contract only');\n }\n}\n\nvoid InvalidMcpContract;\nvoid InvalidMcpArities;\n"]}
@@ -1,4 +1,5 @@
1
1
  import 'reflect-metadata';
2
+ import { McpToolProfilesOptions } from './Mcp';
2
3
  import { EndpointOperation } from '../http/HttpEndpointOptions';
3
4
  /** The immutable hints MCP clients use when deciding whether and how to call a tool. */
4
5
  export declare class WpMcpToolHints {
@@ -19,9 +20,10 @@ export declare class WpMcpToolMetadata {
19
20
  readonly name: string;
20
21
  /** The human-readable display name; `tools/list` publishes it as `title` AND `annotations.title`. */
21
22
  readonly title: string;
23
+ readonly profiles: readonly string[];
22
24
  constructor(methodName: string, name: string,
23
25
  /** The human-readable display name; `tools/list` publishes it as `title` AND `annotations.title`. */
24
- title: string);
26
+ title: string, profiles: readonly string[]);
25
27
  }
26
28
  /**
27
29
  * Explicitly publishes an existing `@Endpoint(POST, path, WRITE, RPC)` method as an MCP tool, under
@@ -31,7 +33,8 @@ export declare class WpMcpToolMetadata {
31
33
  * @WpMcpTool('learner_get_passages', 'Get your passages')
32
34
  * ```
33
35
  *
34
- * Those two are the whole argument list — the only facts about a tool the source cannot otherwise
36
+ * The optional third argument selects profiles; omission selects only Mcp.DEFAULT.
37
+ * The name and title are facts the source cannot otherwise
35
38
  * state:
36
39
  *
37
40
  * | fact | where it comes from |
@@ -55,7 +58,7 @@ export declare class WpMcpToolMetadata {
55
58
  * one paragraph drift the first time somebody edits one, so it is gone; the title is a short NAME,
56
59
  * not a second copy of the description.
57
60
  */
58
- export declare function WpMcpTool(name: string, title: string): WpMcpMethodDecorator;
61
+ export declare function WpMcpTool(name: string, title: string, options?: McpToolProfilesOptions): WpMcpMethodDecorator;
59
62
  /** Runtime metadata for one endpoint declared PERMANENTLY outside MCP. */
60
63
  export declare class InvalidEndpointForMcpMetadata {
61
64
  readonly methodName: string;
@@ -7,6 +7,7 @@ exports.getInvalidEndpointsForMcp = getInvalidEndpointsForMcp;
7
7
  exports.mcpHintsForOperation = mcpHintsForOperation;
8
8
  exports.getWpMcpTools = getWpMcpTools;
9
9
  require("reflect-metadata");
10
+ const Mcp_1 = require("./Mcp");
10
11
  const decorators_1 = require("../http/decorators");
11
12
  const HttpEndpointOptions_1 = require("../http/HttpEndpointOptions");
12
13
  /** The immutable hints MCP clients use when deciding whether and how to call a tool. */
@@ -28,12 +29,14 @@ class WpMcpToolMetadata {
28
29
  methodName;
29
30
  name;
30
31
  title;
32
+ profiles;
31
33
  constructor(methodName, name,
32
34
  /** The human-readable display name; `tools/list` publishes it as `title` AND `annotations.title`. */
33
- title) {
35
+ title, profiles) {
34
36
  this.methodName = methodName;
35
37
  this.name = name;
36
38
  this.title = title;
39
+ this.profiles = profiles;
37
40
  }
38
41
  }
39
42
  exports.WpMcpToolMetadata = WpMcpToolMetadata;
@@ -45,7 +48,8 @@ exports.WpMcpToolMetadata = WpMcpToolMetadata;
45
48
  * @WpMcpTool('learner_get_passages', 'Get your passages')
46
49
  * ```
47
50
  *
48
- * Those two are the whole argument list — the only facts about a tool the source cannot otherwise
51
+ * The optional third argument selects profiles; omission selects only Mcp.DEFAULT.
52
+ * The name and title are facts the source cannot otherwise
49
53
  * state:
50
54
  *
51
55
  * | fact | where it comes from |
@@ -70,7 +74,15 @@ exports.WpMcpToolMetadata = WpMcpToolMetadata;
70
74
  * not a second copy of the description.
71
75
  */
72
76
  // webpieces-disable no-function-outside-class -- decorator factories are inherently module-scope
73
- function WpMcpTool(name, title) {
77
+ function WpMcpTool(name, title, options) {
78
+ if (options !== undefined &&
79
+ (typeof options !== 'object' ||
80
+ options === null ||
81
+ Array.isArray(options) ||
82
+ Object.keys(options).some((key) => key !== 'profiles'))) {
83
+ throw new Error('@WpMcpTool options must be an object containing only profiles.');
84
+ }
85
+ const profiles = Mcp_1.Mcp.profiles(options !== undefined && 'profiles' in options ? options.profiles : [Mcp_1.Mcp.DEFAULT], '@WpMcpTool');
74
86
  if (name.trim() === '')
75
87
  throw new Error('@WpMcpTool requires a non-empty stable name.');
76
88
  if (title.trim() === '') {
@@ -82,7 +94,7 @@ function WpMcpTool(name, title) {
82
94
  const apiClass = target.constructor;
83
95
  const tools = Reflect.getMetadata(decorators_1.METADATA_KEYS.MCP_TOOLS, apiClass) ?? {};
84
96
  const methodName = String(propertyKey);
85
- tools[methodName] = new WpMcpToolMetadata(methodName, name, title);
97
+ tools[methodName] = new WpMcpToolMetadata(methodName, name, title, profiles);
86
98
  Reflect.defineMetadata(decorators_1.METADATA_KEYS.MCP_TOOLS, tools, apiClass);
87
99
  };
88
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"McpMetadata.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import 'reflect-metadata';\nimport { METADATA_KEYS } from '../http/decorators';\nimport { EndpointOperation, READ, WRITE_IDEMPOTENT, WRITE } from '../http/HttpEndpointOptions';\n\n/** The immutable hints MCP clients use when deciding whether and how to call a tool. */\nexport class WpMcpToolHints {\n constructor(\n public readonly readOnlyHint: boolean,\n public readonly destructiveHint: boolean,\n public readonly idempotentHint: boolean,\n public readonly openWorldHint: boolean,\n ) {}\n}\n\ntype AsyncObjectMethod = (...args: never[]) => Promise<object>;\ntype ExactOneParameter<TMethod extends AsyncObjectMethod> = Parameters<TMethod>['length'] extends 1\n ? object\n : never;\ntype ExactOneMethodDescriptor<TMethod extends AsyncObjectMethod> =\n TypedPropertyDescriptor<TMethod> & ExactOneParameter<TMethod>;\n\n/** Method decorator restricted to one request DTO and one async response DTO. */\nexport type WpMcpMethodDecorator = <TMethod extends AsyncObjectMethod>(\n target: object,\n propertyKey: string | symbol,\n descriptor: ExactOneMethodDescriptor<TMethod>,\n) => void;\n\n/** Runtime metadata for one explicitly exposed endpoint. */\nexport class WpMcpToolMetadata {\n constructor(\n public readonly methodName: string,\n public readonly name: string,\n /** The human-readable display name; `tools/list` publishes it as `title` AND `annotations.title`. */\n public readonly title: string,\n ) {}\n}\n\n/**\n * Explicitly publishes an existing `@Endpoint(POST, path, WRITE, RPC)` method as an MCP tool, under\n * the STABLE protocol name and the human-readable TITLE given here.\n *\n * ```typescript\n * @WpMcpTool('learner_get_passages', 'Get your passages')\n * ```\n *\n * Those two are the whole argument list — the only facts about a tool the source cannot otherwise\n * state:\n *\n * | fact | where it comes from |\n * |---|---|\n * | `name` | this decorator — the stable protocol identity, independent of the method name because renaming a method must not break a saved agent workflow |\n * | `title` | this decorator — the display name clients and the Claude Connectors Directory show; published as BOTH `Tool.title` and `annotations.title` |\n * | `description` | the method's JSDoc body, or its `@mcp` tag — the same words the partner reads |\n * | `readOnlyHint` / `destructiveHint` / `idempotentHint` | `@Endpoint`'s `operation`, via {@link mcpHintsForOperation} |\n * | `openWorldHint` | `@Endpoint`'s `openWorld` option |\n * | `inputSchema` / `outputSchema` | the declared request and response types |\n *\n * ## Why the title is REQUIRED and never derived (#1180)\n *\n * The Connectors Directory flags every tool without `annotations.title`. An optional title gets\n * skipped and the miss surfaces only at directory-submission time, so it is a compile-time\n * requirement and an empty or whitespace one throws at decoration time. It is never computed from\n * the name: `learner_get_passages` → \"Learner get passages\" is exactly the mechanical listing text\n * reviewers push back on, and the area prefix means nothing to an end user.\n *\n * Until #984 the decorator also took a `description`, duplicating the JSDoc. Two authored copies of\n * one paragraph drift the first time somebody edits one, so it is gone; the title is a short NAME,\n * not a second copy of the description.\n */\n// webpieces-disable no-function-outside-class -- decorator factories are inherently module-scope\nexport function WpMcpTool(name: string, title: string): WpMcpMethodDecorator {\n if (name.trim() === '') throw new Error('@WpMcpTool requires a non-empty stable name.');\n if (title.trim() === '') {\n throw new Error(\n `@WpMcpTool('${name}', ...) requires a non-empty human-readable title, e.g. ` +\n \"@WpMcpTool('learner_get_passages', 'Get your passages'). tools/list publishes it as \" +\n 'title and annotations.title, and the Claude Connectors Directory flags a tool without one.',\n );\n }\n return <TMethod extends AsyncObjectMethod>(\n target: object,\n propertyKey: string | symbol,\n _descriptor: ExactOneMethodDescriptor<TMethod>,\n ): void => {\n const apiClass = target.constructor;\n const tools: Record<string, WpMcpToolMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_TOOLS, apiClass) ?? {};\n const methodName = String(propertyKey);\n tools[methodName] = new WpMcpToolMetadata(methodName, name, title);\n Reflect.defineMetadata(METADATA_KEYS.MCP_TOOLS, tools, apiClass);\n };\n}\n\n/** Runtime metadata for one endpoint declared PERMANENTLY outside MCP. */\nexport class InvalidEndpointForMcpMetadata {\n constructor(\n public readonly methodName: string,\n /** WHY it can never be a tool. Non-empty, enforced at decoration time. */\n public readonly reason: string,\n ) {}\n}\n\n/**\n * Declares that this endpoint is PERMANENTLY outside MCP, and says why.\n *\n * ## It is not a suppression, and that distinction is the whole feature\n *\n * `// webpieces-disable api-rules-for-mcp -- <reason>` says \"stop complaining\". This says \"this is\n * structurally impossible, forever\", and the two have different futures: a suppression is something\n * somebody should eventually come back to, and this is something nobody should. Both measured cases\n * are types that are CORRECT and must not be \"fixed\" —\n *\n * - a webhook TRANSPORT envelope, whose `data` is owned by each event's own published contract;\n * typing it here would fork that ownership and make adding an event type a change to the\n * transport contract rather than a registration, and\n * - a freeform-SQL escape hatch, whose result columns depend on the model-authored `SELECT`.\n *\n * The second one is worth stating rather than burying: it is the most obviously useful tool in that\n * repo, and it is excluded by a type that is right.\n *\n * ## Absence already says \"not a tool YET\"\n *\n * A method with no `@WpMcpTool` is simply not published. This decorator is the NEVER, and the reason\n * is what makes `grep -rn InvalidEndpointForMcp` a list of permanent exclusions with their arguments\n * rather than a list of names. `api-rules-for-mcp` restates that list on every run, so an exclusion\n * stays visible instead of being announced once and forgotten.\n *\n * ## It contradicts `@WpMcpTool`\n *\n * Both on one method is an ERROR, asserted by {@link assertApiTypeMatchesMcpTools}. \"Publish this as\n * a tool\" and \"this can never be a tool\" are two spellings of one decision, which is exactly the\n * defect `.claude/rules/no-backwards-compat.md` shim shape #1 rejects.\n *\n * ```typescript\n * @InvalidEndpointForMcp('a transport envelope body is opaque by design; the published partner ' +\n * 'contract for each event type owns its shape')\n * ```\n */\n// webpieces-disable no-function-outside-class -- decorator factories are inherently module-scope\nexport function InvalidEndpointForMcp(reason: string): MethodDecorator {\n if (reason.trim() === '') {\n throw new Error(\n '@InvalidEndpointForMcp requires a non-empty reason. The reason IS the declaration — ' +\n 'without it this is a suppression with a longer name.',\n );\n }\n return (target: object, propertyKey: string | symbol): void => {\n const apiClass = target.constructor;\n const excluded: Record<string, InvalidEndpointForMcpMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_INVALID, apiClass) ?? {};\n const methodName = String(propertyKey);\n excluded[methodName] = new InvalidEndpointForMcpMetadata(methodName, reason);\n Reflect.defineMetadata(METADATA_KEYS.MCP_INVALID, excluded, apiClass);\n };\n}\n\n/** Every method declared permanently outside MCP by {@link InvalidEndpointForMcp}. */\n// webpieces-disable no-function-outside-class -- metadata reader paired with the decorator\nexport function getInvalidEndpointsForMcp(apiClass: Function): InvalidEndpointForMcpMetadata[] {\n const excluded: Record<string, InvalidEndpointForMcpMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_INVALID, apiClass) ?? {};\n return Object.values(excluded);\n}\n\n/** The one mapping from endpoint side effects to MCP advisory annotations. */\n// webpieces-disable no-function-outside-class -- pure metadata mapping shared by MCP registration\nexport function mcpHintsForOperation(\n operation: EndpointOperation,\n openWorldHint: boolean,\n): WpMcpToolHints {\n switch (operation) {\n case READ:\n return new WpMcpToolHints(true, false, true, openWorldHint);\n case WRITE_IDEMPOTENT:\n return new WpMcpToolHints(false, true, true, openWorldHint);\n case WRITE:\n return new WpMcpToolHints(false, true, false, openWorldHint);\n }\n}\n\n/** Returns only methods explicitly opted in through {@link WpMcpTool}. */\n// webpieces-disable no-function-outside-class -- metadata reader paired with the decorator\nexport function getWpMcpTools(apiClass: Function): WpMcpToolMetadata[] {\n const tools: Record<string, WpMcpToolMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_TOOLS, apiClass) ?? {};\n return Object.values(tools);\n}\n"]}
1
+ {"version":3,"file":"McpMetadata.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpMetadata.ts"],"names":[],"mappings":"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","sourcesContent":["import 'reflect-metadata';\nimport { Mcp, McpToolProfilesOptions } from './Mcp';\nimport { METADATA_KEYS } from '../http/decorators';\nimport { EndpointOperation, READ, WRITE_IDEMPOTENT, WRITE } from '../http/HttpEndpointOptions';\n\n/** The immutable hints MCP clients use when deciding whether and how to call a tool. */\nexport class WpMcpToolHints {\n constructor(\n public readonly readOnlyHint: boolean,\n public readonly destructiveHint: boolean,\n public readonly idempotentHint: boolean,\n public readonly openWorldHint: boolean,\n ) {}\n}\n\ntype AsyncObjectMethod = (...args: never[]) => Promise<object>;\ntype ExactOneParameter<TMethod extends AsyncObjectMethod> = Parameters<TMethod>['length'] extends 1\n ? object\n : never;\ntype ExactOneMethodDescriptor<TMethod extends AsyncObjectMethod> =\n TypedPropertyDescriptor<TMethod> & ExactOneParameter<TMethod>;\n\n/** Method decorator restricted to one request DTO and one async response DTO. */\nexport type WpMcpMethodDecorator = <TMethod extends AsyncObjectMethod>(\n target: object,\n propertyKey: string | symbol,\n descriptor: ExactOneMethodDescriptor<TMethod>,\n) => void;\n\n/** Runtime metadata for one explicitly exposed endpoint. */\nexport class WpMcpToolMetadata {\n constructor(\n public readonly methodName: string,\n public readonly name: string,\n /** The human-readable display name; `tools/list` publishes it as `title` AND `annotations.title`. */\n public readonly title: string,\n public readonly profiles: readonly string[],\n ) {}\n}\n\n/**\n * Explicitly publishes an existing `@Endpoint(POST, path, WRITE, RPC)` method as an MCP tool, under\n * the STABLE protocol name and the human-readable TITLE given here.\n *\n * ```typescript\n * @WpMcpTool('learner_get_passages', 'Get your passages')\n * ```\n *\n * The optional third argument selects profiles; omission selects only Mcp.DEFAULT.\n * The name and title are facts the source cannot otherwise\n * state:\n *\n * | fact | where it comes from |\n * |---|---|\n * | `name` | this decorator — the stable protocol identity, independent of the method name because renaming a method must not break a saved agent workflow |\n * | `title` | this decorator — the display name clients and the Claude Connectors Directory show; published as BOTH `Tool.title` and `annotations.title` |\n * | `description` | the method's JSDoc body, or its `@mcp` tag — the same words the partner reads |\n * | `readOnlyHint` / `destructiveHint` / `idempotentHint` | `@Endpoint`'s `operation`, via {@link mcpHintsForOperation} |\n * | `openWorldHint` | `@Endpoint`'s `openWorld` option |\n * | `inputSchema` / `outputSchema` | the declared request and response types |\n *\n * ## Why the title is REQUIRED and never derived (#1180)\n *\n * The Connectors Directory flags every tool without `annotations.title`. An optional title gets\n * skipped and the miss surfaces only at directory-submission time, so it is a compile-time\n * requirement and an empty or whitespace one throws at decoration time. It is never computed from\n * the name: `learner_get_passages` → \"Learner get passages\" is exactly the mechanical listing text\n * reviewers push back on, and the area prefix means nothing to an end user.\n *\n * Until #984 the decorator also took a `description`, duplicating the JSDoc. Two authored copies of\n * one paragraph drift the first time somebody edits one, so it is gone; the title is a short NAME,\n * not a second copy of the description.\n */\n// webpieces-disable no-function-outside-class -- decorator factories are inherently module-scope\nexport function WpMcpTool(\n name: string,\n title: string,\n options?: McpToolProfilesOptions,\n): WpMcpMethodDecorator {\n if (\n options !== undefined &&\n (typeof options !== 'object' ||\n options === null ||\n Array.isArray(options) ||\n Object.keys(options).some((key: string) => key !== 'profiles'))\n ) {\n throw new Error('@WpMcpTool options must be an object containing only profiles.');\n }\n const profiles = Mcp.profiles(\n options !== undefined && 'profiles' in options ? options.profiles! : [Mcp.DEFAULT],\n '@WpMcpTool',\n );\n if (name.trim() === '') throw new Error('@WpMcpTool requires a non-empty stable name.');\n if (title.trim() === '') {\n throw new Error(\n `@WpMcpTool('${name}', ...) requires a non-empty human-readable title, e.g. ` +\n \"@WpMcpTool('learner_get_passages', 'Get your passages'). tools/list publishes it as \" +\n 'title and annotations.title, and the Claude Connectors Directory flags a tool without one.',\n );\n }\n return <TMethod extends AsyncObjectMethod>(\n target: object,\n propertyKey: string | symbol,\n _descriptor: ExactOneMethodDescriptor<TMethod>,\n ): void => {\n const apiClass = target.constructor;\n const tools: Record<string, WpMcpToolMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_TOOLS, apiClass) ?? {};\n const methodName = String(propertyKey);\n tools[methodName] = new WpMcpToolMetadata(methodName, name, title, profiles);\n Reflect.defineMetadata(METADATA_KEYS.MCP_TOOLS, tools, apiClass);\n };\n}\n\n/** Runtime metadata for one endpoint declared PERMANENTLY outside MCP. */\nexport class InvalidEndpointForMcpMetadata {\n constructor(\n public readonly methodName: string,\n /** WHY it can never be a tool. Non-empty, enforced at decoration time. */\n public readonly reason: string,\n ) {}\n}\n\n/**\n * Declares that this endpoint is PERMANENTLY outside MCP, and says why.\n *\n * ## It is not a suppression, and that distinction is the whole feature\n *\n * `// webpieces-disable api-rules-for-mcp -- <reason>` says \"stop complaining\". This says \"this is\n * structurally impossible, forever\", and the two have different futures: a suppression is something\n * somebody should eventually come back to, and this is something nobody should. Both measured cases\n * are types that are CORRECT and must not be \"fixed\" —\n *\n * - a webhook TRANSPORT envelope, whose `data` is owned by each event's own published contract;\n * typing it here would fork that ownership and make adding an event type a change to the\n * transport contract rather than a registration, and\n * - a freeform-SQL escape hatch, whose result columns depend on the model-authored `SELECT`.\n *\n * The second one is worth stating rather than burying: it is the most obviously useful tool in that\n * repo, and it is excluded by a type that is right.\n *\n * ## Absence already says \"not a tool YET\"\n *\n * A method with no `@WpMcpTool` is simply not published. This decorator is the NEVER, and the reason\n * is what makes `grep -rn InvalidEndpointForMcp` a list of permanent exclusions with their arguments\n * rather than a list of names. `api-rules-for-mcp` restates that list on every run, so an exclusion\n * stays visible instead of being announced once and forgotten.\n *\n * ## It contradicts `@WpMcpTool`\n *\n * Both on one method is an ERROR, asserted by {@link assertApiTypeMatchesMcpTools}. \"Publish this as\n * a tool\" and \"this can never be a tool\" are two spellings of one decision, which is exactly the\n * defect `.claude/rules/no-backwards-compat.md` shim shape #1 rejects.\n *\n * ```typescript\n * @InvalidEndpointForMcp('a transport envelope body is opaque by design; the published partner ' +\n * 'contract for each event type owns its shape')\n * ```\n */\n// webpieces-disable no-function-outside-class -- decorator factories are inherently module-scope\nexport function InvalidEndpointForMcp(reason: string): MethodDecorator {\n if (reason.trim() === '') {\n throw new Error(\n '@InvalidEndpointForMcp requires a non-empty reason. The reason IS the declaration — ' +\n 'without it this is a suppression with a longer name.',\n );\n }\n return (target: object, propertyKey: string | symbol): void => {\n const apiClass = target.constructor;\n const excluded: Record<string, InvalidEndpointForMcpMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_INVALID, apiClass) ?? {};\n const methodName = String(propertyKey);\n excluded[methodName] = new InvalidEndpointForMcpMetadata(methodName, reason);\n Reflect.defineMetadata(METADATA_KEYS.MCP_INVALID, excluded, apiClass);\n };\n}\n\n/** Every method declared permanently outside MCP by {@link InvalidEndpointForMcp}. */\n// webpieces-disable no-function-outside-class -- metadata reader paired with the decorator\nexport function getInvalidEndpointsForMcp(apiClass: Function): InvalidEndpointForMcpMetadata[] {\n const excluded: Record<string, InvalidEndpointForMcpMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_INVALID, apiClass) ?? {};\n return Object.values(excluded);\n}\n\n/** The one mapping from endpoint side effects to MCP advisory annotations. */\n// webpieces-disable no-function-outside-class -- pure metadata mapping shared by MCP registration\nexport function mcpHintsForOperation(\n operation: EndpointOperation,\n openWorldHint: boolean,\n): WpMcpToolHints {\n switch (operation) {\n case READ:\n return new WpMcpToolHints(true, false, true, openWorldHint);\n case WRITE_IDEMPOTENT:\n return new WpMcpToolHints(false, true, true, openWorldHint);\n case WRITE:\n return new WpMcpToolHints(false, true, false, openWorldHint);\n }\n}\n\n/** Returns only methods explicitly opted in through {@link WpMcpTool}. */\n// webpieces-disable no-function-outside-class -- metadata reader paired with the decorator\nexport function getWpMcpTools(apiClass: Function): WpMcpToolMetadata[] {\n const tools: Record<string, WpMcpToolMetadata> =\n Reflect.getMetadata(METADATA_KEYS.MCP_TOOLS, apiClass) ?? {};\n return Object.values(tools);\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { ApiJsonSchema } from './DtoSchema';
2
2
  import { WpMcpToolHints } from './McpMetadata';
3
3
  /**
4
- * ONE MCP tool, as `tools/list` publishes it.
4
+ * ONE generated MCP tool definition, including server-only profile membership.
5
5
  *
6
6
  * It is BUILT from the source by `@webpieces/api-doc-model`'s `McpSchemaRenderer` at build time, and
7
7
  * READ here at boot — so the tool an agent is shown and the tool the server accepts are the same
@@ -36,6 +36,7 @@ export declare class McpToolDefinition {
36
36
  readonly hints: WpMcpToolHints;
37
37
  readonly inputSchema: ApiJsonSchema;
38
38
  readonly outputSchema: ApiJsonSchema;
39
+ readonly profiles: readonly string[];
39
40
  constructor(
40
41
  /** The stable protocol name from `@WpMcpTool('<name>', '<title>')`. */
41
42
  name: string,
@@ -58,7 +59,7 @@ export declare class McpToolDefinition {
58
59
  * `mcpHintsForOperation`, which is the one place that mapping lives; `openWorldHint` comes
59
60
  * from `@Endpoint`'s `openWorld` option.
60
61
  */
61
- hints: WpMcpToolHints, inputSchema: ApiJsonSchema, outputSchema: ApiJsonSchema);
62
+ hints: WpMcpToolHints, inputSchema: ApiJsonSchema, outputSchema: ApiJsonSchema, profiles: readonly string[]);
62
63
  }
63
64
  /** Thrown when a catalog is not one this release can read or write. */
64
65
  export declare class McpToolCatalogError extends Error {
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.McpToolCatalogFile = exports.McpToolCatalogError = exports.McpToolDefinition = void 0;
4
4
  const DtoSchema_1 = require("./DtoSchema");
5
+ const Mcp_1 = require("./Mcp");
5
6
  const McpMetadata_1 = require("./McpMetadata");
6
7
  /**
7
- * ONE MCP tool, as `tools/list` publishes it.
8
+ * ONE generated MCP tool definition, including server-only profile membership.
8
9
  *
9
10
  * It is BUILT from the source by `@webpieces/api-doc-model`'s `McpSchemaRenderer` at build time, and
10
11
  * READ here at boot — so the tool an agent is shown and the tool the server accepts are the same
@@ -22,6 +23,7 @@ class McpToolDefinition {
22
23
  hints;
23
24
  inputSchema;
24
25
  outputSchema;
26
+ profiles;
25
27
  constructor(
26
28
  /** The stable protocol name from `@WpMcpTool('<name>', '<title>')`. */
27
29
  name,
@@ -44,7 +46,7 @@ class McpToolDefinition {
44
46
  * `mcpHintsForOperation`, which is the one place that mapping lives; `openWorldHint` comes
45
47
  * from `@Endpoint`'s `openWorld` option.
46
48
  */
47
- hints, inputSchema, outputSchema) {
49
+ hints, inputSchema, outputSchema, profiles) {
48
50
  this.name = name;
49
51
  this.title = title;
50
52
  this.methodName = methodName;
@@ -52,6 +54,8 @@ class McpToolDefinition {
52
54
  this.hints = hints;
53
55
  this.inputSchema = inputSchema;
54
56
  this.outputSchema = outputSchema;
57
+ this.profiles = profiles;
58
+ this.profiles = Mcp_1.Mcp.profiles(profiles, 'MCP catalog tool');
55
59
  }
56
60
  }
57
61
  exports.McpToolDefinition = McpToolDefinition;
@@ -183,7 +187,14 @@ class McpCatalogJson {
183
187
  toolFrom(entry) {
184
188
  const record = this.record(entry, 'a tool definition');
185
189
  const hints = this.record(record['hints'], 'a tool definition hints block');
186
- return new McpToolDefinition(this.text(record['name'], 'name'), this.title(record['title'], record['name']), this.text(record['methodName'], 'methodName'), this.text(record['description'], 'description'), new McpMetadata_1.WpMcpToolHints(hints['readOnlyHint'] === true, hints['destructiveHint'] === true, hints['idempotentHint'] === true, hints['openWorldHint'] === true), this.schemaFrom(record['inputSchema']), this.schemaFrom(record['outputSchema']));
190
+ return new McpToolDefinition(this.text(record['name'], 'name'), this.title(record['title'], record['name']), this.text(record['methodName'], 'methodName'), this.text(record['description'], 'description'), new McpMetadata_1.WpMcpToolHints(hints['readOnlyHint'] === true, hints['destructiveHint'] === true, hints['idempotentHint'] === true, hints['openWorldHint'] === true), this.schemaFrom(record['inputSchema']), this.schemaFrom(record['outputSchema']), this.profiles(record['profiles']));
191
+ }
192
+ // webpieces-disable no-any-unknown -- JSON catalog parse boundary
193
+ profiles(value) {
194
+ if (!Array.isArray(value) || !value.every((entry) => typeof entry === 'string')) {
195
+ throw new McpToolCatalogError('The MCP tool catalog requires profiles (#1187); stale artifacts are refused.', REGENERATE);
196
+ }
197
+ return Mcp_1.Mcp.profiles(value, 'MCP catalog profiles', (message) => new McpToolCatalogError(message, REGENERATE));
187
198
  }
188
199
  // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs
189
200
  schemaFrom(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"McpToolCatalogFile.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpToolCatalogFile.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiJsonSchema, ApiJsonSchemaDiscriminator, ApiJsonSchemaType } from './DtoSchema';\nimport { WpMcpToolHints } from './McpMetadata';\n\n/**\n * ONE MCP tool, as `tools/list` publishes it.\n *\n * It is BUILT from the source by `@webpieces/api-doc-model`'s `McpSchemaRenderer` at build time, and\n * READ here at boot — so the tool an agent is shown and the tool the server accepts are the same\n * bytes by construction, not by two declarations agreeing.\n *\n * It lives in `core-util` rather than in the extractor package because both ends need it and only\n * one end may depend on the TypeScript compiler API. `ApiJsonSchema` and {@link WpMcpToolHints},\n * which it is made of, are already here for the same reason.\n */\nexport class McpToolDefinition {\n constructor(\n /** The stable protocol name from `@WpMcpTool('<name>', '<title>')`. */\n readonly name: string,\n /**\n * The human-readable display name from `@WpMcpTool('<name>', '<title>')`. REQUIRED (#1180):\n * `tools/list` publishes it as both `Tool.title` and `annotations.title`, and a catalog entry\n * without one is refused on load rather than silently publishing an untitled tool.\n */\n readonly title: string,\n /** The contract method it was rendered from, so a mismatch report can name the source. */\n readonly methodName: string,\n /**\n * The tool documentation: the method's `@mcp` tag when it has one, its JSDoc body otherwise.\n * Documentation has exactly ONE source — the doc comment above the declaration — for the\n * partner reading OpenAPI and the agent reading `tools/list` alike.\n */\n readonly description: string,\n /**\n * All four hints. Three are COMPUTED from `@Endpoint`'s `operation` by\n * `mcpHintsForOperation`, which is the one place that mapping lives; `openWorldHint` comes\n * from `@Endpoint`'s `openWorld` option.\n */\n readonly hints: WpMcpToolHints,\n readonly inputSchema: ApiJsonSchema,\n readonly outputSchema: ApiJsonSchema,\n ) {}\n}\n\n/** Thrown when a catalog is not one this release can read or write. */\nexport class McpToolCatalogError extends Error {\n constructor(\n message: string,\n /** What to do instead, in one sentence. */\n readonly cure: string,\n ) {\n super(`${message} ${cure}`);\n this.name = 'McpToolCatalogError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The one cure every catalog failure prescribes: rebuild the artifact from the contracts. */\nconst REGENERATE =\n 'Rebuild the api library that declares the contract (its `openapi-generate` target runs ' +\n '`wp-openapi`, which writes one `mcp-<ContractClass>-tools.json` per MCP contract).';\n\nconst FILE_PREFIX = 'mcp-';\nconst FILE_SUFFIX = '-tools.json';\n\n/** A class name, which is what the file name carries. Anything else is not one of these files. */\nconst CONTRACT_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * ONE contract's MCP tools, keyed by protocol name — the artifact `wp-openapi` writes as\n * `mcp-<ContractClass>-tools.json`, one file per contract that declares `MCP` and has at least one\n * `@WpMcpTool`, beside the library's OpenAPI documents.\n *\n * ## Why one file per CONTRACT and not one per library\n *\n * One api library holds many contracts (it is how a public partner API is grouped), and a server binds\n * contracts, not libraries — `McpApiBinding.local(LangCourseAuthorApi, ...)`. With one file per\n * contract the server can check every binding against exactly the file generated from THAT contract,\n * and refuse a file it was handed for a contract it does not bind. A single per-library file could only\n * say \"some tool is missing\" (#1021).\n *\n * This is the browser-safe CODEC — the bytes and the file name. Reading the files from an installed\n * package is `McpToolCatalog.fromPackages` in `@webpieces/mcp-server`, because only a node process\n * has a filesystem to read them from.\n */\nexport class McpToolCatalogFile {\n private readonly byName: ReadonlyMap<string, McpToolDefinition>;\n\n constructor(\n /** The contract CLASS name — `binding.api.name` at runtime, the class declaration at build time. */\n readonly contractName: string,\n readonly tools: readonly McpToolDefinition[],\n ) {\n if (!CONTRACT_NAME.test(contractName)) {\n throw new McpToolCatalogError(\n `'${contractName}' is not a contract class name, so it cannot name an MCP tool catalog.`,\n REGENERATE,\n );\n }\n const byName = new Map<string, McpToolDefinition>();\n for (const tool of tools) {\n if (byName.has(tool.name)) {\n throw new McpToolCatalogError(\n `Duplicate MCP tool name '${tool.name}' in the generated catalog of ${contractName}.`,\n 'Tool names are the protocol identity and must be globally unique — rename one ' +\n \"of the two @WpMcpTool('<name>', '<title>') declarations.\",\n );\n }\n byName.set(tool.name, tool);\n }\n this.byName = byName;\n }\n\n /** `mcp-<ContractClass>-tools.json`. */\n get fileName(): string {\n return McpToolCatalogFile.fileNameFor(this.contractName);\n }\n\n find(name: string): McpToolDefinition | undefined {\n return this.byName.get(name);\n }\n\n /** The names this catalog carries, sorted, so a failure can print what WAS published. */\n names(): readonly string[] {\n return [...this.byName.keys()].sort();\n }\n\n /** The bytes `wp-openapi` writes. Sorted by name so the artifact is diffable. */\n toJsonText(): string {\n const tools = [...this.tools].sort((left: McpToolDefinition, right: McpToolDefinition) =>\n left.name.localeCompare(right.name),\n );\n return `${JSON.stringify(tools, undefined, 2)}\\n`;\n }\n\n /** The file name the catalog of `contractName` is written to and read from. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static fileNameFor(contractName: string): string {\n return `${FILE_PREFIX}${contractName}${FILE_SUFFIX}`;\n }\n\n /** The contract a file name is the catalog of, or `undefined` when it is not one of these files. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static contractNameOf(fileName: string): string | undefined {\n if (!fileName.startsWith(FILE_PREFIX) || !fileName.endsWith(FILE_SUFFIX)) return undefined;\n const name = fileName.slice(FILE_PREFIX.length, fileName.length - FILE_SUFFIX.length);\n return CONTRACT_NAME.test(name) ? name : undefined;\n }\n\n /**\n * Reads one `mcp-<ContractClass>-tools.json`. The contract is the one the FILE NAME names. Every\n * nested value is rebuilt as a real class instance, because this is the one place untyped bytes\n * become the schemas a live protocol surface publishes.\n *\n * Malformed JSON is not caught here: it throws `SyntaxError` to the caller's own top-level\n * handler, which is where every other read-the-world failure in webpieces is reported.\n */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromJsonText(fileName: string, text: string): McpToolCatalogFile {\n const contractName = McpToolCatalogFile.contractNameOf(fileName);\n if (contractName === undefined) {\n throw new McpToolCatalogError(\n `'${fileName}' is not an MCP tool catalog file name; they are named ` +\n `${FILE_PREFIX}<ContractClass>${FILE_SUFFIX}.`,\n REGENERATE,\n );\n }\n return new McpToolCatalogFile(contractName, new McpCatalogJson().parse(text));\n }\n}\n\n/**\n * The PARSE BOUNDARY: untyped bytes in, real class instances out.\n *\n * A class of its own rather than statics on {@link McpToolCatalogFile} so every step is an ordinary\n * instance method — and because it is the one place in this file where `unknown` is the correct type\n * rather than a missing one. Nothing else in webpieces should ever hold a half-narrowed schema.\n */\nclass McpCatalogJson {\n parse(text: string): readonly McpToolDefinition[] {\n // webpieces-disable no-any-unknown -- this IS the untyped-bytes boundary; every step below narrows it\n const parsed: unknown = JSON.parse(text);\n if (!Array.isArray(parsed)) {\n throw new McpToolCatalogError(\n 'The MCP tool catalog must be a JSON array of tool definitions.',\n REGENERATE,\n );\n }\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n return parsed.map((entry: unknown) => this.toolFrom(entry));\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private toolFrom(entry: unknown): McpToolDefinition {\n const record = this.record(entry, 'a tool definition');\n const hints = this.record(record['hints'], 'a tool definition hints block');\n return new McpToolDefinition(\n this.text(record['name'], 'name'),\n this.title(record['title'], record['name']),\n this.text(record['methodName'], 'methodName'),\n this.text(record['description'], 'description'),\n new WpMcpToolHints(\n hints['readOnlyHint'] === true,\n hints['destructiveHint'] === true,\n hints['idempotentHint'] === true,\n hints['openWorldHint'] === true,\n ),\n this.schemaFrom(record['inputSchema']),\n this.schemaFrom(record['outputSchema']),\n );\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private schemaFrom(value: unknown): ApiJsonSchema {\n const record = this.record(value, 'a JSON schema');\n const schema = new ApiJsonSchema(\n record['type'] as ApiJsonSchemaType | readonly ApiJsonSchemaType[],\n );\n if (typeof record['description'] === 'string') schema.description = record['description'];\n if (typeof record['minimum'] === 'number') schema.minimum = record['minimum'];\n if (typeof record['maximum'] === 'number') schema.maximum = record['maximum'];\n if (Array.isArray(record['required'])) schema.required = record['required'] as string[];\n if (Array.isArray(record['enum'])) schema.enum = record['enum'] as string[];\n if (typeof record['x-mcp-header'] === 'string') {\n schema['x-mcp-header'] = record['x-mcp-header'];\n }\n if (record['items'] !== undefined) schema.items = this.schemaFrom(record['items']);\n const extra = record['additionalProperties'];\n if (typeof extra === 'boolean') schema.additionalProperties = extra;\n else if (extra !== undefined) schema.additionalProperties = this.schemaFrom(extra);\n const properties = record['properties'];\n if (properties !== undefined) {\n const built: Record<string, ApiJsonSchema> = {};\n for (const [key, child] of Object.entries(\n this.record(properties, 'a schema properties block'),\n )) {\n built[key] = this.schemaFrom(child);\n }\n schema.properties = built;\n }\n const oneOf = record['oneOf'];\n if (Array.isArray(oneOf)) {\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n schema.oneOf = oneOf.map((branch: unknown) => this.schemaFrom(branch));\n schema.discriminator = this.discriminatorFrom(record['discriminator']);\n }\n return schema;\n }\n\n /**\n * The `discriminator` block, or undefined — a union TypeScript cannot narrow is published WITHOUT\n * one, so an absent block is a legal document and not a missing field.\n */\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private discriminatorFrom(value: unknown): ApiJsonSchemaDiscriminator | undefined {\n if (value === undefined) return undefined;\n const record = this.record(value, 'a schema discriminator block');\n const mapping: Record<string, string> = {};\n for (const [key, branch] of Object.entries(\n this.record(record['mapping'], 'a discriminator mapping block'),\n )) {\n mapping[key] = this.text(branch, `discriminator mapping '${key}'`);\n }\n return new ApiJsonSchemaDiscriminator(\n this.text(record['propertyName'], 'discriminator propertyName'),\n mapping,\n );\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private record(value: unknown, what: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new McpToolCatalogError(`The MCP tool catalog is missing ${what}.`, REGENERATE);\n }\n // webpieces-disable no-any-unknown -- the narrowed result of the check above\n return value as Record<string, unknown>;\n }\n\n /**\n * The REQUIRED, non-blank `title` (#1180). A catalog generated before titles existed has none, and\n * is refused here so a stale artifact fails the boot loudly instead of publishing untitled tools.\n */\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private title(value: unknown, name: unknown): string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new McpToolCatalogError(\n `The MCP tool catalog has no 'title' on tool '${String(name)}'; every tool needs a ` +\n \"human-readable title from @WpMcpTool('<name>', '<title>'). The catalog predates \" +\n 'required titles (#1180).',\n REGENERATE,\n );\n }\n return value;\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private text(value: unknown, field: string): string {\n if (typeof value !== 'string') {\n throw new McpToolCatalogError(\n `The MCP tool catalog has no '${field}' on a tool definition.`,\n REGENERATE,\n );\n }\n return value;\n }\n}\n"]}
1
+ {"version":3,"file":"McpToolCatalogFile.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/mcp/McpToolCatalogFile.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiJsonSchema, ApiJsonSchemaDiscriminator, ApiJsonSchemaType } from './DtoSchema';\nimport { Mcp } from './Mcp';\nimport { WpMcpToolHints } from './McpMetadata';\n\n/**\n * ONE generated MCP tool definition, including server-only profile membership.\n *\n * It is BUILT from the source by `@webpieces/api-doc-model`'s `McpSchemaRenderer` at build time, and\n * READ here at boot — so the tool an agent is shown and the tool the server accepts are the same\n * bytes by construction, not by two declarations agreeing.\n *\n * It lives in `core-util` rather than in the extractor package because both ends need it and only\n * one end may depend on the TypeScript compiler API. `ApiJsonSchema` and {@link WpMcpToolHints},\n * which it is made of, are already here for the same reason.\n */\nexport class McpToolDefinition {\n constructor(\n /** The stable protocol name from `@WpMcpTool('<name>', '<title>')`. */\n readonly name: string,\n /**\n * The human-readable display name from `@WpMcpTool('<name>', '<title>')`. REQUIRED (#1180):\n * `tools/list` publishes it as both `Tool.title` and `annotations.title`, and a catalog entry\n * without one is refused on load rather than silently publishing an untitled tool.\n */\n readonly title: string,\n /** The contract method it was rendered from, so a mismatch report can name the source. */\n readonly methodName: string,\n /**\n * The tool documentation: the method's `@mcp` tag when it has one, its JSDoc body otherwise.\n * Documentation has exactly ONE source — the doc comment above the declaration — for the\n * partner reading OpenAPI and the agent reading `tools/list` alike.\n */\n readonly description: string,\n /**\n * All four hints. Three are COMPUTED from `@Endpoint`'s `operation` by\n * `mcpHintsForOperation`, which is the one place that mapping lives; `openWorldHint` comes\n * from `@Endpoint`'s `openWorld` option.\n */\n readonly hints: WpMcpToolHints,\n readonly inputSchema: ApiJsonSchema,\n readonly outputSchema: ApiJsonSchema,\n readonly profiles: readonly string[],\n ) {\n this.profiles = Mcp.profiles(profiles, 'MCP catalog tool');\n }\n}\n\n/** Thrown when a catalog is not one this release can read or write. */\nexport class McpToolCatalogError extends Error {\n constructor(\n message: string,\n /** What to do instead, in one sentence. */\n readonly cure: string,\n ) {\n super(`${message} ${cure}`);\n this.name = 'McpToolCatalogError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** The one cure every catalog failure prescribes: rebuild the artifact from the contracts. */\nconst REGENERATE =\n 'Rebuild the api library that declares the contract (its `openapi-generate` target runs ' +\n '`wp-openapi`, which writes one `mcp-<ContractClass>-tools.json` per MCP contract).';\n\nconst FILE_PREFIX = 'mcp-';\nconst FILE_SUFFIX = '-tools.json';\n\n/** A class name, which is what the file name carries. Anything else is not one of these files. */\nconst CONTRACT_NAME = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\n/**\n * ONE contract's MCP tools, keyed by protocol name — the artifact `wp-openapi` writes as\n * `mcp-<ContractClass>-tools.json`, one file per contract that declares `MCP` and has at least one\n * `@WpMcpTool`, beside the library's OpenAPI documents.\n *\n * ## Why one file per CONTRACT and not one per library\n *\n * One api library holds many contracts (it is how a public partner API is grouped), and a server binds\n * contracts, not libraries — `McpApiBinding.local(LangCourseAuthorApi, ...)`. With one file per\n * contract the server can check every binding against exactly the file generated from THAT contract,\n * and refuse a file it was handed for a contract it does not bind. A single per-library file could only\n * say \"some tool is missing\" (#1021).\n *\n * This is the browser-safe CODEC — the bytes and the file name. Reading the files from an installed\n * package is `McpToolCatalog.fromPackages` in `@webpieces/mcp-server`, because only a node process\n * has a filesystem to read them from.\n */\nexport class McpToolCatalogFile {\n private readonly byName: ReadonlyMap<string, McpToolDefinition>;\n\n constructor(\n /** The contract CLASS name — `binding.api.name` at runtime, the class declaration at build time. */\n readonly contractName: string,\n readonly tools: readonly McpToolDefinition[],\n ) {\n if (!CONTRACT_NAME.test(contractName)) {\n throw new McpToolCatalogError(\n `'${contractName}' is not a contract class name, so it cannot name an MCP tool catalog.`,\n REGENERATE,\n );\n }\n const byName = new Map<string, McpToolDefinition>();\n for (const tool of tools) {\n if (byName.has(tool.name)) {\n throw new McpToolCatalogError(\n `Duplicate MCP tool name '${tool.name}' in the generated catalog of ${contractName}.`,\n 'Tool names are the protocol identity and must be globally unique — rename one ' +\n \"of the two @WpMcpTool('<name>', '<title>') declarations.\",\n );\n }\n byName.set(tool.name, tool);\n }\n this.byName = byName;\n }\n\n /** `mcp-<ContractClass>-tools.json`. */\n get fileName(): string {\n return McpToolCatalogFile.fileNameFor(this.contractName);\n }\n\n find(name: string): McpToolDefinition | undefined {\n return this.byName.get(name);\n }\n\n /** The names this catalog carries, sorted, so a failure can print what WAS published. */\n names(): readonly string[] {\n return [...this.byName.keys()].sort();\n }\n\n /** The bytes `wp-openapi` writes. Sorted by name so the artifact is diffable. */\n toJsonText(): string {\n const tools = [...this.tools].sort((left: McpToolDefinition, right: McpToolDefinition) =>\n left.name.localeCompare(right.name),\n );\n return `${JSON.stringify(tools, undefined, 2)}\\n`;\n }\n\n /** The file name the catalog of `contractName` is written to and read from. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static fileNameFor(contractName: string): string {\n return `${FILE_PREFIX}${contractName}${FILE_SUFFIX}`;\n }\n\n /** The contract a file name is the catalog of, or `undefined` when it is not one of these files. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static contractNameOf(fileName: string): string | undefined {\n if (!fileName.startsWith(FILE_PREFIX) || !fileName.endsWith(FILE_SUFFIX)) return undefined;\n const name = fileName.slice(FILE_PREFIX.length, fileName.length - FILE_SUFFIX.length);\n return CONTRACT_NAME.test(name) ? name : undefined;\n }\n\n /**\n * Reads one `mcp-<ContractClass>-tools.json`. The contract is the one the FILE NAME names. Every\n * nested value is rebuilt as a real class instance, because this is the one place untyped bytes\n * become the schemas a live protocol surface publishes.\n *\n * Malformed JSON is not caught here: it throws `SyntaxError` to the caller's own top-level\n * handler, which is where every other read-the-world failure in webpieces is reported.\n */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromJsonText(fileName: string, text: string): McpToolCatalogFile {\n const contractName = McpToolCatalogFile.contractNameOf(fileName);\n if (contractName === undefined) {\n throw new McpToolCatalogError(\n `'${fileName}' is not an MCP tool catalog file name; they are named ` +\n `${FILE_PREFIX}<ContractClass>${FILE_SUFFIX}.`,\n REGENERATE,\n );\n }\n return new McpToolCatalogFile(contractName, new McpCatalogJson().parse(text));\n }\n}\n\n/**\n * The PARSE BOUNDARY: untyped bytes in, real class instances out.\n *\n * A class of its own rather than statics on {@link McpToolCatalogFile} so every step is an ordinary\n * instance method — and because it is the one place in this file where `unknown` is the correct type\n * rather than a missing one. Nothing else in webpieces should ever hold a half-narrowed schema.\n */\nclass McpCatalogJson {\n parse(text: string): readonly McpToolDefinition[] {\n // webpieces-disable no-any-unknown -- this IS the untyped-bytes boundary; every step below narrows it\n const parsed: unknown = JSON.parse(text);\n if (!Array.isArray(parsed)) {\n throw new McpToolCatalogError(\n 'The MCP tool catalog must be a JSON array of tool definitions.',\n REGENERATE,\n );\n }\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n return parsed.map((entry: unknown) => this.toolFrom(entry));\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private toolFrom(entry: unknown): McpToolDefinition {\n const record = this.record(entry, 'a tool definition');\n const hints = this.record(record['hints'], 'a tool definition hints block');\n return new McpToolDefinition(\n this.text(record['name'], 'name'),\n this.title(record['title'], record['name']),\n this.text(record['methodName'], 'methodName'),\n this.text(record['description'], 'description'),\n new WpMcpToolHints(\n hints['readOnlyHint'] === true,\n hints['destructiveHint'] === true,\n hints['idempotentHint'] === true,\n hints['openWorldHint'] === true,\n ),\n this.schemaFrom(record['inputSchema']),\n this.schemaFrom(record['outputSchema']),\n this.profiles(record['profiles']),\n );\n }\n\n // webpieces-disable no-any-unknown -- JSON catalog parse boundary\n private profiles(value: unknown): readonly string[] {\n if (!Array.isArray(value) || !value.every((entry: unknown) => typeof entry === 'string')) {\n throw new McpToolCatalogError(\n 'The MCP tool catalog requires profiles (#1187); stale artifacts are refused.',\n REGENERATE,\n );\n }\n return Mcp.profiles(value, 'MCP catalog profiles',\n (message: string) => new McpToolCatalogError(message, REGENERATE));\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private schemaFrom(value: unknown): ApiJsonSchema {\n const record = this.record(value, 'a JSON schema');\n const schema = new ApiJsonSchema(\n record['type'] as ApiJsonSchemaType | readonly ApiJsonSchemaType[],\n );\n if (typeof record['description'] === 'string') schema.description = record['description'];\n if (typeof record['minimum'] === 'number') schema.minimum = record['minimum'];\n if (typeof record['maximum'] === 'number') schema.maximum = record['maximum'];\n if (Array.isArray(record['required'])) schema.required = record['required'] as string[];\n if (Array.isArray(record['enum'])) schema.enum = record['enum'] as string[];\n if (typeof record['x-mcp-header'] === 'string') {\n schema['x-mcp-header'] = record['x-mcp-header'];\n }\n if (record['items'] !== undefined) schema.items = this.schemaFrom(record['items']);\n const extra = record['additionalProperties'];\n if (typeof extra === 'boolean') schema.additionalProperties = extra;\n else if (extra !== undefined) schema.additionalProperties = this.schemaFrom(extra);\n const properties = record['properties'];\n if (properties !== undefined) {\n const built: Record<string, ApiJsonSchema> = {};\n for (const [key, child] of Object.entries(\n this.record(properties, 'a schema properties block'),\n )) {\n built[key] = this.schemaFrom(child);\n }\n schema.properties = built;\n }\n const oneOf = record['oneOf'];\n if (Array.isArray(oneOf)) {\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n schema.oneOf = oneOf.map((branch: unknown) => this.schemaFrom(branch));\n schema.discriminator = this.discriminatorFrom(record['discriminator']);\n }\n return schema;\n }\n\n /**\n * The `discriminator` block, or undefined — a union TypeScript cannot narrow is published WITHOUT\n * one, so an absent block is a legal document and not a missing field.\n */\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private discriminatorFrom(value: unknown): ApiJsonSchemaDiscriminator | undefined {\n if (value === undefined) return undefined;\n const record = this.record(value, 'a schema discriminator block');\n const mapping: Record<string, string> = {};\n for (const [key, branch] of Object.entries(\n this.record(record['mapping'], 'a discriminator mapping block'),\n )) {\n mapping[key] = this.text(branch, `discriminator mapping '${key}'`);\n }\n return new ApiJsonSchemaDiscriminator(\n this.text(record['propertyName'], 'discriminator propertyName'),\n mapping,\n );\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private record(value: unknown, what: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new McpToolCatalogError(`The MCP tool catalog is missing ${what}.`, REGENERATE);\n }\n // webpieces-disable no-any-unknown -- the narrowed result of the check above\n return value as Record<string, unknown>;\n }\n\n /**\n * The REQUIRED, non-blank `title` (#1180). A catalog generated before titles existed has none, and\n * is refused here so a stale artifact fails the boot loudly instead of publishing untitled tools.\n */\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private title(value: unknown, name: unknown): string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new McpToolCatalogError(\n `The MCP tool catalog has no 'title' on tool '${String(name)}'; every tool needs a ` +\n \"human-readable title from @WpMcpTool('<name>', '<title>'). The catalog predates \" +\n 'required titles (#1180).',\n REGENERATE,\n );\n }\n return value;\n }\n\n // webpieces-disable no-any-unknown -- parsing JSON is exactly where unknown belongs\n private text(value: unknown, field: string): string {\n if (typeof value !== 'string') {\n throw new McpToolCatalogError(\n `The MCP tool catalog has no '${field}' on a tool definition.`,\n REGENERATE,\n );\n }\n return value;\n }\n}\n"]}