@webpieces/mcp-server 0.4.765 → 0.4.766
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.766",
|
|
4
4
|
"description": "Secure MCP tool generation from annotated Webpieces API contracts",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
26
|
-
"@webpieces/core-context": "0.4.
|
|
27
|
-
"@webpieces/core-util": "0.4.
|
|
28
|
-
"@webpieces/http-routing": "0.4.
|
|
26
|
+
"@webpieces/core-context": "0.4.766",
|
|
27
|
+
"@webpieces/core-util": "0.4.766",
|
|
28
|
+
"@webpieces/http-routing": "0.4.766",
|
|
29
29
|
"reflect-metadata": "0.2.2",
|
|
30
30
|
"tslib": "2.8.1"
|
|
31
31
|
}
|
|
32
|
-
}
|
|
32
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpApiDispatcher.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"McpApiDispatcher.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpApiDispatcher.ts"],"names":[],"mappings":";;;AAAA,oDAQ8B;AAC9B,0DAA6F;AAI7F,MAAa,kBAAkB;IAEC;IAAiC;IADpD,OAAO,GAAG,IAAI,CAAC;IACxB,YAA4B,KAAe,EAAkB,SAAiB;QAAlD,UAAK,GAAL,KAAK,CAAU;QAAkB,cAAS,GAAT,SAAS,CAAQ;IAAG,CAAC;CACrF;AAHD,gDAGC;AAED,MAAa,kBAAkB;IAEC;IAAwC;IAD3D,OAAO,GAAG,KAAK,CAAC;IACzB,YAA4B,KAAsB,EAAkB,SAAiB;QAAzD,UAAK,GAAL,KAAK,CAAiB;QAAkB,cAAS,GAAT,SAAS,CAAQ;IAAG,CAAC;CAC5F;AAHD,gDAGC;AAID,0FAA0F;AAC1F,MAAa,gBAAgB;IAGI;IAFZ,aAAa,GAAG,IAAI,4BAAgB,EAAE,CAAC;IAExD,YAA6B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAEvD,KAAK,CAAC,IAAI,CACN,IAAuB,EACvB,UAAoB,EACpB,mBAA2B;QAE3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,UAAU,mBAAmB,EAAE,CAAC,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,0BAAW,CAAC,MAAM,EAAE,oBAAoB,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,CAAC;QAClF,OAAO,6BAAc,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YACjC,IAAI,oCAAqB,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACrD,MAAM,SAAS,GACX,6BAAc,CAAC,YAAY,CAAC,gCAAoB,CAAC,UAAU,CAAC,IAAI,oBAAoB,CAAC;YACzF,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;YAChF,IAAI,YAAY,EAAE,CAAC;gBACf,OAAO,IAAI,kBAAkB,CACzB,yBAAa,CAAC,MAAM,CAChB,IAAI,8BAAkB,CAClB,oDAAoD,EACpD,SAAS,EACT,YAAY,CAAC,OAAO,CACvB,CACJ,EACD,SAAS,CACZ,CAAC;YACN,CAAC;YACD,8GAA8G;YAC9G,IAAI,CAAC;gBACD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,eAAe,CAAiB,IAAI,CAAC,QAAiB,CAAC,CAAC;gBACvF,MAAM,KAAK,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAa,CAAC;gBACtE,OAAO,IAAI,kBAAkB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACpD,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACpB,MAAM,KAAK,GAAG,IAAA,mBAAO,EAAC,GAAG,CAAC,CAAC;gBAC3B,OAAO,IAAI,kBAAkB,CAAC,yBAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;YAC1E,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;CACJ;AAzCD,4CAyCC","sourcesContent":["import {\n ApiBadRequestError,\n ApiErrorCodec,\n ApiErrorPayload,\n DtoSchemaBuilder,\n DtoValue,\n toError,\n WebpiecesCoreHeaders,\n} from '@webpieces/core-util';\nimport { HttpRequest, RequestContext, RequestContextHeaders } from '@webpieces/core-context';\nimport { ApiFactory, ApiClientProxy } from '@webpieces/http-routing';\nimport { RegisteredMcpTool } from './McpToolRegistry';\n\nexport class McpDispatchSuccess {\n readonly success = true;\n constructor(public readonly value: DtoValue, public readonly requestId: string) {}\n}\n\nexport class McpDispatchFailure {\n readonly success = false;\n constructor(public readonly error: ApiErrorPayload, public readonly requestId: string) {}\n}\n\nexport type McpDispatchResult = McpDispatchSuccess | McpDispatchFailure;\n\n/** Executes one tool through the same ApiFactory proxy/filter/controller path as HTTP. */\nexport class McpApiDispatcher {\n private readonly schemaBuilder = new DtoSchemaBuilder();\n\n constructor(private readonly apiFactory: ApiFactory) {}\n\n async call(\n tool: RegisteredMcpTool,\n requestDto: DtoValue,\n endpointBearerToken: string,\n ): Promise<McpDispatchResult> {\n const headers = new Map<string, string[]>();\n headers.set('authorization', [`Bearer ${endpointBearerToken}`]);\n const request = new HttpRequest('POST', `/__webpieces/mcp/${tool.name}`, headers);\n return RequestContext.run(async () => {\n new RequestContextHeaders().fillFromRequest(request);\n const requestId =\n RequestContext.getUntrusted(WebpiecesCoreHeaders.REQUEST_ID) ?? 'missing-request-id';\n const inputFailure = this.schemaBuilder.validate(tool.requestClass, requestDto);\n if (inputFailure) {\n return new McpDispatchFailure(\n ApiErrorCodec.encode(\n new ApiBadRequestError(\n 'MCP request DTO did not match its declared schema.',\n undefined,\n inputFailure.message,\n ),\n ),\n requestId,\n );\n }\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary sanitizes endpoint throws\n try {\n const client = this.apiFactory.createApiClient<ApiClientProxy>(tool.apiClass as never);\n const value = (await client[tool.methodName](requestDto)) as DtoValue;\n return new McpDispatchSuccess(value, requestId);\n } catch (err: unknown) {\n const error = toError(err);\n return new McpDispatchFailure(ApiErrorCodec.encode(error), requestId);\n }\n });\n }\n}\n"]}
|
package/src/McpAuth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpAuth.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"McpAuth.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpAuth.ts"],"names":[],"mappings":";;;AAAA,yGAAyG;AACzG,MAAa,qBAAqB;IAGV;IACA;IAEA;IACA;IACA;IAEA;IATpB;IACI,2FAA2F;IAC3E,mBAA2B,EAC3B,MAAc;IAC9B,gFAAgF;IAChE,QAAgB,EAChB,qBAA6B,EAC7B,MAAyB;IACzC,oFAAoF;IACpE,eAAkC,EAAE;QAPpC,wBAAmB,GAAnB,mBAAmB,CAAQ;QAC3B,WAAM,GAAN,MAAM,CAAQ;QAEd,aAAQ,GAAR,QAAQ,CAAQ;QAChB,0BAAqB,GAArB,qBAAqB,CAAQ;QAC7B,WAAM,GAAN,MAAM,CAAmB;QAEzB,iBAAY,GAAZ,YAAY,CAAwB;IACrD,CAAC;CACP;AAZD,sDAYC;AAED,gGAAgG;AAChG,MAAsB,sBAAsB;CAK3C;AALD,wDAKC;AAED,qEAAqE;AACrE,MAAa,4BAA4B;IAC5B,QAAQ,CAAS;IACjB,qBAAqB,CAAoB;IACzC,wBAAwB,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,gBAAgB,CAAqB;IAE9C,YACI,QAAgB,EAChB,oBAAuC,EACvC,eAAmC;QAEnC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;QAClD,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAC;IAC5C,CAAC;CACJ;AAfD,oEAeC;AAED,wGAAwG;AACxG,MAAa,iBAAiB;IAEN;IACA;IACA;IACA;IACA;IACA;IANpB,YACoB,IAAY,EACZ,OAAe,EACf,QAAgB,EAChB,aAAqC,EACrC,oBAAuC,EACvC,cAAiC;QALjC,SAAI,GAAJ,IAAI,CAAQ;QACZ,YAAO,GAAP,OAAO,CAAQ;QACf,aAAQ,GAAR,QAAQ,CAAQ;QAChB,kBAAa,GAAb,aAAa,CAAwB;QACrC,yBAAoB,GAApB,oBAAoB,CAAmB;QACvC,mBAAc,GAAd,cAAc,CAAmB;QAEjD,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC1E,CAAC;IACL,CAAC;IAED,yBAAyB;QACrB,OAAO,IAAI,4BAA4B,CACnC,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,oBAAoB,EACzB,IAAI,CAAC,cAAc,CACtB,CAAC;IACN,CAAC;CACJ;AArBD,8CAqBC","sourcesContent":["/** Credential accepted at the MCP resource boundary and the local endpoint credential it resolves to. */\nexport class VerifiedMcpCredential {\n constructor(\n /** Used only on the in-process endpoint invocation; never forwarded to another service. */\n public readonly endpointBearerToken: string,\n public readonly issuer: string,\n /** The RFC 8707 resource/audience the verifier proved from the access token. */\n public readonly resource: string,\n public readonly expiresAtEpochSeconds: number,\n public readonly scopes: readonly string[],\n /** Advisory tools/list filtering only. Endpoint authorization always runs again. */\n public readonly listingRoles: readonly string[] = [],\n ) {}\n}\n\n/** Application-owned verification/token-exchange seam for a resource-bound MCP access token. */\nexport abstract class McpAccessTokenVerifier {\n abstract verify(\n accessToken: string,\n expectedResource: string,\n ): Promise<VerifiedMcpCredential>;\n}\n\n/** RFC 9728-style metadata exposed by the MCP protected resource. */\nexport class McpProtectedResourceMetadata {\n readonly resource: string;\n readonly authorization_servers: readonly string[];\n readonly bearer_methods_supported = ['header'];\n readonly scopes_supported?: readonly string[];\n\n constructor(\n resource: string,\n authorizationServers: readonly string[],\n scopesSupported?: readonly string[],\n ) {\n this.resource = resource;\n this.authorization_servers = authorizationServers;\n this.scopes_supported = scopesSupported;\n }\n}\n\n/** Node MCP server configuration. OAuth token issuance stays with the application/identity provider. */\nexport class WpMcpServerConfig {\n constructor(\n public readonly name: string,\n public readonly version: string,\n public readonly resource: string,\n public readonly tokenVerifier: McpAccessTokenVerifier,\n public readonly authorizationServers: readonly string[],\n public readonly requiredScopes: readonly string[],\n ) {\n if (name.trim() === '' || version.trim() === '' || resource.trim() === '') {\n throw new Error('MCP name, version, and resource must be non-empty.');\n }\n }\n\n protectedResourceMetadata(): McpProtectedResourceMetadata {\n return new McpProtectedResourceMetadata(\n this.resource,\n this.authorizationServers,\n this.requiredScopes,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpToolRegistry.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"McpToolRegistry.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/McpToolRegistry.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ApiJsonSchema,\n AuthMeta,\n DtoClass,\n DtoSchemaBuilder,\n getAuthMeta,\n getEndpointKind,\n getEndpoints,\n getWpMcpTools,\n rolesRequired,\n WpMcpToolMetadata,\n} from '@webpieces/core-util';\nimport { ClassType } from '@webpieces/http-routing';\n\n/** Fully resolved contract metadata for one MCP tool. */\nexport class RegisteredMcpTool {\n constructor(\n public readonly apiClass: ClassType,\n public readonly methodName: string,\n public readonly name: string,\n public readonly description: string,\n public readonly annotations: WpMcpToolMetadata['hints'],\n public readonly authMeta: AuthMeta,\n public readonly requestClass: DtoClass,\n public readonly responseClass: DtoClass,\n public readonly inputSchema: ApiJsonSchema,\n public readonly outputSchema: ApiJsonSchema,\n ) {}\n\n /** Listing is advisory; the ordinary endpoint AuthFilter is the only authorization boundary. */\n isVisibleTo(listingRoles: readonly string[]): boolean {\n if (this.authMeta.mode.kind !== 'jwt') return true;\n const required = rolesRequired(this.authMeta.mode.requirement);\n return required.length === 0 || required.some((role: string) => listingRoles.includes(role));\n }\n}\n\n/** Fail-fast registry built entirely from API/decorator metadata. */\nexport class McpToolRegistry {\n readonly tools: readonly RegisteredMcpTool[];\n readonly schemaBuilder = new DtoSchemaBuilder();\n\n constructor(apiClasses: readonly ClassType[]) {\n const registered: RegisteredMcpTool[] = [];\n const names = new Set<string>();\n for (const apiClass of apiClasses) {\n for (const metadata of getWpMcpTools(apiClass)) {\n if (names.has(metadata.name)) {\n throw new Error(`Duplicate @WpMcpTool name '${metadata.name}'. Tool names must be globally unique.`);\n }\n names.add(metadata.name);\n registered.push(this.resolve(apiClass, metadata));\n }\n }\n this.tools = registered;\n }\n\n find(name: string): RegisteredMcpTool | undefined {\n return this.tools.find((tool: RegisteredMcpTool) => tool.name === name);\n }\n\n private resolve(apiClass: ClassType, metadata: WpMcpToolMetadata): RegisteredMcpTool {\n const endpoints = getEndpoints(apiClass) ?? {};\n if (!endpoints[metadata.methodName]) {\n throw new Error(`@WpMcpTool ${apiClass.name}.${metadata.methodName} must also be an @Endpoint.`);\n }\n if (getEndpointKind(apiClass, metadata.methodName) !== 'rpc') {\n throw new Error(`@WpMcpTool ${apiClass.name}.${metadata.methodName} must be an RPC endpoint.`);\n }\n const authMeta = getAuthMeta(apiClass, metadata.methodName);\n if (!authMeta || (authMeta.mode.kind !== 'jwt' && authMeta.mode.kind !== 'public')) {\n throw new Error(\n `@WpMcpTool ${apiClass.name}.${metadata.methodName} must use @WpAuthJwt or @WpAuthPublic.`,\n );\n }\n if (authMeta.mode.kind === 'public' && !metadata.hints.readOnlyHint) {\n throw new Error(`Public MCP tool ${metadata.name} must be read-only.`);\n }\n const requestClass = this.schemaBuilder.requestClassOf(apiClass, metadata.methodName);\n const responseClass = this.schemaBuilder.responseClassOf(apiClass, metadata.methodName);\n return new RegisteredMcpTool(\n apiClass,\n metadata.methodName,\n metadata.name,\n metadata.description,\n metadata.hints,\n authMeta,\n requestClass,\n responseClass,\n this.schemaBuilder.build(requestClass),\n this.schemaBuilder.build(responseClass),\n );\n }\n}\n"]}
|
package/src/WpMcpServer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WpMcpServer.js","sourceRoot":"","sources":["../../../../../../packages/http/mcp-server/src/WpMcpServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequest,\n CallToolRequestSchema,\n CallToolResult,\n ErrorCode,\n ListToolsRequestSchema,\n McpError,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n ApiErrorPayload,\n DtoValue,\n LogManager,\n toError,\n} from '@webpieces/core-util';\nimport { ApiFactory, ClassType } from '@webpieces/http-routing';\nimport { VerifiedMcpCredential, WpMcpServerConfig } from './McpAuth';\nimport { McpApiDispatcher } from './McpApiDispatcher';\nimport { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\n\nconst log = LogManager.getLogger('WpMcpServer');\n\n/** The only error shape rendered into model-visible MCP content. */\nexport class ModelVisibleToolError {\n constructor(\n public readonly kind: string,\n public readonly message: string,\n public readonly requestId?: string,\n public readonly field?: string,\n public readonly callerMessage?: string,\n public readonly errorCode?: string,\n public readonly retryAfterSeconds?: number,\n ) {}\n}\n\n/**\n * Node-only MCP adapter. Build one Server per authenticated transport/session; every tool call still\n * re-enters the endpoint's ordinary AuthFilter, so tools/list visibility never grants access.\n */\nexport class WpMcpServer {\n private readonly registry: McpToolRegistry;\n private readonly dispatcher: McpApiDispatcher;\n\n constructor(\n private readonly config: WpMcpServerConfig,\n apiFactory: ApiFactory,\n apiClasses: readonly ClassType[],\n ) {\n this.registry = new McpToolRegistry(apiClasses);\n this.dispatcher = new McpApiDispatcher(apiFactory);\n }\n\n async build(accessToken: string): Promise<Server> {\n const credential = await this.config.tokenVerifier.verify(\n accessToken,\n this.config.resource,\n );\n this.validateCredential(credential);\n return this.buildForCredential(credential);\n }\n\n protectedResourceMetadata(): ReturnType<WpMcpServerConfig['protectedResourceMetadata']> {\n return this.config.protectedResourceMetadata();\n }\n\n private buildForCredential(credential: VerifiedMcpCredential): Server {\n const server = new Server(\n // webpieces-disable no-anonymous-object-literals -- external MCP SDK request structure\n { name: this.config.name, version: this.config.version },\n // webpieces-disable no-anonymous-object-literals -- external MCP SDK capability structure\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: this.registry.tools\n .filter((tool: RegisteredMcpTool) => tool.isVisibleTo(credential.listingRoles))\n .map((tool: RegisteredMcpTool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n annotations: tool.annotations,\n })),\n }));\n server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) => {\n const tool = this.registry.find(request.params.name);\n if (!tool) {\n throw new McpError(ErrorCode.InvalidParams, `Unknown tool: ${request.params.name}`);\n }\n return this.call(tool, request.params.arguments ?? {}, credential);\n });\n return server;\n }\n\n private validateCredential(credential: VerifiedMcpCredential): void {\n if (credential.resource !== this.config.resource) {\n throw new Error('MCP access token was not issued for this protected resource.');\n }\n if (!this.config.authorizationServers.includes(credential.issuer)) {\n throw new Error('MCP access token issuer is not trusted by this protected resource.');\n }\n if (credential.expiresAtEpochSeconds <= Date.now() / 1000) {\n throw new Error('MCP access token has expired.');\n }\n for (const scope of this.config.requiredScopes) {\n if (!credential.scopes.includes(scope)) {\n throw new Error(`MCP access token is missing required scope '${scope}'.`);\n }\n }\n if (credential.endpointBearerToken.trim() === '') {\n throw new Error('MCP verifier returned an empty endpoint bearer credential.');\n }\n }\n\n private async call(\n tool: RegisteredMcpTool,\n args: DtoValue,\n credential: VerifiedMcpCredential,\n ): Promise<CallToolResult> {\n const result = await this.dispatcher.call(tool, args ?? {}, credential.endpointBearerToken);\n if (!result.success) return this.apiError(result.error, result.requestId);\n\n const outputFailure = this.registry.schemaBuilder.validate(tool.responseClass, result.value);\n if (outputFailure) {\n log.error(\n `MCP output schema violation for ${tool.apiClass.name}.${tool.methodName}: ${outputFailure.message}`,\n );\n return this.errorResult(\n new ModelVisibleToolError('implementation', 'Internal Error', result.requestId),\n );\n }\n let structured: Record<string, DtoValue>;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary sanitizes serialization failures\n try {\n structured = this.record(result.value);\n } catch (err: unknown) {\n const error = toError(err);\n log.error(\n `MCP response serialization failed for ${tool.apiClass.name}.${tool.methodName}`,\n error,\n );\n return this.errorResult(\n new ModelVisibleToolError('implementation', 'Internal Error', result.requestId),\n );\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(structured) }],\n structuredContent: structured,\n };\n }\n\n private apiError(payload: ApiErrorPayload, requestId: string): CallToolResult {\n return this.errorResult(\n new ModelVisibleToolError(\n payload.kind,\n payload.message,\n requestId,\n payload.field,\n payload.callerMessage,\n payload.errorCode,\n payload.retryAfterSeconds,\n ),\n );\n }\n\n private errorResult(error: ModelVisibleToolError): CallToolResult {\n const structured = this.record(error);\n return {\n content: [{ type: 'text', text: JSON.stringify(structured) }],\n structuredContent: structured,\n isError: true,\n };\n }\n\n private record(value: DtoValue): Record<string, DtoValue> {\n const json = JSON.stringify(value);\n if (json === undefined) throw new Error('MCP structured content is not JSON serializable.');\n const parsed = JSON.parse(json) as DtoValue;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n // webpieces-disable no-anonymous-object-literals -- external MCP structured-content wrapper\n return { value: parsed };\n }\n return parsed as Record<string, DtoValue>;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WpMcpServer.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/WpMcpServer.ts"],"names":[],"mappings":"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","sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequest,\n CallToolRequestSchema,\n CallToolResult,\n ErrorCode,\n ListToolsRequestSchema,\n McpError,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n ApiErrorPayload,\n DtoValue,\n LogManager,\n toError,\n} from '@webpieces/core-util';\nimport { ApiFactory, ClassType } from '@webpieces/http-routing';\nimport { VerifiedMcpCredential, WpMcpServerConfig } from './McpAuth';\nimport { McpApiDispatcher } from './McpApiDispatcher';\nimport { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\n\nconst log = LogManager.getLogger('WpMcpServer');\n\n/** The only error shape rendered into model-visible MCP content. */\nexport class ModelVisibleToolError {\n constructor(\n public readonly kind: string,\n public readonly message: string,\n public readonly requestId?: string,\n public readonly field?: string,\n public readonly callerMessage?: string,\n public readonly errorCode?: string,\n public readonly retryAfterSeconds?: number,\n ) {}\n}\n\n/**\n * Node-only MCP adapter. Build one Server per authenticated transport/session; every tool call still\n * re-enters the endpoint's ordinary AuthFilter, so tools/list visibility never grants access.\n */\nexport class WpMcpServer {\n private readonly registry: McpToolRegistry;\n private readonly dispatcher: McpApiDispatcher;\n\n constructor(\n private readonly config: WpMcpServerConfig,\n apiFactory: ApiFactory,\n apiClasses: readonly ClassType[],\n ) {\n this.registry = new McpToolRegistry(apiClasses);\n this.dispatcher = new McpApiDispatcher(apiFactory);\n }\n\n async build(accessToken: string): Promise<Server> {\n const credential = await this.config.tokenVerifier.verify(\n accessToken,\n this.config.resource,\n );\n this.validateCredential(credential);\n return this.buildForCredential(credential);\n }\n\n protectedResourceMetadata(): ReturnType<WpMcpServerConfig['protectedResourceMetadata']> {\n return this.config.protectedResourceMetadata();\n }\n\n private buildForCredential(credential: VerifiedMcpCredential): Server {\n const server = new Server(\n // webpieces-disable no-anonymous-object-literals -- external MCP SDK request structure\n { name: this.config.name, version: this.config.version },\n // webpieces-disable no-anonymous-object-literals -- external MCP SDK capability structure\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: this.registry.tools\n .filter((tool: RegisteredMcpTool) => tool.isVisibleTo(credential.listingRoles))\n .map((tool: RegisteredMcpTool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n annotations: tool.annotations,\n })),\n }));\n server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) => {\n const tool = this.registry.find(request.params.name);\n if (!tool) {\n throw new McpError(ErrorCode.InvalidParams, `Unknown tool: ${request.params.name}`);\n }\n return this.call(tool, request.params.arguments ?? {}, credential);\n });\n return server;\n }\n\n private validateCredential(credential: VerifiedMcpCredential): void {\n if (credential.resource !== this.config.resource) {\n throw new Error('MCP access token was not issued for this protected resource.');\n }\n if (!this.config.authorizationServers.includes(credential.issuer)) {\n throw new Error('MCP access token issuer is not trusted by this protected resource.');\n }\n if (credential.expiresAtEpochSeconds <= Date.now() / 1000) {\n throw new Error('MCP access token has expired.');\n }\n for (const scope of this.config.requiredScopes) {\n if (!credential.scopes.includes(scope)) {\n throw new Error(`MCP access token is missing required scope '${scope}'.`);\n }\n }\n if (credential.endpointBearerToken.trim() === '') {\n throw new Error('MCP verifier returned an empty endpoint bearer credential.');\n }\n }\n\n private async call(\n tool: RegisteredMcpTool,\n args: DtoValue,\n credential: VerifiedMcpCredential,\n ): Promise<CallToolResult> {\n const result = await this.dispatcher.call(tool, args ?? {}, credential.endpointBearerToken);\n if (!result.success) return this.apiError(result.error, result.requestId);\n\n const outputFailure = this.registry.schemaBuilder.validate(tool.responseClass, result.value);\n if (outputFailure) {\n log.error(\n `MCP output schema violation for ${tool.apiClass.name}.${tool.methodName}: ${outputFailure.message}`,\n );\n return this.errorResult(\n new ModelVisibleToolError('implementation', 'Internal Error', result.requestId),\n );\n }\n let structured: Record<string, DtoValue>;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- transport boundary sanitizes serialization failures\n try {\n structured = this.record(result.value);\n } catch (err: unknown) {\n const error = toError(err);\n log.error(\n `MCP response serialization failed for ${tool.apiClass.name}.${tool.methodName}`,\n error,\n );\n return this.errorResult(\n new ModelVisibleToolError('implementation', 'Internal Error', result.requestId),\n );\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(structured) }],\n structuredContent: structured,\n };\n }\n\n private apiError(payload: ApiErrorPayload, requestId: string): CallToolResult {\n return this.errorResult(\n new ModelVisibleToolError(\n payload.kind,\n payload.message,\n requestId,\n payload.field,\n payload.callerMessage,\n payload.errorCode,\n payload.retryAfterSeconds,\n ),\n );\n }\n\n private errorResult(error: ModelVisibleToolError): CallToolResult {\n const structured = this.record(error);\n return {\n content: [{ type: 'text', text: JSON.stringify(structured) }],\n structuredContent: structured,\n isError: true,\n };\n }\n\n private record(value: DtoValue): Record<string, DtoValue> {\n const json = JSON.stringify(value);\n if (json === undefined) throw new Error('MCP structured content is not JSON serializable.');\n const parsed = JSON.parse(json) as DtoValue;\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n // webpieces-disable no-anonymous-object-literals -- external MCP structured-content wrapper\n return { value: parsed };\n }\n return parsed as Record<string, DtoValue>;\n }\n}\n"]}
|
package/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/http/mcp-server/src/index.ts"],"names":[],"mappings":";;;AAAA,qCAKmB;AAJf,iHAAA,sBAAsB,OAAA;AACtB,uHAAA,4BAA4B,OAAA;AAC5B,gHAAA,qBAAqB,OAAA;AACrB,4GAAA,iBAAiB,OAAA;AAErB,qDAAuE;AAA9D,kHAAA,eAAe,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAC3C,uDAI4B;AAHxB,oHAAA,gBAAgB,OAAA;AAChB,sHAAA,kBAAkB,OAAA;AAClB,sHAAA,kBAAkB,OAAA;AAGtB,6CAAmE;AAA1D,oHAAA,qBAAqB,OAAA;AAAE,0GAAA,WAAW,OAAA","sourcesContent":["export {\n McpAccessTokenVerifier,\n McpProtectedResourceMetadata,\n VerifiedMcpCredential,\n WpMcpServerConfig,\n} from './McpAuth';\nexport { McpToolRegistry, RegisteredMcpTool } from './McpToolRegistry';\nexport {\n McpApiDispatcher,\n McpDispatchFailure,\n McpDispatchSuccess,\n} from './McpApiDispatcher';\nexport type { McpDispatchResult } from './McpApiDispatcher';\nexport { ModelVisibleToolError, WpMcpServer } from './WpMcpServer';\n"]}
|