@vritti/api-sdk 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcp/index.ts","../src/mcp/coverage.ts","../src/mcp/mcp.module.ts","../src/mcp/mcp.options.ts","../src/exceptions/bad-gateway.exception.ts","../src/exceptions/base-field.exception.ts","../src/exceptions/bad-request.exception.ts","../src/exceptions/conflict.exception.ts","../src/exceptions/forbidden.exception.ts","../src/exceptions/gone.exception.ts","../src/exceptions/internal-server-error.exception.ts","../src/exceptions/method-not-allowed.exception.ts","../src/exceptions/not-acceptable.exception.ts","../src/exceptions/not-found.exception.ts","../src/exceptions/not-implemented.exception.ts","../src/exceptions/payload-too-large.exception.ts","../src/exceptions/request-timeout.exception.ts","../src/exceptions/service-unavailable.exception.ts","../src/exceptions/too-many-requests.exception.ts","../src/exceptions/unauthorized.exception.ts","../src/exceptions/unprocessable-entity.exception.ts","../src/exceptions/unsupported-media-type.exception.ts","../src/exceptions/validation.exception.ts","../src/mcp/mcp-principal.ts","../src/mcp/mcp-request.handler.ts","../src/mcp/mcp-server.factory.ts","../src/mcp/tool-registry.ts","../src/mcp/tool-definition.ts","../src/mcp/tool-result.ts","../src/mcp/mcp-transport.factory.ts","../src/mcp/mcp-schema-registry.ts","../src/mcp/validate-dto.ts"],"sourcesContent":["// Model Context Protocol plumbing for a NestJS + Fastify server: one stateless Streamable HTTP endpoint whose tools\n// are discovered from @McpTools() providers and run through a shared scope, validation and error-mapping pipeline.\n\nexport { collectOperationIds } from './coverage';\nexport { McpModule } from './mcp.module';\nexport { MCP_SERVER_OPTIONS, type McpModuleOptions, type McpServerOptions } from './mcp.options';\nexport { MCP_PRINCIPAL_FACTORY, McpPrincipal, type McpPrincipalFactory, principalFromOAuth } from './mcp-principal';\nexport { McpRequestHandler } from './mcp-request.handler';\nexport { McpSchemaRegistry } from './mcp-schema-registry';\nexport { McpServerFactory } from './mcp-server.factory';\nexport { McpTransportFactory } from './mcp-transport.factory';\nexport {\n defineTool,\n MCP_TOOL_PROVIDER_KEY,\n type McpToolAnnotations,\n type McpToolProvider,\n McpTools,\n type ToolDefinition,\n} from './tool-definition';\nexport { ToolRegistry } from './tool-registry';\nexport { problemFromError, type ToolFieldError, type ToolProblem, toolError, toolOk } from './tool-result';\nexport { McpValidationError, validateDto } from './validate-dto';\n","import type { Type } from '@nestjs/common';\nimport { METHOD_METADATA, MODULE_METADATA } from '@nestjs/common/constants';\n\n// The operation ids Swagger derives for every route-decorated method of the given modules' controllers\n// (`${ControllerName}_${method}`). A server's coverage test compares this with what its tools cover and exclude.\nexport function collectOperationIds(modules: Type[]): string[] {\n const ids: string[] = [];\n for (const module of modules) {\n const controllers: Type[] = Reflect.getMetadata(MODULE_METADATA.CONTROLLERS, module) ?? [];\n for (const controller of controllers) {\n const prototype = controller.prototype as Record<string, unknown>;\n for (const method of Object.getOwnPropertyNames(prototype)) {\n if (method === 'constructor') continue;\n const handler = prototype[method];\n if (typeof handler !== 'function') continue;\n if (Reflect.getMetadata(METHOD_METADATA, handler) === undefined) continue;\n ids.push(`${controller.name}_${method}`);\n }\n }\n }\n return ids;\n}\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport { DiscoveryModule } from '@nestjs/core';\nimport { MCP_SERVER_OPTIONS, type McpModuleOptions, type McpServerOptions } from './mcp.options';\nimport { MCP_PRINCIPAL_FACTORY, principalFromOAuth } from './mcp-principal';\nimport { McpRequestHandler } from './mcp-request.handler';\nimport { McpSchemaRegistry } from './mcp-schema-registry';\nimport { McpServerFactory } from './mcp-server.factory';\nimport { McpTransportFactory } from './mcp-transport.factory';\nimport { ToolRegistry } from './tool-registry';\n\n// The MCP plumbing a server shares: transport, protocol server, request handler, schema registry and tool registry.\n// The server keeps what is its own — the controller carrying the route and its @Require(), the @McpTools() providers,\n// and whatever resource tables or workflows those tools compose.\n@Module({})\nexport class McpModule {\n static forRoot(options: McpModuleOptions): DynamicModule {\n const serverOptions: McpServerOptions = {\n name: options.name,\n version: options.version,\n instructions: options.instructions,\n };\n return {\n module: McpModule,\n imports: [DiscoveryModule],\n providers: [\n { provide: MCP_SERVER_OPTIONS, useValue: serverOptions },\n { provide: MCP_PRINCIPAL_FACTORY, useValue: options.principal ?? principalFromOAuth },\n McpTransportFactory,\n McpServerFactory,\n McpRequestHandler,\n McpSchemaRegistry,\n ToolRegistry,\n ],\n exports: [McpRequestHandler, McpSchemaRegistry, ToolRegistry],\n };\n }\n}\n","import type { McpPrincipalFactory } from './mcp-principal';\n\nexport const MCP_SERVER_OPTIONS = Symbol('MCP_SERVER_OPTIONS');\n\nexport interface McpServerOptions {\n name: string;\n version: string;\n instructions?: string;\n}\n\nexport interface McpModuleOptions extends McpServerOptions {\n // How a request becomes a principal; defaults to the OAuth bearer the auth guard resolved\n principal?: McpPrincipalFactory;\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class BadGatewayException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Bad Gateway', HttpStatus.BAD_GATEWAY);\n }\n}\n","import { HttpException, HttpStatus } from '@nestjs/common';\nimport type { FieldError } from '../types/error-response.types';\n\n// Re-export FieldError for backwards compatibility\nexport type { FieldError } from '../types/error-response.types';\n\nexport interface ProblemOptions {\n type?: string;\n label?: string;\n detail?: string;\n errors?: FieldError[];\n}\n\nexport abstract class HttpProblemException extends HttpException {\n constructor(detailOrOptions: string | ProblemOptions, httpStatus: HttpStatus) {\n const options = typeof detailOrOptions === 'string' ? { detail: detailOrOptions } : detailOrOptions;\n\n super(\n {\n type: options.type ?? 'about:blank',\n label: options.label,\n detail: options.detail,\n errors: options.errors ?? [],\n },\n httpStatus,\n );\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class BadRequestException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Bad Request', HttpStatus.BAD_REQUEST);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ConflictException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Conflict', HttpStatus.CONFLICT);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ForbiddenException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Forbidden', HttpStatus.FORBIDDEN);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class GoneException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Gone', HttpStatus.GONE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class InternalServerErrorException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Internal Server Error', HttpStatus.INTERNAL_SERVER_ERROR);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class MethodNotAllowedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Method Not Allowed', HttpStatus.METHOD_NOT_ALLOWED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotAcceptableException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Acceptable', HttpStatus.NOT_ACCEPTABLE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotFoundException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Found', HttpStatus.NOT_FOUND);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class NotImplementedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Not Implemented', HttpStatus.NOT_IMPLEMENTED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class PayloadTooLargeException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Payload Too Large', HttpStatus.PAYLOAD_TOO_LARGE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class RequestTimeoutException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Request Timeout', HttpStatus.REQUEST_TIMEOUT);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ServiceUnavailableException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Service Unavailable', HttpStatus.SERVICE_UNAVAILABLE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class TooManyRequestsException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Too Many Requests', HttpStatus.TOO_MANY_REQUESTS);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnauthorizedException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unauthorized', HttpStatus.UNAUTHORIZED);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnprocessableEntityException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unprocessable Entity', HttpStatus.UNPROCESSABLE_ENTITY);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class UnsupportedMediaTypeException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Unsupported Media Type', HttpStatus.UNSUPPORTED_MEDIA_TYPE);\n }\n}\n","import { HttpStatus } from '@nestjs/common';\nimport { HttpProblemException, type ProblemOptions } from './base-field.exception';\n\nexport class ValidationException extends HttpProblemException {\n constructor(detailOrOptions?: string | ProblemOptions) {\n super(detailOrOptions ?? 'Validation Failed', HttpStatus.UNPROCESSABLE_ENTITY);\n }\n}\n","import type { FastifyRequest } from 'fastify';\nimport { UnauthorizedException } from '../exceptions';\nimport '../types/fastify-augmentation';\n\n// Who a tool call acts as, whatever authenticated the request. Scopes are the server's own vocabulary; the registry\n// only compares them with each tool's requiredScope.\nexport class McpPrincipal {\n constructor(\n readonly userId: string,\n readonly scopes: readonly string[],\n readonly clientId?: string,\n readonly grantId?: string,\n readonly organizationId?: string,\n ) {}\n\n hasScope(scope: string): boolean {\n return this.scopes.includes(scope);\n }\n}\n\nexport type McpPrincipalFactory = (request: FastifyRequest) => McpPrincipal;\n\nexport const MCP_PRINCIPAL_FACTORY = Symbol('MCP_PRINCIPAL_FACTORY');\n\n// The default: an OAuth bearer the auth guard resolved. Fails loudly when the guard did not run — a missing principal\n// must never mean \"no restrictions\". Servers that authenticate MCP calls another way supply their own factory.\nexport function principalFromOAuth(request: FastifyRequest): McpPrincipal {\n const auth = request.auth;\n if (!auth || auth.kind !== 'oauth' || !auth.userId || !auth.grantId) {\n throw new UnauthorizedException('MCP request is not authenticated.');\n }\n return new McpPrincipal(auth.userId, auth.scopes ?? [], auth.clientId, auth.grantId, auth.organizationId);\n}\n","import { Inject, Injectable } from '@nestjs/common';\nimport type { FastifyReply, FastifyRequest } from 'fastify';\nimport { MCP_PRINCIPAL_FACTORY, type McpPrincipalFactory } from './mcp-principal';\nimport { McpServerFactory } from './mcp-server.factory';\nimport { McpTransportFactory } from './mcp-transport.factory';\n\n// Runs one JSON-RPC exchange. The reply is hijacked so the MCP transport writes the raw response itself, and the\n// already-parsed body is handed over because Fastify has consumed the request stream by the time a handler runs.\n@Injectable()\nexport class McpRequestHandler {\n constructor(\n private readonly serverFactory: McpServerFactory,\n private readonly transportFactory: McpTransportFactory,\n @Inject(MCP_PRINCIPAL_FACTORY) private readonly principalFactory: McpPrincipalFactory,\n ) {}\n\n async handle(request: FastifyRequest, reply: FastifyReply, body: unknown): Promise<void> {\n const principal = this.principalFactory(request);\n reply.hijack();\n\n const transport = this.transportFactory.create();\n const server = this.serverFactory.create(principal);\n reply.raw.on('close', () => {\n void transport.close();\n void server.close();\n });\n\n await server.connect(transport);\n await transport.handleRequest(request.raw, reply.raw, body);\n }\n\n // The JSON-RPC answer for verbs a stateless server does not serve (GET streams, DELETE session teardown)\n methodNotAllowed(reply: FastifyReply): void {\n reply\n .status(405)\n .header('Allow', 'POST')\n .send({ jsonrpc: '2.0', error: { code: -32000, message: 'Method not allowed.' }, id: null });\n }\n}\n","import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { Inject, Injectable } from '@nestjs/common';\nimport { MCP_SERVER_OPTIONS, type McpServerOptions } from './mcp.options';\nimport type { McpPrincipal } from './mcp-principal';\nimport { ToolRegistry } from './tool-registry';\n\n// Builds the protocol server for one request, binding the two tool handlers to the caller's principal\n@Injectable()\nexport class McpServerFactory {\n constructor(\n @Inject(MCP_SERVER_OPTIONS) private readonly options: McpServerOptions,\n private readonly toolRegistry: ToolRegistry,\n ) {}\n\n create(principal: McpPrincipal): Server {\n const server = new Server(\n { name: this.options.name, version: this.options.version },\n { capabilities: { tools: {} }, instructions: this.options.instructions },\n );\n server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: this.toolRegistry.listTools() }));\n server.setRequestHandler(CallToolRequestSchema, async (request) =>\n this.toolRegistry.execute(request.params.name, request.params.arguments, principal),\n );\n return server;\n }\n}\n","import type { CallToolResult, Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { Injectable, Logger, type OnApplicationBootstrap, type Type } from '@nestjs/common';\nimport { DiscoveryService, Reflector } from '@nestjs/core';\nimport { z } from 'zod';\nimport type { McpPrincipal } from './mcp-principal';\nimport { MCP_TOOL_PROVIDER_KEY, type McpToolProvider, type ToolDefinition } from './tool-definition';\nimport { problemFromError, toolError, toolOk } from './tool-result';\n\nconst TOOL_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,64}$/;\n\n// Owns every tool the server exposes: collects @McpTools() providers at bootstrap, builds the tools/list catalog once,\n// then runs each call through the same scope check, argument validation, error mapping and audit line so individual\n// tools only implement their handler.\n@Injectable()\nexport class ToolRegistry implements OnApplicationBootstrap {\n private readonly logger = new Logger(ToolRegistry.name);\n private readonly definitions = new Map<string, ToolDefinition>();\n private catalog: Tool[] = [];\n\n constructor(\n private readonly discovery: DiscoveryService,\n private readonly reflector: Reflector,\n ) {}\n\n // After every module has initialised, so providers from any module are instantiated and discoverable\n onApplicationBootstrap(): void {\n for (const provider of this.findProviders()) {\n for (const definition of provider.tools()) this.register(definition);\n }\n this.catalog = [...this.definitions.values()].map((definition) => this.toCatalogEntry(definition));\n this.logger.log(`Registered ${this.catalog.length} MCP tools`);\n }\n\n listTools(): Tool[] {\n return this.catalog;\n }\n\n // Every REST operation the tools stand in for — a coverage test compares this with the live route set\n coveredOperationIds(): string[] {\n return [...this.definitions.values()].flatMap((definition) => [...definition.covers]);\n }\n\n async execute(name: string, rawArgs: unknown, principal: McpPrincipal): Promise<CallToolResult> {\n const started = Date.now();\n const definition = this.definitions.get(name);\n if (!definition) {\n return toolError({ status: 404, label: 'Unknown Tool', detail: `No tool named \"${name}\".`, errors: [] });\n }\n\n let status = 200;\n let result: CallToolResult;\n if (!principal.hasScope(definition.requiredScope)) {\n status = 403;\n result = toolError({\n status,\n label: 'Insufficient Scope',\n detail: `Tool \"${name}\" requires the ${definition.requiredScope} scope. Reconnect the client and grant it.`,\n errors: [],\n });\n } else {\n try {\n const args = definition.inputSchema.parse(rawArgs ?? {});\n result = toolOk(await definition.handler(principal, args));\n } catch (error) {\n const problem = problemFromError(error);\n status = problem.status;\n result = toolError(problem);\n }\n }\n\n this.logger.log(\n `mcp tool=${name} user=${principal.userId} grant=${principal.grantId ?? '-'} client=${principal.clientId ?? '-'} scope=${definition.requiredScope} ok=${status < 400} status=${status} ms=${Date.now() - started}`,\n );\n return result;\n }\n\n private findProviders(): McpToolProvider[] {\n return this.discovery\n .getProviders()\n .filter((wrapper) => typeof wrapper.metatype === 'function' && wrapper.instance)\n .filter(\n (wrapper) => this.reflector.get<boolean>(MCP_TOOL_PROVIDER_KEY, wrapper.metatype as Type<unknown>) === true,\n )\n .map((wrapper) => wrapper.instance as McpToolProvider);\n }\n\n private register(definition: ToolDefinition): void {\n if (!TOOL_NAME_PATTERN.test(definition.name)) {\n throw new Error(`MCP tool name \"${definition.name}\" is invalid (letters, digits, _ and -, max 64 chars).`);\n }\n if (this.definitions.has(definition.name)) {\n throw new Error(`MCP tool \"${definition.name}\" is registered twice.`);\n }\n this.definitions.set(definition.name, definition);\n }\n\n private toCatalogEntry(definition: ToolDefinition): Tool {\n return {\n name: definition.name,\n title: definition.title,\n description: definition.description,\n inputSchema: this.toInputSchema(definition),\n annotations: {\n title: definition.title,\n readOnlyHint: definition.annotations.readOnlyHint,\n destructiveHint: definition.annotations.destructiveHint,\n idempotentHint: definition.annotations.idempotentHint,\n openWorldHint: false,\n },\n };\n }\n\n // MCP wants a bare JSON Schema object at the root; zod adds a $schema marker the catalog does not need\n private toInputSchema(definition: ToolDefinition): Tool['inputSchema'] {\n const schema = z.toJSONSchema(definition.inputSchema, { io: 'input' }) as Record<string, unknown>;\n delete schema.$schema;\n if (schema.type !== 'object') {\n throw new Error(`MCP tool \"${definition.name}\" must declare an object input schema.`);\n }\n return schema as Tool['inputSchema'];\n }\n}\n","import { SetMetadata } from '@nestjs/common';\nimport type { ZodType } from 'zod';\nimport type { McpPrincipal } from './mcp-principal';\n\nexport interface McpToolAnnotations {\n readOnlyHint: boolean;\n destructiveHint: boolean;\n idempotentHint: boolean;\n}\n\nexport interface ToolDefinition<Args = unknown> {\n name: string;\n title: string;\n description: string;\n inputSchema: ZodType<Args>;\n annotations: McpToolAnnotations;\n requiredScope: string;\n covers: readonly string[];\n handler: (principal: McpPrincipal, args: Args) => Promise<unknown>;\n}\n\nexport interface McpToolProvider {\n tools(): ToolDefinition[];\n}\n\nexport const MCP_TOOL_PROVIDER_KEY = 'mcp:tool-provider';\n\n// Marks an injectable class whose tools() the registry collects at bootstrap. Register the class as an ordinary\n// provider in any module — discovery finds it wherever it lives, so a server's tools stay in the server's own module.\nexport const McpTools = (): ClassDecorator => SetMetadata(MCP_TOOL_PROVIDER_KEY, true);\n\n// Keeps the parsed argument type flowing into the handler while the registry stores every definition in one list\nexport function defineTool<Args>(definition: ToolDefinition<Args>): ToolDefinition {\n return definition as unknown as ToolDefinition;\n}\n","import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { Logger } from '@nestjs/common';\nimport { ZodError } from 'zod';\n\nexport interface ToolFieldError {\n field?: string;\n message: string;\n}\n\nexport interface ToolProblem {\n status: number;\n label?: string;\n detail: string;\n errors: ToolFieldError[];\n}\n\ninterface HttpExceptionLike {\n getStatus(): number;\n getResponse(): unknown;\n}\n\nconst PG_UNIQUE_VIOLATION = '23505';\nconst logger = new Logger('McpTool');\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n// Duck-typed like the exception filter: pnpm may load more than one @nestjs/common, so instanceof is not reliable\nfunction isHttpExceptionLike(value: unknown): value is HttpExceptionLike {\n return isRecord(value) && typeof value.getStatus === 'function' && typeof value.getResponse === 'function';\n}\n\n// Walks the cause chain for a Postgres unique violation the way the exception filter does\nfunction findPgUniqueViolation(error: unknown, depth = 0): { detail?: string } | undefined {\n if (!isRecord(error) || depth > 5) return undefined;\n if (error.code === PG_UNIQUE_VIOLATION)\n return { detail: typeof error.detail === 'string' ? error.detail : undefined };\n return findPgUniqueViolation(error.cause, depth + 1);\n}\n\nfunction normalizeFieldErrors(value: unknown): ToolFieldError[] {\n if (!Array.isArray(value)) return [];\n return value.filter(isRecord).map((entry) => ({\n field: typeof entry.field === 'string' ? entry.field : undefined,\n message: typeof entry.message === 'string' ? entry.message : 'Invalid value',\n }));\n}\n\nexport function toolOk(payload: unknown): CallToolResult {\n const structuredContent = isRecord(payload) ? payload : { result: payload };\n return { content: [{ type: 'text', text: JSON.stringify(payload) }], structuredContent };\n}\n\nexport function toolError(problem: ToolProblem): CallToolResult {\n return {\n isError: true,\n content: [{ type: 'text', text: JSON.stringify(problem) }],\n structuredContent: { ...problem },\n };\n}\n\n// Turns whatever a handler threw into the problem shape the REST API speaks, so field errors reach the model verbatim\nexport function problemFromError(error: unknown): ToolProblem {\n if (error instanceof ZodError) {\n return {\n status: 400,\n label: 'Invalid Arguments',\n detail: 'The tool arguments did not match the schema.',\n errors: error.issues.map((issue) => ({ field: issue.path.join('.'), message: issue.message })),\n };\n }\n\n if (isHttpExceptionLike(error)) {\n const status = error.getStatus();\n const body = error.getResponse();\n if (isRecord(body)) {\n const detail =\n typeof body.detail === 'string'\n ? body.detail\n : typeof body.message === 'string'\n ? body.message\n : 'Request failed.';\n return {\n status,\n label: typeof body.label === 'string' ? body.label : undefined,\n detail,\n errors: normalizeFieldErrors(body.errors),\n };\n }\n return { status, detail: typeof body === 'string' ? body : 'Request failed.', errors: [] };\n }\n\n const duplicate = findPgUniqueViolation(error);\n if (duplicate) {\n return {\n status: 409,\n label: 'Duplicate Entry',\n detail: duplicate.detail ?? 'A record with these values already exists.',\n errors: [],\n };\n }\n\n logger.error(`Unhandled tool error: ${error instanceof Error ? error.stack : String(error)}`);\n return { status: 500, detail: 'An unexpected error occurred.', errors: [] };\n}\n","import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { Injectable } from '@nestjs/common';\n\n// One transport per request. Stateless: no session id is issued, so any node can serve any call and nothing is kept\n// between calls. JSON responses rather than an SSE stream, since a tools-only server never pushes notifications.\n@Injectable()\nexport class McpTransportFactory {\n create(): StreamableHTTPServerTransport {\n return new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true });\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport type { OpenAPIObject } from '@nestjs/swagger';\n\ntype JsonSchema = Record<string, unknown>;\n\nconst COMPONENT_REF = '#/components/schemas/';\n\n// Serves the request DTO schemas the REST API already documents (descriptions, examples, enums) to tools that\n// describe resources. The server hands over its live Swagger document at boot, so schemas cannot drift from the DTOs.\n@Injectable()\nexport class McpSchemaRegistry {\n private schemas: Record<string, JsonSchema> = {};\n\n setDocument(document: OpenAPIObject): void {\n this.schemas = (document.components?.schemas ?? {}) as Record<string, JsonSchema>;\n }\n\n // The schema for a DTO class, with its component references inlined as local $defs\n schemaFor(dto: { name: string }): JsonSchema {\n const root = this.schemas[dto.name];\n if (!root) return { type: 'object', description: `The schema for ${dto.name} is unavailable.` };\n const defs: Record<string, JsonSchema> = {};\n const rewritten = this.rewrite(root, defs);\n return Object.keys(defs).length > 0 ? { ...rewritten, $defs: defs } : rewritten;\n }\n\n private rewrite(node: unknown, defs: Record<string, JsonSchema>): JsonSchema {\n if (Array.isArray(node)) return node.map((item) => this.rewrite(item, defs)) as unknown as JsonSchema;\n if (typeof node !== 'object' || node === null) return node as JsonSchema;\n\n const record = node as JsonSchema;\n if (typeof record.$ref === 'string' && record.$ref.startsWith(COMPONENT_REF)) {\n const name = record.$ref.slice(COMPONENT_REF.length);\n if (!(name in defs)) {\n // Placeholder first, so a self-referencing schema terminates\n defs[name] = {};\n defs[name] = this.rewrite(this.schemas[name] ?? {}, defs);\n }\n return { $ref: `#/$defs/${name}` };\n }\n\n const out: JsonSchema = {};\n for (const [key, value] of Object.entries(record)) out[key] = this.rewrite(value, defs);\n return out;\n }\n}\n","import { type ClassConstructor, plainToInstance } from 'class-transformer';\nimport { type ValidationError, validate } from 'class-validator';\nimport { BadRequestException } from '../exceptions';\n\ninterface FieldError {\n field: string;\n message: string;\n}\n\nexport class McpValidationError extends BadRequestException {\n constructor(errors: FieldError[]) {\n super({ label: 'Validation Failed', detail: 'Please check your input and try again.', errors });\n }\n}\n\n// Nested paths (\"entries.0.amount\") where the global pipe only reports the top-level property — an agent needs the path\nfunction flattenValidationErrors(errors: ValidationError[], parent = ''): FieldError[] {\n return errors.flatMap((error) => {\n const field = parent ? `${parent}.${error.property}` : error.property;\n const own = Object.values(error.constraints ?? {}).map((message) => ({ field, message }));\n const nested = error.children?.length ? flattenValidationErrors(error.children, field) : [];\n return [...own, ...nested];\n });\n}\n\n// Validates tool input against the same class-validator DTO the REST endpoint uses, with the global pipe's options\nexport async function validateDto<T extends object>(cls: ClassConstructor<T>, input: unknown): Promise<T> {\n const instance = plainToInstance(cls, input ?? {}, { enableImplicitConversion: true });\n const errors = await validate(instance, { whitelist: true, forbidNonWhitelisted: true });\n if (errors.length > 0) throw new McpValidationError(flattenValidationErrors(errors));\n return instance;\n}\n"],"mappings":"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","names":["collectOperationIds","modules","ids","module","controllers","Reflect","getMetadata","MODULE_METADATA","CONTROLLERS","controller","prototype","method","Object","getOwnPropertyNames","handler","METHOD_METADATA","undefined","push","name","import_common","import_core","MCP_SERVER_OPTIONS","Symbol","import_common","HttpProblemException","HttpException","detailOrOptions","httpStatus","options","detail","type","label","errors","import_common","BadRequestException","HttpProblemException","detailOrOptions","HttpStatus","BAD_REQUEST","import_common","import_common","import_common","import_common","import_common","import_common","import_common","import_common","import_common","import_common","import_common","import_common","import_common","UnauthorizedException","HttpProblemException","detailOrOptions","HttpStatus","UNAUTHORIZED","import_common","import_common","import_common","McpPrincipal","userId","scopes","clientId","grantId","organizationId","hasScope","scope","includes","MCP_PRINCIPAL_FACTORY","Symbol","principalFromOAuth","request","auth","kind","UnauthorizedException","import_common","import_common","import_common","import_zod","import_common","MCP_TOOL_PROVIDER_KEY","McpTools","SetMetadata","defineTool","definition","import_common","PG_UNIQUE_VIOLATION","logger","Logger","isRecord","value","Array","isArray","isHttpExceptionLike","getStatus","getResponse","findPgUniqueViolation","error","depth","undefined","code","detail","cause","normalizeFieldErrors","filter","map","entry","field","message","toolOk","payload","structuredContent","result","content","type","text","JSON","stringify","toolError","problem","isError","problemFromError","ZodError","status","label","errors","issues","issue","path","join","body","duplicate","Error","stack","String","TOOL_NAME_PATTERN","ToolRegistry","logger","Logger","name","definitions","Map","catalog","discovery","reflector","onApplicationBootstrap","provider","findProviders","definition","tools","register","values","map","toCatalogEntry","log","length","listTools","coveredOperationIds","flatMap","covers","execute","rawArgs","principal","started","Date","now","get","toolError","status","label","detail","errors","result","hasScope","requiredScope","args","inputSchema","parse","toolOk","handler","error","problem","problemFromError","userId","grantId","clientId","getProviders","filter","wrapper","metatype","instance","MCP_TOOL_PROVIDER_KEY","test","Error","has","set","title","description","toInputSchema","annotations","readOnlyHint","destructiveHint","idempotentHint","openWorldHint","schema","z","toJSONSchema","io","$schema","type","McpServerFactory","options","toolRegistry","create","principal","server","Server","name","version","capabilities","tools","instructions","setRequestHandler","ListToolsRequestSchema","listTools","CallToolRequestSchema","request","execute","params","arguments","import_common","McpTransportFactory","create","StreamableHTTPServerTransport","sessionIdGenerator","undefined","enableJsonResponse","McpRequestHandler","serverFactory","transportFactory","principalFactory","handle","request","reply","body","principal","hijack","transport","create","server","raw","on","close","connect","handleRequest","methodNotAllowed","status","header","send","jsonrpc","error","code","message","id","import_common","COMPONENT_REF","McpSchemaRegistry","schemas","setDocument","document","components","schemaFor","dto","root","name","type","description","defs","rewritten","rewrite","Object","keys","length","$defs","node","Array","isArray","map","item","record","$ref","startsWith","slice","out","key","value","entries","McpModule","forRoot","options","serverOptions","name","version","instructions","module","imports","DiscoveryModule","providers","provide","MCP_SERVER_OPTIONS","useValue","MCP_PRINCIPAL_FACTORY","principal","principalFromOAuth","McpTransportFactory","McpServerFactory","McpRequestHandler","McpSchemaRegistry","ToolRegistry","exports","McpValidationError","BadRequestException","errors","label","detail","flattenValidationErrors","parent","flatMap","error","field","property","own","Object","values","constraints","map","message","nested","children","length","validateDto","cls","input","instance","plainToInstance","enableImplicitConversion","validate","whitelist","forbidNonWhitelisted"]}
package/dist/mcp.d.cts ADDED
@@ -0,0 +1,135 @@
1
+ import { Type, DynamicModule, OnApplicationBootstrap } from '@nestjs/common';
2
+ import { FastifyRequest, FastifyReply } from 'fastify';
3
+ import './index.cjs';
4
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
5
+ import { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js';
6
+ import { DiscoveryService, Reflector } from '@nestjs/core';
7
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
8
+ import { OpenAPIObject } from '@nestjs/swagger';
9
+ import { ZodType } from 'zod';
10
+ import { ClassConstructor } from 'class-transformer';
11
+ import { B as BadRequestException } from './bad-request.exception-D-KmhiXQ.cjs';
12
+ import './types.cjs';
13
+
14
+ declare function collectOperationIds(modules: Type[]): string[];
15
+
16
+ declare class McpPrincipal {
17
+ readonly userId: string;
18
+ readonly scopes: readonly string[];
19
+ readonly clientId?: string | undefined;
20
+ readonly grantId?: string | undefined;
21
+ readonly organizationId?: string | undefined;
22
+ constructor(userId: string, scopes: readonly string[], clientId?: string | undefined, grantId?: string | undefined, organizationId?: string | undefined);
23
+ hasScope(scope: string): boolean;
24
+ }
25
+ type McpPrincipalFactory = (request: FastifyRequest) => McpPrincipal;
26
+ declare const MCP_PRINCIPAL_FACTORY: unique symbol;
27
+ declare function principalFromOAuth(request: FastifyRequest): McpPrincipal;
28
+
29
+ declare const MCP_SERVER_OPTIONS: unique symbol;
30
+ interface McpServerOptions {
31
+ name: string;
32
+ version: string;
33
+ instructions?: string;
34
+ }
35
+ interface McpModuleOptions extends McpServerOptions {
36
+ principal?: McpPrincipalFactory;
37
+ }
38
+
39
+ declare class McpModule {
40
+ static forRoot(options: McpModuleOptions): DynamicModule;
41
+ }
42
+
43
+ declare class ToolRegistry implements OnApplicationBootstrap {
44
+ private readonly discovery;
45
+ private readonly reflector;
46
+ private readonly logger;
47
+ private readonly definitions;
48
+ private catalog;
49
+ constructor(discovery: DiscoveryService, reflector: Reflector);
50
+ onApplicationBootstrap(): void;
51
+ listTools(): Tool[];
52
+ coveredOperationIds(): string[];
53
+ execute(name: string, rawArgs: unknown, principal: McpPrincipal): Promise<CallToolResult>;
54
+ private findProviders;
55
+ private register;
56
+ private toCatalogEntry;
57
+ private toInputSchema;
58
+ }
59
+
60
+ declare class McpServerFactory {
61
+ private readonly options;
62
+ private readonly toolRegistry;
63
+ constructor(options: McpServerOptions, toolRegistry: ToolRegistry);
64
+ create(principal: McpPrincipal): Server;
65
+ }
66
+
67
+ declare class McpTransportFactory {
68
+ create(): StreamableHTTPServerTransport;
69
+ }
70
+
71
+ declare class McpRequestHandler {
72
+ private readonly serverFactory;
73
+ private readonly transportFactory;
74
+ private readonly principalFactory;
75
+ constructor(serverFactory: McpServerFactory, transportFactory: McpTransportFactory, principalFactory: McpPrincipalFactory);
76
+ handle(request: FastifyRequest, reply: FastifyReply, body: unknown): Promise<void>;
77
+ methodNotAllowed(reply: FastifyReply): void;
78
+ }
79
+
80
+ type JsonSchema = Record<string, unknown>;
81
+ declare class McpSchemaRegistry {
82
+ private schemas;
83
+ setDocument(document: OpenAPIObject): void;
84
+ schemaFor(dto: {
85
+ name: string;
86
+ }): JsonSchema;
87
+ private rewrite;
88
+ }
89
+
90
+ interface McpToolAnnotations {
91
+ readOnlyHint: boolean;
92
+ destructiveHint: boolean;
93
+ idempotentHint: boolean;
94
+ }
95
+ interface ToolDefinition<Args = unknown> {
96
+ name: string;
97
+ title: string;
98
+ description: string;
99
+ inputSchema: ZodType<Args>;
100
+ annotations: McpToolAnnotations;
101
+ requiredScope: string;
102
+ covers: readonly string[];
103
+ handler: (principal: McpPrincipal, args: Args) => Promise<unknown>;
104
+ }
105
+ interface McpToolProvider {
106
+ tools(): ToolDefinition[];
107
+ }
108
+ declare const MCP_TOOL_PROVIDER_KEY = "mcp:tool-provider";
109
+ declare const McpTools: () => ClassDecorator;
110
+ declare function defineTool<Args>(definition: ToolDefinition<Args>): ToolDefinition;
111
+
112
+ interface ToolFieldError {
113
+ field?: string;
114
+ message: string;
115
+ }
116
+ interface ToolProblem {
117
+ status: number;
118
+ label?: string;
119
+ detail: string;
120
+ errors: ToolFieldError[];
121
+ }
122
+ declare function toolOk(payload: unknown): CallToolResult;
123
+ declare function toolError(problem: ToolProblem): CallToolResult;
124
+ declare function problemFromError(error: unknown): ToolProblem;
125
+
126
+ interface FieldError {
127
+ field: string;
128
+ message: string;
129
+ }
130
+ declare class McpValidationError extends BadRequestException {
131
+ constructor(errors: FieldError[]);
132
+ }
133
+ declare function validateDto<T extends object>(cls: ClassConstructor<T>, input: unknown): Promise<T>;
134
+
135
+ export { MCP_PRINCIPAL_FACTORY, MCP_SERVER_OPTIONS, MCP_TOOL_PROVIDER_KEY, McpModule, type McpModuleOptions, McpPrincipal, type McpPrincipalFactory, McpRequestHandler, McpSchemaRegistry, McpServerFactory, type McpServerOptions, type McpToolAnnotations, type McpToolProvider, McpTools, McpTransportFactory, McpValidationError, type ToolDefinition, type ToolFieldError, type ToolProblem, ToolRegistry, collectOperationIds, defineTool, principalFromOAuth, problemFromError, toolError, toolOk, validateDto };
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,135 @@
1
+ import { Type, DynamicModule, OnApplicationBootstrap } from '@nestjs/common';
2
+ import { FastifyRequest, FastifyReply } from 'fastify';
3
+ import './index.js';
4
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
5
+ import { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js';
6
+ import { DiscoveryService, Reflector } from '@nestjs/core';
7
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
8
+ import { OpenAPIObject } from '@nestjs/swagger';
9
+ import { ZodType } from 'zod';
10
+ import { ClassConstructor } from 'class-transformer';
11
+ import { B as BadRequestException } from './bad-request.exception-Db94kZxY.js';
12
+ import './types.js';
13
+
14
+ declare function collectOperationIds(modules: Type[]): string[];
15
+
16
+ declare class McpPrincipal {
17
+ readonly userId: string;
18
+ readonly scopes: readonly string[];
19
+ readonly clientId?: string | undefined;
20
+ readonly grantId?: string | undefined;
21
+ readonly organizationId?: string | undefined;
22
+ constructor(userId: string, scopes: readonly string[], clientId?: string | undefined, grantId?: string | undefined, organizationId?: string | undefined);
23
+ hasScope(scope: string): boolean;
24
+ }
25
+ type McpPrincipalFactory = (request: FastifyRequest) => McpPrincipal;
26
+ declare const MCP_PRINCIPAL_FACTORY: unique symbol;
27
+ declare function principalFromOAuth(request: FastifyRequest): McpPrincipal;
28
+
29
+ declare const MCP_SERVER_OPTIONS: unique symbol;
30
+ interface McpServerOptions {
31
+ name: string;
32
+ version: string;
33
+ instructions?: string;
34
+ }
35
+ interface McpModuleOptions extends McpServerOptions {
36
+ principal?: McpPrincipalFactory;
37
+ }
38
+
39
+ declare class McpModule {
40
+ static forRoot(options: McpModuleOptions): DynamicModule;
41
+ }
42
+
43
+ declare class ToolRegistry implements OnApplicationBootstrap {
44
+ private readonly discovery;
45
+ private readonly reflector;
46
+ private readonly logger;
47
+ private readonly definitions;
48
+ private catalog;
49
+ constructor(discovery: DiscoveryService, reflector: Reflector);
50
+ onApplicationBootstrap(): void;
51
+ listTools(): Tool[];
52
+ coveredOperationIds(): string[];
53
+ execute(name: string, rawArgs: unknown, principal: McpPrincipal): Promise<CallToolResult>;
54
+ private findProviders;
55
+ private register;
56
+ private toCatalogEntry;
57
+ private toInputSchema;
58
+ }
59
+
60
+ declare class McpServerFactory {
61
+ private readonly options;
62
+ private readonly toolRegistry;
63
+ constructor(options: McpServerOptions, toolRegistry: ToolRegistry);
64
+ create(principal: McpPrincipal): Server;
65
+ }
66
+
67
+ declare class McpTransportFactory {
68
+ create(): StreamableHTTPServerTransport;
69
+ }
70
+
71
+ declare class McpRequestHandler {
72
+ private readonly serverFactory;
73
+ private readonly transportFactory;
74
+ private readonly principalFactory;
75
+ constructor(serverFactory: McpServerFactory, transportFactory: McpTransportFactory, principalFactory: McpPrincipalFactory);
76
+ handle(request: FastifyRequest, reply: FastifyReply, body: unknown): Promise<void>;
77
+ methodNotAllowed(reply: FastifyReply): void;
78
+ }
79
+
80
+ type JsonSchema = Record<string, unknown>;
81
+ declare class McpSchemaRegistry {
82
+ private schemas;
83
+ setDocument(document: OpenAPIObject): void;
84
+ schemaFor(dto: {
85
+ name: string;
86
+ }): JsonSchema;
87
+ private rewrite;
88
+ }
89
+
90
+ interface McpToolAnnotations {
91
+ readOnlyHint: boolean;
92
+ destructiveHint: boolean;
93
+ idempotentHint: boolean;
94
+ }
95
+ interface ToolDefinition<Args = unknown> {
96
+ name: string;
97
+ title: string;
98
+ description: string;
99
+ inputSchema: ZodType<Args>;
100
+ annotations: McpToolAnnotations;
101
+ requiredScope: string;
102
+ covers: readonly string[];
103
+ handler: (principal: McpPrincipal, args: Args) => Promise<unknown>;
104
+ }
105
+ interface McpToolProvider {
106
+ tools(): ToolDefinition[];
107
+ }
108
+ declare const MCP_TOOL_PROVIDER_KEY = "mcp:tool-provider";
109
+ declare const McpTools: () => ClassDecorator;
110
+ declare function defineTool<Args>(definition: ToolDefinition<Args>): ToolDefinition;
111
+
112
+ interface ToolFieldError {
113
+ field?: string;
114
+ message: string;
115
+ }
116
+ interface ToolProblem {
117
+ status: number;
118
+ label?: string;
119
+ detail: string;
120
+ errors: ToolFieldError[];
121
+ }
122
+ declare function toolOk(payload: unknown): CallToolResult;
123
+ declare function toolError(problem: ToolProblem): CallToolResult;
124
+ declare function problemFromError(error: unknown): ToolProblem;
125
+
126
+ interface FieldError {
127
+ field: string;
128
+ message: string;
129
+ }
130
+ declare class McpValidationError extends BadRequestException {
131
+ constructor(errors: FieldError[]);
132
+ }
133
+ declare function validateDto<T extends object>(cls: ClassConstructor<T>, input: unknown): Promise<T>;
134
+
135
+ export { MCP_PRINCIPAL_FACTORY, MCP_SERVER_OPTIONS, MCP_TOOL_PROVIDER_KEY, McpModule, type McpModuleOptions, McpPrincipal, type McpPrincipalFactory, McpRequestHandler, McpSchemaRegistry, McpServerFactory, type McpServerOptions, type McpToolAnnotations, type McpToolProvider, McpTools, McpTransportFactory, McpValidationError, type ToolDefinition, type ToolFieldError, type ToolProblem, ToolRegistry, collectOperationIds, defineTool, principalFromOAuth, problemFromError, toolError, toolOk, validateDto };