@happyvertical/smrt-core 0.40.61 → 0.40.63

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.
Files changed (51) hide show
  1. package/AGENTS.md +16 -3
  2. package/README.md +32 -1
  3. package/agents/generators.md +22 -0
  4. package/dist/collection.d.ts +12 -1
  5. package/dist/collection.d.ts.map +1 -1
  6. package/dist/collection.js +37 -5
  7. package/dist/collection.js.map +1 -1
  8. package/dist/decorators/index.d.ts +8 -2
  9. package/dist/decorators/index.d.ts.map +1 -1
  10. package/dist/decorators/index.js.map +1 -1
  11. package/dist/embeddings/types.d.ts +4 -1
  12. package/dist/embeddings/types.d.ts.map +1 -1
  13. package/dist/generators/mcp-emit.d.ts +72 -0
  14. package/dist/generators/mcp-emit.d.ts.map +1 -0
  15. package/dist/generators/mcp-emit.js +104 -0
  16. package/dist/generators/mcp-emit.js.map +1 -0
  17. package/dist/generators/mcp-runtime-template.d.ts +5 -0
  18. package/dist/generators/mcp-runtime-template.d.ts.map +1 -1
  19. package/dist/generators/mcp-runtime-template.js +236 -3
  20. package/dist/generators/mcp-runtime-template.js.map +1 -1
  21. package/dist/generators/mcp.d.ts +63 -3
  22. package/dist/generators/mcp.d.ts.map +1 -1
  23. package/dist/generators/mcp.js +145 -21
  24. package/dist/generators/mcp.js.map +1 -1
  25. package/dist/manifest/generator.d.ts +5 -0
  26. package/dist/manifest/generator.d.ts.map +1 -1
  27. package/dist/manifest/generator.js +10 -7
  28. package/dist/manifest/generator.js.map +1 -1
  29. package/dist/manifest/static-manifest.js +1 -1
  30. package/dist/manifest/static-manifest.js.map +1 -1
  31. package/dist/manifest/store.js +1 -1
  32. package/dist/manifest.json +1 -1
  33. package/dist/object.d.ts +11 -1
  34. package/dist/object.d.ts.map +1 -1
  35. package/dist/object.js +11 -1
  36. package/dist/object.js.map +1 -1
  37. package/dist/registry/types.d.ts +8 -0
  38. package/dist/registry/types.d.ts.map +1 -1
  39. package/dist/smrt-knowledge.json +7 -7
  40. package/dist/system/compatibility.d.ts.map +1 -1
  41. package/dist/system/compatibility.js +6 -0
  42. package/dist/system/compatibility.js.map +1 -1
  43. package/dist/system/types.d.ts +4 -1
  44. package/dist/system/types.d.ts.map +1 -1
  45. package/dist/utils/scanner-module.d.ts +7 -0
  46. package/dist/utils/scanner-module.d.ts.map +1 -1
  47. package/dist/vite-plugin/index.d.ts +7 -0
  48. package/dist/vite-plugin/index.d.ts.map +1 -1
  49. package/dist/vite-plugin/index.js +3 -2
  50. package/dist/vite-plugin/index.js.map +1 -1
  51. package/package.json +10 -12
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","names":[],"sources":["../../src/generators/mcp.ts"],"sourcesContent":["/**\n * MCP (Model Context Protocol) server generator for smrt objects\n *\n * Exposes smrt objects as AI tools for Claude, GPT, and other AI models\n */\n\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { SmrtCollection } from '../collection';\nimport type { PublicJsonOptions, SmrtObject } from '../object';\nimport { ObjectRegistry } from '../registry';\nimport type { RegisteredClass } from '../registry/types.js';\nimport type { FieldDefinition, MethodDefinition } from '../scanner/types.js';\nimport {\n buildCustomActionInvocationArgs,\n type CustomActionFailure,\n type CustomActionMetadata,\n customActionParameterInputName,\n normalizeCustomActionFailure,\n resolveCustomActionMetadata,\n SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY,\n} from './custom-action.js';\nimport {\n generateClaudeConfig,\n generateMCPDocumentation,\n generateMCPScript,\n generateRuntimeBootstrap,\n type RuntimeOptions,\n} from './mcp-runtime-template.js';\nimport { runWithTenantGate } from './tenant-gate.js';\nimport {\n buildToolInputSchema,\n fieldTypeToJsonSchema,\n finalizeMcpJsonSchema,\n type ToolFieldMeta,\n type ToolJsonSchema,\n} from './tool-schema.js';\n\n/**\n * Runtime tool-call arguments. They arrive as untyped JSON from the MCP client,\n * so individual keys are narrowed (`as`) at each action's boundary.\n */\ntype ToolArgs = Record<string, unknown>;\n\n/**\n * A method resolved dynamically (by action name) from an object/collection\n * instance and invoked with the parsed tool-call arguments. Narrowed to this\n * type at the call boundary after a `typeof === 'function'` guard.\n */\ntype InstanceCallable = (...args: unknown[]) => unknown;\n\nexport interface MCPConfig {\n name?: string;\n version?: string;\n description?: string;\n /**\n * Cache policy for generated MCP protocol results.\n *\n * Generated catalog results are private by default. A public tool catalog\n * needs both an explicit public scope and an explicit assertion that the\n * entire catalog is global and unauthenticated; tenant-scoped catalogs are\n * always forced back to private.\n */\n cache?: {\n toolsList?: MCPToolListCacheOptions;\n };\n server?: {\n name: string;\n version: string;\n };\n}\n\nexport const MCP_STABLE_CATALOG_TTL_MS = 86_400_000;\n\nexport interface MCPToolListCacheOptions {\n /** Cache lifetime in milliseconds. Defaults to one day for a deploy-static catalog. */\n ttlMs?: number;\n /** Requested cache visibility. Defaults to private. */\n cacheScope?: 'private' | 'public';\n /**\n * Explicitly attest that every listed tool is global and unauthenticated.\n * This must accompany `cacheScope: 'public'`; tenant-scoped tool sets cannot\n * opt in regardless of this assertion.\n */\n publicCatalog?: true;\n}\n\nexport interface MCPToolListCacheHint {\n ttlMs: number;\n cacheScope: 'private' | 'public';\n}\n\n/**\n * Resolve the generated tools/list cache policy at generation time.\n *\n * A shared cache may otherwise serve one tenant's tool catalog to another, so\n * public caching is deliberately double opt-in and unavailable when a\n * generated server exposes any tenant-scoped object.\n */\nexport function resolveMCPToolListCacheHint(\n options: MCPToolListCacheOptions | undefined,\n hasTenantScopedTools: boolean,\n): MCPToolListCacheHint {\n const ttlMs = options?.ttlMs ?? MCP_STABLE_CATALOG_TTL_MS;\n if (!Number.isSafeInteger(ttlMs) || ttlMs < 0) {\n throw new RangeError(\n 'MCP tools/list cache ttlMs must be a non-negative safe integer.',\n );\n }\n if (\n options?.cacheScope !== undefined &&\n options.cacheScope !== 'private' &&\n options.cacheScope !== 'public'\n ) {\n throw new RangeError(\n \"MCP tools/list cacheScope must be 'private' or 'public'.\",\n );\n }\n\n const cacheScope =\n !hasTenantScopedTools &&\n options?.cacheScope === 'public' &&\n options.publicCatalog === true\n ? 'public'\n : 'private';\n\n return { ttlMs, cacheScope };\n}\n\nexport interface MCPContext {\n db?: unknown;\n ai?: unknown;\n user?: {\n id: string;\n roles?: string[];\n };\n /** Resolved permission slugs held by the caller. */\n permissions?: Iterable<string>;\n /**\n * Tenant the calling principal is scoped to (#1554). When set, tenant-scoped\n * tools run inside this tenant's context. Hosts that authenticate a principal\n * (e.g. `@happyvertical/smrt-app-mcp`) should derive it from the principal —\n * the MCP analogue of the SvelteKit auth hook setting `locals.tenantId`.\n */\n tenantId?: string;\n /**\n * Explicit operator opt-in to cross-tenant access for tenant-scoped tools\n * (#1554). Only set for trusted operator/admin callers. Without a `tenantId`\n * or this flag, tenant-scoped tool calls fail closed when tenancy is enabled.\n */\n allowCrossTenant?: boolean;\n}\n\nexport interface MCPTool {\n name: string;\n description: string;\n inputSchema: ToolJsonSchema;\n /** Public result schema for tools/call structuredContent. */\n outputSchema: ToolJsonSchema;\n}\n\n/** Return a copied, canonical tool sequence for byte-stable tools/list output. */\nexport function sortMCPTools<T extends Pick<MCPTool, 'name'>>(tools: T[]): T[] {\n return [...tools].sort((left, right) =>\n left.name < right.name ? -1 : left.name > right.name ? 1 : 0,\n );\n}\n\nexport interface MCPRequest {\n method: string;\n params: {\n name: string;\n arguments: ToolArgs;\n };\n}\n\nexport interface MCPResponse {\n content: Array<{\n type: 'text';\n text: string;\n }>;\n isError?: boolean;\n _meta?: Record<string, unknown>;\n /** Machine-readable projection matching the tool's declared outputSchema. */\n structuredContent?: unknown;\n}\n\nclass CustomActionFailureError extends Error {\n constructor(readonly failure: CustomActionFailure) {\n super(failure.message);\n this.name = 'CustomActionFailureError';\n }\n}\n\n/**\n * MCP tool identifiers are lowercase for stable protocol vocabulary, while\n * JavaScript method names retain their declared casing. Resolve a tool suffix\n * back to the registry's canonical method name before inspecting metadata or\n * invoking it.\n */\nfunction resolveCustomActionMethod(\n methods: Map<string, MethodDefinition>,\n toolAction: string,\n): [methodName: string, method: MethodDefinition | undefined] {\n const direct = methods.get(toolAction);\n if (direct) return [toolAction, direct];\n for (const [methodName, method] of methods) {\n if (methodName.toLowerCase() === toolAction.toLowerCase()) {\n return [methodName, method];\n }\n }\n return [toolAction, undefined];\n}\n\n/**\n * Generate MCP server from smrt objects\n */\nexport class MCPGenerator {\n private config: MCPConfig;\n private context: MCPContext;\n private collections = new Map<string, SmrtCollection<SmrtObject>>();\n\n constructor(config: MCPConfig = {}, context: MCPContext = {}) {\n this.config = {\n name: 'smrt-mcp-server',\n version: '1.0.0',\n description: 'Auto-generated MCP server from smrt objects',\n server: {\n name: 'smrt-mcp',\n version: '1.0.0',\n },\n ...config,\n };\n this.context = context;\n }\n\n /**\n * Get server name\n */\n get name(): string | undefined {\n return this.config.name;\n }\n\n /**\n * Get server version\n */\n get version(): string | undefined {\n return this.config.version;\n }\n\n /**\n * Generate all available tools from registered objects\n */\n async generateTools(): Promise<MCPTool[]> {\n const tools: MCPTool[] = [];\n const registeredClasses = ObjectRegistry.getAllClasses();\n\n for (const [key, classInfo] of registeredClasses) {\n // Issue #951: Use simple name for tool naming, map key for registry lookups\n const simpleName = classInfo.name || key;\n const config = ObjectRegistry.getConfig(simpleName);\n const mcpConfig = config.mcp;\n\n // `mcp: false` disables MCP generation entirely for the class. Without\n // this gate an `include` list still leaked custom-method tools (the\n // custom-method branch historically only honored `include` when it\n // listed custom methods), so `false` is the only fully fail-closed\n // switch. Mirrors rest.ts's `apiConfig === false` short-circuit\n // (#1540 / #1546).\n if (mcpConfig === false) {\n continue;\n }\n\n // Handle boolean vs object config\n const excluded: string[] =\n typeof mcpConfig === 'object' && mcpConfig?.exclude\n ? mcpConfig.exclude\n : [];\n const included: string[] | undefined =\n typeof mcpConfig === 'object' ? mcpConfig?.include : undefined;\n\n const shouldInclude = (endpoint: string) => {\n if (included && !included.includes(endpoint)) return false;\n if (excluded.includes(endpoint)) return false;\n return true;\n };\n\n const objectTools = await this.generateObjectTools(\n simpleName,\n shouldInclude,\n );\n tools.push(...objectTools);\n }\n\n return sortMCPTools(tools);\n }\n\n /**\n * Generate tools for a specific object\n */\n private async generateObjectTools(\n objectName: string,\n shouldInclude: (endpoint: string) => boolean,\n ): Promise<MCPTool[]> {\n const tools: MCPTool[] = [];\n const fields = ObjectRegistry.getFields(objectName);\n const lowerName = objectName.toLowerCase();\n const classInfo = ObjectRegistry.getClass(objectName);\n\n // LIST tool\n if (shouldInclude('list')) {\n tools.push({\n name: `${lowerName}_list`,\n description: `List ${objectName} objects with optional filtering`,\n inputSchema: this.buildInputSchema(objectName, 'list', fields),\n outputSchema: this.buildOutputSchema(objectName, 'list', fields),\n });\n }\n\n // GET tool\n if (shouldInclude('get')) {\n tools.push({\n name: `${lowerName}_get`,\n description: `Get a specific ${objectName} by ID or slug`,\n inputSchema: this.buildInputSchema(objectName, 'get', fields),\n outputSchema: this.buildOutputSchema(objectName, 'get', fields),\n });\n }\n\n // CREATE tool\n if (shouldInclude('create')) {\n tools.push({\n name: `${lowerName}_create`,\n description: `Create a new ${objectName}`,\n inputSchema: this.buildInputSchema(objectName, 'create', fields),\n outputSchema: this.buildOutputSchema(objectName, 'create', fields),\n });\n }\n\n // UPDATE tool\n if (shouldInclude('update')) {\n tools.push({\n name: `${lowerName}_update`,\n description: `Update an existing ${objectName}`,\n inputSchema: this.buildInputSchema(objectName, 'update', fields),\n outputSchema: this.buildOutputSchema(objectName, 'update', fields),\n });\n }\n\n // DELETE tool\n if (shouldInclude('delete')) {\n tools.push({\n name: `${lowerName}_delete`,\n description: `Delete a ${objectName} by ID`,\n inputSchema: this.buildInputSchema(objectName, 'delete', fields),\n outputSchema: this.buildOutputSchema(objectName, 'delete', fields),\n });\n }\n\n // CUSTOM METHODS - discover from manifest and show by default\n if (classInfo) {\n const config = ObjectRegistry.getConfig(objectName);\n const mcpConfig = config.mcp;\n const included: string[] | undefined =\n typeof mcpConfig === 'object' ? mcpConfig?.include : undefined;\n const excluded: string[] =\n typeof mcpConfig === 'object' && mcpConfig?.exclude\n ? mcpConfig.exclude\n : [];\n\n // When an `include` list is present it is the COMPLETE allowlist for\n // this surface: a custom (non-CRUD) method is exposed ONLY if its name\n // appears in `include`. Without an include list we keep the historical\n // default of auto-exposing every public method. This closes the leak\n // where `mcp: { include: ['list', 'get'] }` still emitted custom-method\n // tools like `payment_recordpayment` because `include` only gated CRUD\n // verbs (#1540 / #1390).\n const crudOperations = ['list', 'get', 'create', 'update', 'delete'];\n const customMethodsInInclude =\n included?.filter((item) => !crudOperations.includes(item)) || [];\n // An include list (even one naming only CRUD verbs) switches custom\n // methods into strict allowlist mode.\n const hasIncludeList = included !== undefined;\n\n // Try to discover methods from manifest (including inherited methods)\n const methods = await ObjectRegistry.getAllMethods(objectName);\n const methodNames = new Set(Array.from(methods.keys()));\n\n // Strict mode: an include list is present, so only the custom methods it\n // names are generated (may be none, e.g. include: ['list', 'get']).\n if (hasIncludeList) {\n for (const methodName of customMethodsInInclude) {\n // Skip if explicitly excluded\n if (excluded.includes(methodName)) continue;\n\n // Check if method exists (in manifest or on class prototype)\n const existsInManifest = methodNames.has(methodName);\n const existsOnClass = this.validateCustomMethod(\n classInfo.constructor,\n methodName,\n );\n\n if (!existsInManifest && !existsOnClass) {\n // Warn about missing methods\n console.warn(\n `Warning: Custom action '${methodName}' specified in MCP config for ${objectName}, but method ${methodName}() not found on class`,\n );\n continue;\n }\n\n // A non-public method must never be exposed as a tool, even when it\n // is explicitly named in `include`. This keeps strict-include mode\n // consistent with the non-strict path below, which gates on\n // `methodDef.isPublic`. Listing a private method in `include` is a\n // config mistake, not an override of method visibility (#1540).\n //\n // The scanner strips private/protected methods from the manifest, so\n // when a non-public method is named in `include` it is absent from\n // `methods` and is only resolvable via validateCustomMethod() on the\n // runtime prototype (TS access modifiers are erased at runtime). Such\n // a method must NOT be emitted. We still allow methods that are\n // present on the class but legitimately absent from the manifest\n // (e.g. inline/dynamically registered classes), so the guard fires\n // only when there is a public manifest entry to anchor on OR the\n // method exists solely as a stripped (non-public) manifest method.\n const methodDef = methods.get(methodName);\n if (methodDef && !methodDef.isPublic) continue;\n\n tools.push(\n this.buildCustomActionTool(\n objectName,\n lowerName,\n methodName,\n methodDef,\n this.hasCollectionReceiver(classInfo),\n ),\n );\n }\n } else {\n // No custom methods in include = show all discovered methods by default\n for (const [methodName, methodDef] of methods) {\n // Skip if not public (private/protected methods shouldn't be in MCP)\n if (!methodDef.isPublic) continue;\n\n // Always respect exclude list\n if (excluded.includes(methodName)) continue;\n\n tools.push(\n this.buildCustomActionTool(\n objectName,\n lowerName,\n methodName,\n methodDef,\n this.hasCollectionReceiver(classInfo),\n ),\n );\n }\n }\n }\n\n return tools;\n }\n\n private buildCustomActionTool(\n objectName: string,\n lowerName: string,\n methodName: string,\n methodDef?: MethodDefinition,\n collectionReceiver = false,\n ): MCPTool {\n const metadata = this.resolveCustomActionMetadata(\n objectName,\n methodName,\n methodDef,\n collectionReceiver,\n );\n return {\n name: `${lowerName}_${methodName}`.toLowerCase(),\n description: `Execute ${methodName} action on ${objectName}`,\n inputSchema: this.buildInputSchema(\n objectName,\n methodName,\n ObjectRegistry.getFields(objectName),\n metadata,\n ),\n outputSchema: this.buildOutputSchema(\n objectName,\n methodName,\n ObjectRegistry.getFields(objectName),\n ),\n };\n }\n\n private resolveCustomActionMetadata(\n objectName: string,\n action: string,\n method?: MethodDefinition,\n collectionReceiver = false,\n ): CustomActionMetadata {\n return resolveCustomActionMetadata({\n actionName: action,\n method,\n apiConfig: ObjectRegistry.getConfig(objectName).api,\n ...(collectionReceiver ? { defaultScope: 'collection' } : {}),\n });\n }\n\n private hasCollectionReceiver(classInfo?: RegisteredClass): boolean {\n return (\n !!classInfo && classInfo.constructor.prototype instanceof SmrtCollection\n );\n }\n\n /**\n * Validate that a custom method exists on a class\n */\n private validateCustomMethod(\n classConstructor: typeof SmrtObject,\n methodName: string,\n ): boolean {\n try {\n // Check if method exists on the prototype\n const prototype = classConstructor.prototype;\n\n // Check if the method exists and is a function. Dynamic name lookup, so\n // index through a record view of the prototype/constructor.\n if (\n typeof (prototype as unknown as Record<string, unknown>)[methodName] ===\n 'function'\n ) {\n return true;\n }\n\n // Also check static methods\n if (\n typeof (classConstructor as unknown as Record<string, unknown>)[\n methodName\n ] === 'function'\n ) {\n return true;\n }\n\n return false;\n } catch (error) {\n console.warn(\n `Error validating method ${methodName} on class ${classConstructor.name}:`,\n error,\n );\n return false;\n }\n }\n\n /** Normalize registry fields for the transport-neutral schema emitter. */\n private toToolFields(fields: Map<string, FieldDefinition>): ToolFieldMeta[] {\n return Array.from(fields, ([name, field]) => ({\n name,\n type: field.type,\n required: field.required ?? field._meta?.required,\n nullable: field._meta?.nullable === true,\n description:\n typeof field._meta?.description === 'string'\n ? field._meta.description\n : undefined,\n default: field._meta?.default,\n maxLength: field._meta?.maxLength,\n minLength: field._meta?.minLength,\n min: field._meta?.min,\n max: field._meta?.max,\n related: field.related,\n }));\n }\n\n /**\n * Add the optional STI discriminator branches to write schemas. The legacy\n * branch preserves existing base-class creates that let SMRT pick the base\n * type; an explicit `_meta_type` selects a known child collection below.\n */\n private buildInputSchema(\n objectName: string,\n action: string,\n fields: Map<string, FieldDefinition>,\n customAction?: CustomActionMetadata,\n ): ToolJsonSchema {\n const schema = buildToolInputSchema(\n action,\n this.toToolFields(fields),\n customAction,\n ObjectRegistry.getConfig(objectName).idType,\n );\n if (action !== 'create' && action !== 'update') return schema;\n\n const variants = this.getStiVariants(objectName);\n if (variants.length === 0) return schema;\n\n const properties = {\n ...((schema.properties as Record<string, ToolJsonSchema> | undefined) ??\n {}),\n _meta_type: {\n type: 'string',\n description:\n 'Optional STI discriminator. When provided for create, selects the declared subtype.',\n },\n };\n return finalizeMcpJsonSchema({\n ...schema,\n properties,\n oneOf: [\n { not: { required: ['_meta_type'] } },\n ...variants.map(({ name, discriminator }) => {\n const variantFields = ObjectRegistry.getFields(name);\n return {\n properties: {\n ...this.buildFieldSchemaProperties(variantFields),\n _meta_type: { const: discriminator },\n },\n required: [\n '_meta_type',\n ...this.toToolFields(variantFields)\n .filter((field) => field.required)\n .map((field) => field.name),\n ],\n };\n }),\n ],\n });\n }\n\n /**\n * Public output schemas follow the actual `toPublicJSON()` boundary: known\n * non-sensitive fields are described, while `additionalProperties` keeps\n * framework/system fields and application transforms honest.\n */\n private buildOutputSchema(\n objectName: string,\n action: string,\n fields: Map<string, FieldDefinition>,\n ): ToolJsonSchema {\n const errorSchema: ToolJsonSchema = {\n type: 'object',\n properties: {\n error: { type: 'object', additionalProperties: true },\n },\n required: ['error'],\n };\n\n if (!['list', 'get', 'create', 'update', 'delete'].includes(action)) {\n // Custom action results are deliberately domain-defined and can be any\n // JSON value. MCP structuredContent itself must be object-rooted, so the\n // machine-readable projection carries that value in `data`; legacy text\n // keeps the original public result unchanged.\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [\n {\n type: 'object',\n properties: { data: {} },\n required: ['data'],\n },\n { $ref: '#/$defs/error' },\n ],\n $defs: { error: errorSchema },\n });\n }\n\n const itemSchema = this.buildPublicItemSchema(objectName, fields);\n\n if (action === 'list') {\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [\n {\n type: 'object',\n properties: {\n data: {\n type: 'array',\n items: { $ref: '#/$defs/publicItem' },\n },\n meta: {\n type: 'object',\n properties: {\n total: { type: 'integer', minimum: 0 },\n limit: { type: 'integer', minimum: 0 },\n offset: { type: 'integer', minimum: 0 },\n count: { type: 'integer', minimum: 0 },\n },\n required: ['total', 'limit', 'offset', 'count'],\n },\n },\n required: ['data', 'meta'],\n },\n { $ref: '#/$defs/error' },\n ],\n $defs: { publicItem: itemSchema, error: errorSchema },\n });\n }\n\n if (action === 'delete') {\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [\n {\n type: 'object',\n properties: {\n success: { const: true },\n message: { type: 'string' },\n },\n required: ['success', 'message'],\n },\n { $ref: '#/$defs/error' },\n ],\n $defs: { error: errorSchema },\n });\n }\n\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [itemSchema, { $ref: '#/$defs/error' }],\n $defs: { error: errorSchema },\n });\n }\n\n private buildPublicItemSchema(\n objectName: string,\n fields: Map<string, FieldDefinition>,\n ): ToolJsonSchema {\n const properties = this.buildFieldSchemaProperties(fields, true);\n\n const variants = this.getStiVariants(objectName);\n if (variants.length > 0) {\n return {\n oneOf: variants.map(({ name, discriminator }) => ({\n type: 'object',\n properties: {\n ...this.buildFieldSchemaProperties(\n ObjectRegistry.getFields(name),\n true,\n ),\n _meta_type: { const: discriminator },\n },\n required: ['_meta_type'],\n additionalProperties: true,\n })),\n };\n }\n\n return { type: 'object', properties, additionalProperties: true };\n }\n\n private buildFieldSchemaProperties(\n fields: Map<string, FieldDefinition>,\n publicOnly = false,\n ): Record<string, ToolJsonSchema> {\n const properties: Record<string, ToolJsonSchema> = {};\n for (const [name, field] of fields) {\n if (\n publicOnly &&\n (field._meta?.sensitive === true || field._meta?.transient === true)\n ) {\n continue;\n }\n const [toolField] = this.toToolFields(new Map([[name, field]]));\n if (!toolField) continue;\n properties[name] = { ...fieldTypeToJsonSchema(toolField) };\n }\n return properties;\n }\n\n private getStiVariants(\n objectName: string,\n ): Array<{ name: string; discriminator: string }> {\n if (ObjectRegistry.getTableStrategy(objectName) !== 'sti') return [];\n\n const base = ObjectRegistry.getClass(objectName);\n const baseNames = new Set(\n [objectName, base?.name, base?.qualifiedName].filter(\n (name): name is string => typeof name === 'string',\n ),\n );\n const variants = new Map<string, { name: string; discriminator: string }>();\n for (const [key, info] of ObjectRegistry.getAllClasses()) {\n const name = info.name || key;\n const chain = ObjectRegistry.getInheritanceChain(name);\n if (!chain.some((ancestor) => baseNames.has(ancestor))) continue;\n const discriminator = info.qualifiedName || name;\n variants.set(discriminator, { name, discriminator });\n }\n return Array.from(variants.values()).sort((left, right) =>\n left.discriminator.localeCompare(right.discriminator),\n );\n }\n\n /**\n * Handle MCP tool calls\n */\n async handleToolCall(request: MCPRequest): Promise<MCPResponse> {\n const { name, arguments: args } = request.params;\n\n try {\n // Check if tool exists\n const availableTools = await this.generateTools();\n const toolExists = availableTools.some((t) => t.name === name);\n\n if (!toolExists) {\n throw new Error(`Unknown tool: ${name}`);\n }\n\n // Parse tool name: `objectname_action`. Split on the FIRST underscore\n // only — a custom method name can itself contain underscores (e.g.\n // `record_payment` → tool `invoice_record_payment`). A naive\n // `name.split('_')` would take `action` as just `record` and mis-route\n // the call. The emitted stdio servers switch on the full tool name, so\n // splitting greedily here also kept the in-process path divergent (#1378).\n const firstUnderscore = name.indexOf('_');\n const objectName =\n firstUnderscore === -1 ? '' : name.slice(0, firstUnderscore);\n const action =\n firstUnderscore === -1 ? '' : name.slice(firstUnderscore + 1);\n\n if (!objectName || !action) {\n throw new Error(`Invalid tool name format: ${name}`);\n }\n\n // Find the registered class (case-insensitive)\n const registeredClasses = ObjectRegistry.getAllClasses();\n let classInfo = null;\n let actualObjectName = '';\n\n for (const [_key, info] of registeredClasses) {\n // Issue #951: Match by simple name, not the qualified map key\n const simpleName = info.name || _key;\n if (simpleName.toLowerCase() === objectName.toLowerCase()) {\n classInfo = info;\n actualObjectName = simpleName;\n break;\n }\n }\n\n if (!classInfo) {\n throw new Error(`Object type '${objectName}' not found`);\n }\n\n // Get or create collection\n const collection = await this.getCollection(actualObjectName, classInfo);\n\n // Execute the action\n const result = await this.executeAction(\n collection,\n action,\n args,\n actualObjectName,\n );\n const publicResult = this.toJsonValue(result);\n const structuredContent = this.toStructuredContent(action, publicResult);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(publicResult, null, 2),\n },\n ],\n structuredContent,\n };\n } catch (error) {\n if (error instanceof CustomActionFailureError) {\n const structuredContent = { error: error.failure };\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(structuredContent),\n },\n ],\n isError: true,\n structuredContent,\n _meta: {\n [SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY]: error.failure,\n },\n };\n }\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${message}`,\n },\n ],\n isError: true,\n structuredContent: { error: { message } },\n };\n }\n }\n\n /** Convert runtime values to the JSON values MCP structuredContent permits. */\n private toJsonValue(value: unknown): unknown {\n const serialized = JSON.stringify(value);\n return serialized === undefined ? null : JSON.parse(serialized);\n }\n\n /** Build the MCP-required object root without changing legacy text payloads. */\n private toStructuredContent(\n action: string,\n publicResult: unknown,\n ): Record<string, unknown> {\n if (!['list', 'get', 'create', 'update', 'delete'].includes(action)) {\n return { data: publicResult };\n }\n if (\n publicResult === null ||\n typeof publicResult !== 'object' ||\n Array.isArray(publicResult)\n ) {\n throw new Error(`Expected object result for MCP ${action} action`);\n }\n return publicResult as Record<string, unknown>;\n }\n\n /**\n * Get or create collection for an object\n */\n private async getCollection(\n objectName: string,\n classInfo: RegisteredClass,\n ): Promise<SmrtCollection<SmrtObject>> {\n if (!this.collections.has(objectName)) {\n // Ensure we have a valid collection constructor\n if (\n !classInfo.collectionConstructor ||\n typeof classInfo.collectionConstructor !== 'function'\n ) {\n throw new Error(\n `No valid collection constructor found for ${objectName}`,\n );\n }\n\n const collection = new classInfo.collectionConstructor({\n ai: this.context.ai,\n db: this.context.db,\n });\n\n // Verify the collection is actually a SmrtCollection instance\n if (!(collection instanceof SmrtCollection)) {\n throw new Error(\n `Collection for ${objectName} must extend SmrtCollection`,\n );\n }\n\n // Initialize the collection (database setup, etc.)\n await collection.initialize();\n\n this.collections.set(objectName, collection);\n }\n const collection = this.collections.get(objectName);\n if (!collection) {\n throw new Error(`Collection for ${objectName} not found`);\n }\n return collection;\n }\n\n /**\n * Serialize a tool-response payload, excluding sensitive fields (#1540).\n * Recurses through arrays and plain objects so a SmrtObject nested inside a\n * custom-action result (e.g. `{ item }`) is also stripped — `JSON.stringify`\n * would otherwise call its `toJSON()`. Non-plain instances (Date, etc.) and\n * primitives pass through unchanged; a cycle guard prevents infinite loops.\n */\n private toPublicData(\n value: unknown,\n seen: WeakSet<object> = new WeakSet(),\n options: PublicJsonOptions = this.getPublicJsonOptions(),\n ): unknown {\n if (value === null || typeof value !== 'object') return value;\n const publicSource = value as {\n toPublicJSON?: (options?: PublicJsonOptions) => unknown;\n };\n if (typeof publicSource.toPublicJSON === 'function') {\n return publicSource.toPublicJSON(options);\n }\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((entry) => this.toPublicData(entry, seen, options));\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n if (seen.has(value)) return value;\n seen.add(value);\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n out[key] = this.toPublicData(entry, seen, options);\n }\n return out;\n }\n\n private getPublicJsonOptions(): PublicJsonOptions {\n return { permissions: this.context.permissions };\n }\n\n /**\n * Mass-assignment guard (#1540): strip framework/server-managed and\n * `@field({ readonly: true })` fields from a create/update body, and — when an\n * `@smrt({ api: { writable: [...] } })` allowlist is set — intersect with it.\n */\n private applyWritablePolicy(\n objectName: string | undefined,\n data: unknown,\n ): Record<string, unknown> {\n if (!data || typeof data !== 'object') {\n return {};\n }\n\n const serverManaged = new Set([\n 'id',\n 'tenantId',\n 'tenant_id',\n 'createdAt',\n 'created_at',\n 'updatedAt',\n 'updated_at',\n ]);\n\n const readonly = new Set<string>();\n let writable: string[] | null = null;\n\n if (objectName) {\n const apiConfig = ObjectRegistry.getConfig(objectName)?.api;\n if (\n apiConfig &&\n typeof apiConfig === 'object' &&\n Array.isArray((apiConfig as { writable?: unknown }).writable)\n ) {\n writable = (apiConfig as { writable: string[] }).writable;\n }\n\n for (const [name, def] of ObjectRegistry.getFields(objectName)) {\n if (def && (def.readonly === true || def._meta?.readonly === true)) {\n readonly.add(name);\n }\n }\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (key.startsWith('_')) continue;\n if (serverManaged.has(key)) continue;\n if (readonly.has(key)) continue;\n if (writable && !writable.includes(key)) continue;\n result[key] = value;\n }\n return result;\n }\n\n /**\n * Execute action on collection\n */\n /**\n * Fail-closed authorization for tool calls (#1540). Mutating tools\n * (create/update/delete + custom actions) require an authenticated principal\n * (`context.user`) unless the object opts out via `@smrt({ api: { public } })`.\n * Reads are allowed when `public` is `true` or `'read'`.\n */\n private requireToolAuth(\n objectName: string | undefined,\n mutating: boolean,\n ): void {\n const apiConfig = objectName\n ? ObjectRegistry.getConfig(objectName)?.api\n : undefined;\n const publicAccess =\n apiConfig && typeof apiConfig === 'object'\n ? (apiConfig as { public?: boolean | 'read' }).public\n : undefined;\n\n if (publicAccess === true) return;\n if (publicAccess === 'read' && !mutating) return;\n if (!this.context.user) {\n throw new Error('Authentication required');\n }\n }\n\n private async executeAction(\n collection: SmrtCollection<SmrtObject>,\n action: string,\n args: ToolArgs,\n objectName?: string,\n ): Promise<unknown> {\n let targetCollection = collection;\n let targetObjectName = objectName;\n if (\n action === 'create' &&\n objectName &&\n typeof args._meta_type === 'string'\n ) {\n const variant = this.getStiVariants(objectName).find(\n (candidate) => candidate.discriminator === args._meta_type,\n );\n if (!variant) {\n throw new Error(`Unknown STI discriminator: ${args._meta_type}`);\n }\n const classInfo = ObjectRegistry.getClass(variant.name);\n if (!classInfo) {\n throw new Error(`STI subtype '${variant.name}' is not registered`);\n }\n targetCollection = await this.getCollection(variant.name, classInfo);\n targetObjectName = variant.name;\n }\n\n const mutating = action !== 'list' && action !== 'get';\n this.requireToolAuth(targetObjectName, mutating);\n\n // Fail-closed tenant context (#1554). For tenant-scoped objects, establish\n // the context from the principal's tenant (or an explicit cross-tenant\n // opt-in); without either, this throws when tenancy is enabled rather than\n // letting an optional-scoped read range across all tenants. Tenant-scoping\n // is resolved inside tenancy by class name so it matches the interceptor.\n return runWithTenantGate(\n {\n className: targetObjectName,\n tenantId: this.context.tenantId,\n allowCrossTenant: this.context.allowCrossTenant,\n surface: 'MCP',\n },\n () => this.runAction(targetCollection, action, args, targetObjectName),\n );\n }\n\n /**\n * Derive the set of tenant-scoped object names (lowercased simple names) from\n * a generated tool list, for the emitted runtime template's tenant gate\n * (#1554). Tool names are `objectname_action`.\n *\n * Detection uses ONLY tenancy's `isTenantScopedClass` (the authoritative\n * source the interceptor uses; covers `@TenantScoped`), consulted via an\n * optional dynamic import. We deliberately do NOT fall back to core's\n * `ObjectRegistry.isTenantScoped`: a `@smrt({ tenantScoped })` model can exist\n * in an app that has NOT installed `@happyvertical/smrt-tenancy`, and emitting\n * the static `import { runTenantScopedEntryPoint } from '@happyvertical/smrt-tenancy'`\n * gate for it would crash the generated server at import time. When tenancy is\n * absent there is also nothing to enforce, so emitting no gate is correct.\n */\n private async tenantScopedObjectNames(tools: MCPTool[]): Promise<string[]> {\n let isTenantScopedClass: ((name: string) => boolean) | undefined;\n try {\n // Held in a variable so neither TypeScript's declaration emit (TS2307 —\n // core deliberately does not depend on tenancy) nor the bundler tries to\n // statically resolve this optional sibling package. Same pattern as\n // `tenant-gate.ts` / `embeddings/provider.ts`.\n const tenancySpecifier = '@happyvertical/smrt-tenancy';\n const tenancy = (await import(/* @vite-ignore */ tenancySpecifier)) as {\n isTenantScopedClass?: (name: string) => boolean;\n };\n isTenantScopedClass = tenancy.isTenantScopedClass;\n } catch {\n isTenantScopedClass = undefined;\n }\n\n // No tenancy package installed → no gate can run, emit none.\n if (typeof isTenantScopedClass !== 'function') return [];\n\n const scoped = new Set<string>();\n for (const tool of tools) {\n const [objectName] = tool.name.split('_');\n if (!objectName) continue;\n // Resolve the registered simple name (case-insensitive) and test scoping.\n for (const [key, info] of ObjectRegistry.getAllClasses()) {\n const simpleName = info.name || key;\n if (simpleName.toLowerCase() === objectName.toLowerCase()) {\n if (isTenantScopedClass(simpleName)) {\n scoped.add(simpleName.toLowerCase());\n }\n break;\n }\n }\n }\n return Array.from(scoped);\n }\n\n /**\n * Whether a catalog contains a tenant-scoped class for cache isolation.\n *\n * Unlike the emitted runtime tenant gate, cache visibility must also fail\n * closed for core-declared `@smrt({ tenantScoped })` models when the optional\n * tenancy package is not installed. The registry covers that form, while\n * `tenantScopedObjectNames()` covers the tenancy-owned decorator form.\n */\n private async hasTenantScopedTools(tools: MCPTool[]): Promise<boolean> {\n if ((await this.tenantScopedObjectNames(tools)).length > 0) return true;\n\n for (const tool of tools) {\n const [objectName] = tool.name.split('_');\n if (!objectName) continue;\n for (const [key, info] of ObjectRegistry.getAllClasses()) {\n const simpleName = info.name || key;\n if (simpleName.toLowerCase() === objectName.toLowerCase()) {\n if (ObjectRegistry.isTenantScoped(simpleName)) return true;\n break;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Execute a resolved MCP action (CRUD or custom) against a collection. Always\n * invoked inside the tenant gate established by {@link executeAction}.\n */\n private async runAction(\n collection: SmrtCollection<SmrtObject>,\n action: string,\n args: ToolArgs,\n objectName?: string,\n ): Promise<unknown> {\n switch (action) {\n case 'list': {\n // Args arrive as untyped JSON; narrow each query field at this\n // boundary. `where`/`orderBy` are passed through to the collection's\n // typed query API.\n const listOptions: Parameters<typeof collection.list>[0] = {\n limit: Math.min((args.limit as number | undefined) || 50, 1000),\n offset: (args.offset as number | undefined) || 0,\n };\n\n if (args.where) {\n listOptions.where = args.where as (typeof listOptions)['where'];\n }\n\n if (args.orderBy) {\n listOptions.orderBy = args.orderBy as string | string[];\n }\n\n const results = await collection.list(listOptions);\n const total = await collection.count({\n where: (args.where as (typeof listOptions)['where']) || {},\n });\n\n return {\n data: results.map((result) => this.toPublicData(result)),\n meta: {\n total,\n limit: listOptions.limit,\n offset: listOptions.offset,\n count: results.length,\n },\n };\n }\n\n case 'get': {\n if (!args.id && !args.slug) {\n throw new Error('Either id or slug is required');\n }\n\n const filter = (args.id ? args.id : args.slug) as string;\n const item = await collection.get(filter);\n\n if (!item) {\n throw new Error('Object not found');\n }\n\n return this.toPublicData(item);\n }\n\n case 'create': {\n // Mass-assignment guard (#1540): only writable fields from the caller.\n const createData: Record<string, unknown> = this.applyWritablePolicy(\n objectName,\n args,\n );\n // Server-set ownership context (not caller-controlled).\n if (this.context.user) {\n createData.created_by = this.context.user.id;\n createData.owner_id = this.context.user.id;\n }\n\n // The writable-policy output is a dynamically-shaped record of caller\n // data; cast to the collection's create input at this boundary.\n const newItem = await collection.create(\n createData as Parameters<typeof collection.create>[0],\n );\n await newItem.save();\n\n return this.toPublicData(newItem);\n }\n\n case 'update': {\n const id = args.id as string | undefined;\n if (!id) {\n throw new Error('ID is required for update');\n }\n\n const existing = await collection.get(id);\n if (!existing) {\n throw new Error('Object not found');\n }\n\n // Mass-assignment guard (#1540): strip server-managed/read-only keys\n // (incl. `id`) before applying caller-supplied updates.\n const updateData = this.applyWritablePolicy(objectName, args);\n Object.assign(existing, updateData);\n\n // Add user context. `updated_by` is a server-set audit column, not a\n // declared model field, so assign it through a record view.\n if (this.context.user) {\n (existing as unknown as Record<string, unknown>).updated_by =\n this.context.user.id;\n }\n\n await existing.save();\n\n return this.toPublicData(existing);\n }\n\n case 'delete': {\n if (!args.id) {\n throw new Error('ID is required for delete');\n }\n\n const toDelete = await collection.get(args.id as string);\n if (!toDelete) {\n throw new Error('Object not found');\n }\n\n await toDelete.delete();\n\n return { success: true, message: 'Object deleted successfully' };\n }\n\n default: {\n // Handle custom actions. The method may return a SmrtObject (or array),\n // so serialize through toPublicData to strip sensitive fields (#1540).\n const result = await this.executeCustomAction(\n collection,\n action,\n args,\n objectName,\n );\n return this.toPublicData(result);\n }\n }\n }\n\n /**\n * Execute a custom action on a collection/object\n */\n private async executeCustomAction(\n collection: SmrtCollection<SmrtObject>,\n action: string,\n args: ToolArgs,\n objectName?: string,\n ): Promise<unknown> {\n const id = args.id;\n const [methodName, methodDef] = objectName\n ? resolveCustomActionMethod(\n await ObjectRegistry.getAllMethods(objectName),\n action,\n )\n : [action, undefined];\n const metadata = this.resolveCustomActionMetadata(\n objectName ?? '',\n methodName,\n methodDef,\n objectName\n ? this.hasCollectionReceiver(ObjectRegistry.getClass(objectName))\n : false,\n );\n const methodArgs = buildCustomActionInvocationArgs(metadata, args);\n\n try {\n if (methodDef && metadata.idRequired && !id) {\n throw new Error(`ID is required for custom action '${action}'`);\n }\n if (!metadata.idRequired && id && methodDef) {\n throw new Error(\n `Custom action '${action}' is collection-scoped and does not accept an ID`,\n );\n }\n\n // If an ID is provided, get the specific object and call the method on it\n if (id) {\n const object = await collection.get(id as string);\n if (!object) {\n throw new Error('Object not found');\n }\n\n // Custom action names are resolved dynamically, so index the instance\n // through a record view and narrow the value to a callable after the\n // `typeof === 'function'` guard.\n const objectWithMethods = object as unknown as Record<string, unknown>;\n const objectMethod = objectWithMethods[methodName];\n if (typeof objectMethod === 'function') {\n // `.call(object, …)` preserves the receiver binding of the original\n // member call (`object[action](…)`) — the method relies on `this`.\n const result = await (objectMethod as InstanceCallable).call(\n object,\n ...methodArgs,\n );\n const failure = normalizeCustomActionFailure(result);\n if (failure) throw new CustomActionFailureError(failure);\n return result;\n } else {\n throw new Error(\n `Method '${methodName}' not found on object instance`,\n );\n }\n } else if (metadata.isStatic && objectName) {\n const classInfo = ObjectRegistry.getClass(objectName);\n const classMethod = (\n classInfo?.constructor as unknown as\n | Record<string, unknown>\n | undefined\n )?.[methodName];\n if (typeof classMethod !== 'function') {\n throw new Error(\n `Static method '${methodName}' not found on ${objectName}`,\n );\n }\n const result = await (classMethod as InstanceCallable).call(\n classInfo?.constructor,\n ...methodArgs,\n );\n const failure = normalizeCustomActionFailure(result);\n if (failure) throw new CustomActionFailureError(failure);\n return result;\n } else {\n // No ID provided, try to call the method on the collection\n const collectionMethod = (\n collection as unknown as Record<string, unknown>\n )[methodName];\n if (typeof collectionMethod === 'function') {\n // `.call(collection, …)` preserves the receiver binding of the\n // original member call (`collection[action](…)`).\n const result = await (collectionMethod as InstanceCallable).call(\n collection,\n ...methodArgs,\n );\n const failure = normalizeCustomActionFailure(result);\n if (failure) throw new CustomActionFailureError(failure);\n return result;\n } else {\n throw new Error(\n `Method '${methodName}' not found on collection. For object-specific actions, provide an 'id' parameter.`,\n );\n }\n }\n } catch (error) {\n if (error instanceof CustomActionFailureError) throw error;\n throw new Error(\n `Failed to execute custom action '${action}': ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }\n\n /**\n * Generate MCP server info\n */\n getServerInfo() {\n return {\n name: this.config.server?.name,\n version: this.config.server?.version,\n description: this.config.description,\n };\n }\n\n /**\n * Generate complete MCP server with stdio transport\n *\n * Creates a runnable Node.js script that exposes SMRT objects as MCP tools.\n * The generated server includes:\n * - Stdio transport integration\n * - Tool registration from ObjectRegistry\n * - Error handling and logging\n * - Graceful shutdown\n *\n * @param options - Server generation options\n * @returns Promise that resolves when all files are written\n *\n * @example\n * ```typescript\n * const generator = new MCPGenerator({\n * name: 'my-app',\n * version: '1.0.0'\n * });\n *\n * await generator.generateServer({\n * outputPath: '.smrt/mcp-server/index.js',\n * serverName: 'my-app-mcp',\n * debug: true\n * });\n * ```\n */\n async generateServer(\n options: {\n /** Path to output server file (relative or absolute) */\n outputPath?: string;\n\n /** Server name for configuration */\n serverName?: string;\n\n /** Server version */\n serverVersion?: string;\n\n /** Enable debug logging */\n debug?: boolean;\n\n /** Generate Claude Desktop configuration example */\n generateClaudeConfigFile?: boolean;\n\n /** Generate README documentation */\n generateReadme?: boolean;\n\n /** Generate modular directory structure (tools/, handlers/, config.ts) */\n modular?: boolean;\n } = {},\n ): Promise<void> {\n const {\n outputPath = '.smrt/mcp-server/index.js',\n serverName = this.config.name || 'smrt-mcp-server',\n serverVersion = this.config.version || '1.0.0',\n debug = false,\n generateClaudeConfigFile = false,\n generateReadme = false,\n modular = false,\n } = options;\n\n // Resolve output path\n const resolvedPath = resolve(process.cwd(), outputPath);\n const outputDir = dirname(resolvedPath);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n if (modular) {\n // Generate modular structure: tools/, handlers/, config.ts, index.js\n await this.generateModularServer(\n outputDir,\n serverName,\n serverVersion,\n debug,\n );\n } else {\n // Generate single-file server with static tools\n const tools = await this.generateTools();\n const tenantScopedObjects = await this.tenantScopedObjectNames(tools);\n const hasTenantScopedTools =\n tenantScopedObjects.length > 0 ||\n (await this.hasTenantScopedTools(tools));\n\n const runtimeOptions: RuntimeOptions = {\n name: serverName,\n version: serverVersion,\n description: this.config.description,\n config: this.config,\n context: this.context,\n debug,\n tools,\n customActions: await this.runtimeCustomActions(tools),\n tenantScopedObjects,\n stiTargets: this.runtimeStiTargets(tools),\n toolListCacheHint: resolveMCPToolListCacheHint(\n this.config.cache?.toolsList,\n hasTenantScopedTools,\n ),\n };\n\n const serverCode = generateRuntimeBootstrap(runtimeOptions);\n\n // Write server file\n await writeFile(resolvedPath, serverCode, 'utf-8');\n console.log(`✅ Generated MCP server: ${resolvedPath}`);\n }\n\n // Generate Claude Desktop configuration example\n if (generateClaudeConfigFile) {\n const claudeConfig = generateClaudeConfig(serverName, resolvedPath);\n const claudeConfigPath = resolve(outputDir, 'claude-config.example.json');\n await writeFile(\n claudeConfigPath,\n JSON.stringify(claudeConfig, null, 2),\n 'utf-8',\n );\n console.log(`✅ Generated Claude config example: ${claudeConfigPath}`);\n }\n\n // Generate README documentation\n if (generateReadme) {\n const readme = generateMCPDocumentation(serverName, outputPath);\n const readmePath = resolve(outputDir, 'MCP-README.md');\n await writeFile(readmePath, readme, 'utf-8');\n console.log(`✅ Generated MCP documentation: ${readmePath}`);\n }\n\n // Generate npm script suggestion\n const mcpScript = generateMCPScript(outputPath);\n console.log(`\\n📝 Add this to your package.json scripts:`);\n console.log(` \"mcp\": \"${mcpScript}\"\\n`);\n }\n\n private async runtimeCustomActions(\n tools: MCPTool[],\n ): Promise<NonNullable<RuntimeOptions['customActions']>> {\n const metadata: NonNullable<RuntimeOptions['customActions']> = {};\n const crudActions = new Set(['list', 'get', 'create', 'update', 'delete']);\n const classes = ObjectRegistry.getAllClasses();\n\n for (const tool of tools) {\n const separator = tool.name.indexOf('_');\n if (separator === -1) continue;\n const objectPrefix = tool.name.slice(0, separator);\n const action = tool.name.slice(separator + 1);\n if (crudActions.has(action)) continue;\n const matched = Array.from(classes.entries()).find(\n ([key, info]) => (info.name || key).toLowerCase() === objectPrefix,\n );\n if (!matched) continue;\n const [key, classInfo] = matched;\n const objectName = classInfo.name || key;\n const [methodName, method] = resolveCustomActionMethod(\n await ObjectRegistry.getAllMethods(objectName),\n action,\n );\n const resolved = this.resolveCustomActionMetadata(\n objectName,\n methodName,\n method,\n this.hasCollectionReceiver(classInfo),\n );\n metadata[tool.name] = {\n scope: resolved.scope,\n isStatic: resolved.isStatic,\n methodName,\n ...(resolved.parameters\n ? {\n parameterNames: resolved.parameters.map(\n (parameter) => parameter.name,\n ),\n optionsParameter:\n resolved.parameters.length === 1 &&\n resolved.parameters[0]?.name === 'options',\n }\n : {}),\n legacyOptions: !resolved.parameters,\n };\n }\n return metadata;\n }\n\n /**\n * Emit only the STI discriminator targets advertised by create-tool schemas.\n * Generated processes start with an empty registry, so resolving the\n * qualified target through `getCollection()` both validates the declaration\n * and lets the public registry loader register the selected subtype.\n */\n private runtimeStiTargets(\n tools: MCPTool[],\n ): Record<string, Record<string, string>> {\n const targets: Record<string, Record<string, string>> = {};\n const classes = ObjectRegistry.getAllClasses();\n\n for (const tool of tools) {\n const separator = tool.name.indexOf('_');\n if (separator === -1 || tool.name.slice(separator + 1) !== 'create') {\n continue;\n }\n const objectPrefix = tool.name.slice(0, separator);\n const matched = Array.from(classes.entries()).find(\n ([key, info]) => (info.name || key).toLowerCase() === objectPrefix,\n );\n if (!matched) continue;\n\n const [key, classInfo] = matched;\n const variants = this.getStiVariants(classInfo.name || key);\n if (variants.length === 0) continue;\n\n targets[objectPrefix] = Object.fromEntries(\n variants.map((variant) => [\n variant.discriminator,\n variant.discriminator,\n ]),\n );\n }\n\n return targets;\n }\n\n /**\n * Generate modular MCP server structure\n *\n * Creates separate files for tools, handlers, configuration, and main entry point.\n * This makes the generated server easier to customize and extend.\n *\n * @param outputDir - Directory to generate files in\n * @param serverName - Server name\n * @param serverVersion - Server version\n * @param debug - Enable debug logging\n */\n private async generateModularServer(\n outputDir: string,\n serverName: string,\n serverVersion: string,\n debug: boolean,\n ): Promise<void> {\n // Create subdirectories\n const toolsDir = resolve(outputDir, 'tools');\n const handlersDir = resolve(outputDir, 'handlers');\n\n await mkdir(toolsDir, { recursive: true });\n await mkdir(handlersDir, { recursive: true });\n\n // Generate config.ts\n const configPath = resolve(outputDir, 'config.ts');\n const configCode = this.generateConfigFile(\n serverName,\n serverVersion,\n debug,\n );\n await writeFile(configPath, configCode, 'utf-8');\n console.log(`✅ Generated config: ${configPath}`);\n\n const generatedTools = await this.generateTools();\n\n // Generate tools/index.ts with tool definitions\n const toolsPath = resolve(toolsDir, 'index.ts');\n const toolsCode = this.generateToolsFile(generatedTools);\n await writeFile(toolsPath, toolsCode, 'utf-8');\n console.log(`✅ Generated tools: ${toolsPath}`);\n\n // Generate handlers/index.ts with tool call handlers\n const handlersPath = resolve(handlersDir, 'index.ts');\n const tenantScopedObjects =\n await this.tenantScopedObjectNames(generatedTools);\n const hasTenantScopedTools =\n tenantScopedObjects.length > 0 ||\n (await this.hasTenantScopedTools(generatedTools));\n const handlersCode = await this.generateHandlersFile(tenantScopedObjects);\n await writeFile(handlersPath, handlersCode, 'utf-8');\n console.log(`✅ Generated handlers: ${handlersPath}`);\n\n // Generate main index.js entry point\n const indexPath = resolve(outputDir, 'index.js');\n const indexCode = this.generateModularIndex(\n resolveMCPToolListCacheHint(\n this.config.cache?.toolsList,\n hasTenantScopedTools,\n ),\n );\n await writeFile(indexPath, indexCode, 'utf-8');\n console.log(`✅ Generated MCP server: ${indexPath}`);\n }\n\n /**\n * Generate configuration file for modular server\n */\n private generateConfigFile(\n serverName: string,\n serverVersion: string,\n debug: boolean,\n ): string {\n return `/**\n * MCP Server Configuration\n * Auto-generated by @happyvertical/smrt-core\n */\n\nexport const SERVER_NAME = ${JSON.stringify(serverName)};\nexport const SERVER_VERSION = ${JSON.stringify(serverVersion)};\nexport const SERVER_DESCRIPTION = ${JSON.stringify(this.config.description)};\nexport const DEBUG = ${debug};\n`;\n }\n\n /**\n * Generate tools definitions file for modular server\n */\n private generateToolsFile(tools: MCPTool[]): string {\n return `/**\n * MCP Tools Definitions\n * Auto-generated from SMRT objects\n */\n\nexport const tools: Array<{\n name: string;\n description: string;\n inputSchema: any;\n outputSchema: any;\n}> = ${JSON.stringify(tools, null, 2)};\n`;\n }\n\n /**\n * Generate switch cases for tool execution\n */\n private async generateToolSwitchCases(\n indent: string = ' ',\n generatedTools?: MCPTool[],\n ): Promise<string> {\n const tools = generatedTools ?? (await this.generateTools());\n\n const capitalize = (str: string) =>\n str.charAt(0).toUpperCase() + str.slice(1);\n\n const switchCases = (\n await Promise.all(\n tools.map(async (tool) => {\n const separator = tool.name.indexOf('_');\n const objectName = tool.name.slice(0, separator);\n const action = tool.name.slice(separator + 1);\n\n switch (action) {\n case 'list':\n return `${indent}case '${tool.name}': {\n${indent} const limit = args.limit ?? 50;\n${indent} const offset = args.offset ?? 0;\n${indent} const where = args.where ?? {};\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const items = await collection.list({ where, limit, offset });\n${indent} const itemsPublic = items.map((item) => item.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent} const structuredContent = {\n${indent} data: itemsPublic,\n${indent} meta: { total: await collection.count({ where }), limit, offset, count: items.length },\n${indent} };\n${indent} return successResult(structuredContent, JSON.stringify(itemsPublic));\n${indent}}`;\n\n case 'get':\n return `${indent}case '${tool.name}': {\n${indent} if (!args.id && !args.slug) {\n${indent} throw new Error('Either id or slug is required');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const filter = args.id || args.slug;\n${indent} const item = await collection.get(filter);\n\n${indent} if (!item) {\n${indent} throw new Error('Object not found');\n${indent} }\n\n${indent} return successResult(item.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent}}`;\n\n case 'create':\n return `${indent}case '${tool.name}': {\n${indent} const { collection, objectName: targetObjectName } = await resolveCreateTarget('${objectName}', args, aiConfig);\n\n${indent} const newItem = await collection.create(applyWritablePolicy(targetObjectName, args));\n${indent} await newItem.save();\n\n${indent} return successResult(newItem.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent}}`;\n\n case 'update':\n return `${indent}case '${tool.name}': {\n${indent} const { id, ...updateData } = args;\n${indent} if (!id) {\n${indent} throw new Error('ID is required for update');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const existing = await collection.get(id);\n${indent} if (!existing) {\n${indent} throw new Error('Object not found');\n${indent} }\n\n${indent} Object.assign(existing, applyWritablePolicy('${capitalize(objectName)}', updateData));\n${indent} await existing.save();\n\n${indent} return successResult(existing.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent}}`;\n\n case 'delete':\n return `${indent}case '${tool.name}': {\n${indent} if (!args.id) {\n${indent} throw new Error('ID is required for delete');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const toDelete = await collection.get(args.id);\n${indent} if (!toDelete) {\n${indent} throw new Error('Object not found');\n${indent} }\n\n${indent} await toDelete.delete();\n\n${indent} return successResult({ success: true, message: 'Object deleted successfully' });\n${indent}}`;\n\n default: {\n // Custom actions use the same canonical receiver/argument contract\n // as the in-process and standalone MCP runtimes. In particular,\n // a route config cannot turn an instance method into a static one.\n const matched = Array.from(\n ObjectRegistry.getAllClasses().entries(),\n ).find(\n ([key, info]) =>\n (info.name || key).toLowerCase() === objectName.toLowerCase(),\n );\n if (!matched) {\n throw new Error(\n `Unable to resolve custom-action target for tool '${tool.name}'`,\n );\n }\n const [classKey, classInfo] = matched;\n const registeredName = classInfo.name || classKey;\n const [methodName, method] = resolveCustomActionMethod(\n await ObjectRegistry.getAllMethods(registeredName),\n action,\n );\n const metadata = this.resolveCustomActionMetadata(\n registeredName,\n methodName,\n method,\n this.hasCollectionReceiver(classInfo),\n );\n const methodArgs = !metadata.parameters\n ? 'Object.keys(options ?? {}).length > 0 ? options : directArgs'\n : metadata.parameters.length === 1 &&\n metadata.parameters[0]?.name === 'options'\n ? 'options'\n : `[${metadata.parameters\n .map(\n (parameter) =>\n `args[${JSON.stringify(\n customActionParameterInputName(\n metadata,\n parameter.name,\n ),\n )}]`,\n )\n .join(', ')}]`;\n return `${indent}case '${tool.name}': {\n${indent} const { id, options, ...directArgs } = args;\n\n${indent} if (${JSON.stringify(metadata.scope)} === 'item' && !id) {\n${indent} throw new Error('ID is required for custom action ${action}');\n${indent} }\n${indent} if (${JSON.stringify(metadata.scope)} === 'collection' && id) {\n${indent} throw new Error('Custom action ${action} is collection-scoped and does not accept an ID');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection(${JSON.stringify(registeredName)}, {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const target = ${JSON.stringify(metadata.scope)} === 'item'\n${indent} ? await collection.get(id)\n${indent} : ${metadata.isStatic}\n${indent} ? ObjectRegistry.getClass(${JSON.stringify(registeredName)})?.constructor\n${indent} : collection;\n${indent} if (!target) {\n${indent} throw new Error(${JSON.stringify(\n metadata.scope === 'item'\n ? 'Object not found'\n : 'Custom action target not found',\n )});\n${indent} }\n\n${indent} const actionMethod = target[${JSON.stringify(methodName)}];\n${indent} if (typeof actionMethod !== 'function') {\n${indent} throw new Error('Method ${methodName} not found on custom action target');\n${indent} }\n\n${indent} const methodArgs = ${methodArgs.startsWith('[') ? methodArgs : `[${methodArgs}]`};\n${indent} const result = await actionMethod.call(target, ...methodArgs);\n${indent} const failure = normalizeCustomActionFailure(result);\n${indent} if (failure) {\n${indent} return errorResult(\n${indent} { error: failure },\n${indent} JSON.stringify({ error: failure }),\n${indent} { [SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY]: failure },\n${indent} );\n${indent} }\n\n${indent} const publicResult = toPublicResult(result);\n${indent} return successResult({ data: publicResult }, JSON.stringify(publicResult));\n${indent}}`;\n }\n }\n }),\n )\n ).join('\\n\\n');\n\n return switchCases;\n }\n\n /**\n * Generate handlers file for modular server\n */\n private async generateHandlersFile(\n tenantScopedObjects: string[] = [],\n ): Promise<string> {\n const tools = await this.generateTools();\n const switchCases = await this.generateToolSwitchCases(' ', tools);\n const stiTargets = this.runtimeStiTargets(tools);\n const tenantScopedSet = Array.from(\n new Set(tenantScopedObjects.map((n) => n.toLowerCase())),\n );\n const hasTenantScoped = tenantScopedSet.length > 0;\n\n return `/**\n * MCP Tool Call Handlers\n * Auto-generated from SMRT objects\n *\n * SECURITY (#1540): responses exclude @field({ sensitive }) fields and\n * create/update bodies are mass-assignment guarded. This handler has no\n * per-call authentication principal — the generated stdio MCP server's trust\n * boundary is the host process / MCP client. Run it only in a trusted context\n * or behind an authenticated gateway.\n *\n * SECURITY (#1554): tenant-scoped tools run inside a fail-closed tenant gate;\n * the tenant is taken from SMRT_MCP_TENANT_ID (this server has no auth\n * principal) and tenancy is enabled so the interceptor enforces filtering.\n */\n\nimport { ObjectRegistry, normalizeCustomActionFailure, SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY } from '@happyvertical/smrt-core';\n${hasTenantScoped ? \"import { enableTenancy, runTenantScopedEntryPoint } from '@happyvertical/smrt-tenancy';\\n\" : ''}${\n hasTenantScoped\n ? `\n// Install the tenancy interceptor so tenant-scoped tools are filtered and the\n// gate fail-closes when no tenant is supplied (#1554).\nenableTenancy();\nconst TENANT_SCOPED = new Set(${JSON.stringify(tenantScopedSet)});\nconst MCP_TENANT_ID = process.env.SMRT_MCP_TENANT_ID || undefined;\nconst MCP_ALLOW_CROSS_TENANT = process.env.SMRT_MCP_ALLOW_CROSS_TENANT === 'true';\n`\n : ''\n}\nconst PUBLIC_JSON_OPTIONS = {\n permissions: (process.env.SMRT_MCP_PERMISSIONS || '')\n .split(',')\n .map((permission) => permission.trim())\n .filter(Boolean),\n};\nconst STI_TARGETS: Record<string, Record<string, string>> = ${JSON.stringify(stiTargets)};\n\n/**\n * Mass-assignment guard (#1540): strip framework/server-managed and\n * \\`@field({ readonly: true })\\` fields from create/update bodies, intersecting\n * with the optional \\`@smrt({ api: { writable: [...] } })\\` allowlist.\n */\nfunction applyWritablePolicy(objectName: string, data: any): Record<string, any> {\n if (!data || typeof data !== 'object') return {};\n const serverManaged = new Set<string>([\n 'id', 'tenantId', 'tenant_id',\n 'createdAt', 'created_at', 'updatedAt', 'updated_at',\n ]);\n const readonly = new Set<string>();\n let writable: string[] | null = null;\n const apiConfig = ObjectRegistry.getConfig(objectName)?.api as any;\n if (apiConfig && typeof apiConfig === 'object' && Array.isArray(apiConfig.writable)) {\n writable = apiConfig.writable;\n }\n for (const [name, def] of ObjectRegistry.getFields(objectName)) {\n if (def && ((def as any).readonly === true || (def as any)._meta?.readonly === true)) {\n readonly.add(name);\n }\n }\n const result: Record<string, any> = {};\n for (const [key, value] of Object.entries(data as Record<string, any>)) {\n if (key.startsWith('_')) continue;\n if (serverManaged.has(key)) continue;\n if (readonly.has(key)) continue;\n if (writable && !writable.includes(key)) continue;\n result[key] = value;\n }\n return result;\n}\n\n/** Resolve an advertised STI discriminator to its registered subtype collection. */\nasync function resolveCreateTarget(baseObjectName: string, args: Record<string, any>, aiConfig: any) {\n let objectName = baseObjectName;\n const discriminator = args._meta_type;\n const targets = STI_TARGETS[baseObjectName];\n if (typeof discriminator === 'string' && targets) {\n const target = targets[discriminator];\n if (!target) throw new Error('Unknown STI discriminator: ' + discriminator);\n objectName = target;\n }\n const collection = await ObjectRegistry.getCollection(objectName, {\n persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n ai: aiConfig,\n });\n return { collection, objectName };\n}\n\n/**\n * Sensitive-field-safe serialization for custom-action results (#1540).\n * Recurses through arrays and plain objects so nested SmrtObjects are stripped\n * too; non-plain instances (Date, etc.) and primitives pass through. Cycle-safe.\n */\nfunction toPublicResult(value: any, seen: WeakSet<object> = new WeakSet()): any {\n if (value === null || typeof value !== 'object') return value;\n if (typeof value.toPublicJSON === 'function') return value.toPublicJSON(PUBLIC_JSON_OPTIONS);\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((entry: any) => toPublicResult(entry, seen));\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n if (seen.has(value)) return value;\n seen.add(value);\n const out: Record<string, any> = {};\n for (const [key, entry] of Object.entries(value as Record<string, any>)) {\n out[key] = toPublicResult(entry, seen);\n }\n return out;\n}\n\nfunction successResult(structuredContent: any, text = JSON.stringify(structuredContent)) {\n return {\n content: [{ type: 'text', text }],\n structuredContent,\n };\n}\n\nfunction errorResult(structuredContent: any, text: string, _meta?: Record<string, any>) {\n return {\n content: [{ type: 'text', text }],\n isError: true,\n structuredContent,\n ...(_meta ? { _meta } : {}),\n };\n}\n\n/**\n * Handle tool call request\n */\nexport async function handleToolCall(\n name: string,\n arguments: any = {},\n aiConfig: any = {}\n) {\n try {\n const args = arguments;\n\n const runToolBody = async () => {\n switch (name) {\n${switchCases}\n\n default:\n throw new Error(\\`Unknown tool: \\${name}\\`);\n }\n };\n${\n hasTenantScoped\n ? `\n // Fail-closed tenant context for tenant-scoped tools (#1554).\n const [toolObject] = name.split('_');\n const result =\n toolObject && TENANT_SCOPED.has(toolObject.toLowerCase())\n ? await runTenantScopedEntryPoint(\n { tenantScoped: true, tenantId: MCP_TENANT_ID, allowCrossTenant: MCP_ALLOW_CROSS_TENANT, surface: 'MCP' },\n runToolBody,\n )\n : await runToolBody();`\n : `\n const result = await runToolBody();`\n}\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n\n return errorResult(\n { error: { message: errorMessage } },\n \\`Error executing tool \\${name}: \\${errorMessage}\\`,\n );\n }\n}\n`;\n }\n\n /**\n * Generate modular index file (main entry point)\n */\n private generateModularIndex(\n toolListCacheHint: MCPToolListCacheHint,\n ): string {\n return `#!/usr/bin/env node\n/**\n * Auto-generated MCP Server\n * Generated by @happyvertical/smrt-core MCPGenerator\n *\n * This server exposes SMRT objects as MCP tools for AI integration.\n */\n\nimport { Server } from '@modelcontextprotocol/server';\nimport { serveStdio } from '@modelcontextprotocol/server/stdio';\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\nimport { loadConfig } from '@happyvertical/smrt-config';\nimport { getDatabase } from '@happyvertical/sql';\nimport { getAI } from '@happyvertical/ai';\n\nimport { SERVER_NAME, SERVER_VERSION, DEBUG } from './config.js';\nimport { tools } from './tools/index.js';\nimport { handleToolCall } from './handlers/index.js';\n\nconst TOOL_LIST_CACHE_HINT = ${JSON.stringify(toolListCacheHint)};\n\n/**\n * Main server startup function\n */\nexport async function createServer() {\n if (DEBUG) {\n console.error(\\`[MCP] Starting server: \\${SERVER_NAME} v\\${SERVER_VERSION}\\`);\n console.error(\\`[MCP] Available tools:\\`, tools.map(t => t.name).join(', '));\n }\n\n // Register the application package manifest before resolving generated\n // object names. Generated servers are commonly run from the application\n // package itself, which is not a node_modules dependency of its process.\n const localManifestPaths = [\n resolve(process.cwd(), 'dist', 'manifest.json'),\n resolve(process.cwd(), '.smrt', 'manifest.json'),\n ].filter(existsSync);\n if (localManifestPaths.length > 0) {\n ObjectRegistry.loadAllManifests({ manifestPaths: localManifestPaths });\n }\n\n // Load configuration from environment and .smrt.config files\n const appConfig = await loadConfig();\n const aiConfig = appConfig?.ai || {};\n\n // Create MCP server\n const server = new Server(\n {\n name: SERVER_NAME,\n version: SERVER_VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n cacheHints: {\n 'tools/list': TOOL_LIST_CACHE_HINT,\n },\n }\n );\n\n // Register ListTools handler\n server.setRequestHandler('tools/list', async () => {\n if (DEBUG) {\n console.error(\\`[MCP] ListTools request received\\`);\n }\n\n return {\n tools: [...tools].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0).map(tool => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n })),\n };\n });\n\n // Register CallTool handler\n server.setRequestHandler('tools/call', async (request) => {\n const { name, arguments: args = {} } = request.params;\n\n if (DEBUG) {\n console.error(\\`[MCP] CallTool request: \\${name}\\`);\n console.error(\\`[MCP] Arguments:\\`, JSON.stringify(args, null, 2));\n }\n\n return await handleToolCall(name, args, aiConfig);\n });\n\n return server;\n}\n\nasync function main() {\n try {\n const handle = serveStdio(() => createServer(), {\n onerror: (error) => console.error('[MCP] Protocol error:', error),\n });\n const shutdown = async () => {\n if (DEBUG) console.error('[MCP] Shutting down gracefully');\n await handle.close();\n process.exit(0);\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n } catch (error) {\n console.error('[MCP] Fatal error during server startup:', error);\n process.exit(1);\n }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().catch((error) => {\n console.error('[MCP] Unhandled error:', error);\n process.exit(1);\n });\n}\n`;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"mcp.js","names":[],"sources":["../../src/generators/mcp.ts"],"sourcesContent":["/**\n * MCP (Model Context Protocol) server generator for smrt objects\n *\n * Exposes smrt objects as AI tools for Claude, GPT, and other AI models\n */\n\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, resolve } from 'node:path';\nimport { SmrtCollection } from '../collection';\nimport type { PublicJsonOptions, SmrtObject } from '../object';\nimport { ObjectRegistry } from '../registry';\nimport type { RegisteredClass } from '../registry/types.js';\nimport type { FieldDefinition, MethodDefinition } from '../scanner/types.js';\nimport {\n buildCustomActionInvocationArgs,\n type CustomActionFailure,\n type CustomActionMetadata,\n customActionParameterInputName,\n normalizeCustomActionFailure,\n resolveCustomActionMetadata,\n SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY,\n} from './custom-action.js';\nimport {\n type GeneratedSourceExtension,\n type GeneratedSourceLanguage,\n generatedSiblingExtension,\n renderGeneratedSource,\n resolveGeneratedSourceLanguage,\n} from './mcp-emit.js';\nimport {\n generateClaudeConfig,\n generateMCPDocumentation,\n generateMCPScript,\n generateRuntimeBootstrap,\n type RuntimeOptions,\n} from './mcp-runtime-template.js';\nimport { runWithTenantGate } from './tenant-gate.js';\nimport {\n buildToolInputSchema,\n fieldTypeToJsonSchema,\n finalizeMcpJsonSchema,\n type ToolFieldMeta,\n type ToolJsonSchema,\n} from './tool-schema.js';\n\n/**\n * Write one generated module, rendering it for the requested output language.\n *\n * Every generator in this file produces TypeScript source; a JavaScript target\n * is transpiled on the way out so the written file is runnable as-is (#2279).\n *\n * @param targetPath - Absolute path of the file to write\n * @param source - Generated TypeScript source\n * @param language - Language the file must be written in\n */\nasync function writeGeneratedFile(\n targetPath: string,\n source: string,\n language: GeneratedSourceLanguage,\n): Promise<void> {\n const rendered = await renderGeneratedSource(source, language, targetPath);\n await writeFile(targetPath, rendered, 'utf-8');\n}\n\n/**\n * Runtime tool-call arguments. They arrive as untyped JSON from the MCP client,\n * so individual keys are narrowed (`as`) at each action's boundary.\n */\ntype ToolArgs = Record<string, unknown>;\n\n/**\n * A method resolved dynamically (by action name) from an object/collection\n * instance and invoked with the parsed tool-call arguments. Narrowed to this\n * type at the call boundary after a `typeof === 'function'` guard.\n */\ntype InstanceCallable = (...args: unknown[]) => unknown;\n\nexport interface MCPConfig {\n name?: string;\n version?: string;\n description?: string;\n /**\n * Cache policy for generated MCP protocol results.\n *\n * Generated catalog results are private by default. A public tool catalog\n * needs both an explicit public scope and an explicit assertion that the\n * entire catalog is global and unauthenticated; tenant-scoped catalogs are\n * always forced back to private.\n */\n cache?: {\n toolsList?: MCPToolListCacheOptions;\n };\n server?: {\n name: string;\n version: string;\n };\n}\n\nexport const MCP_STABLE_CATALOG_TTL_MS = 86_400_000;\n\nexport interface MCPToolListCacheOptions {\n /** Cache lifetime in milliseconds. Defaults to one day for a deploy-static catalog. */\n ttlMs?: number;\n /** Requested cache visibility. Defaults to private. */\n cacheScope?: 'private' | 'public';\n /**\n * Explicitly attest that every listed tool is global and unauthenticated.\n * This must accompany `cacheScope: 'public'`; tenant-scoped tool sets cannot\n * opt in regardless of this assertion.\n */\n publicCatalog?: true;\n}\n\nexport interface MCPToolListCacheHint {\n ttlMs: number;\n cacheScope: 'private' | 'public';\n}\n\n/**\n * Resolve the generated tools/list cache policy at generation time.\n *\n * A shared cache may otherwise serve one tenant's tool catalog to another, so\n * public caching is deliberately double opt-in and unavailable when a\n * generated server exposes any tenant-scoped object.\n */\nexport function resolveMCPToolListCacheHint(\n options: MCPToolListCacheOptions | undefined,\n hasTenantScopedTools: boolean,\n): MCPToolListCacheHint {\n const ttlMs = options?.ttlMs ?? MCP_STABLE_CATALOG_TTL_MS;\n if (!Number.isSafeInteger(ttlMs) || ttlMs < 0) {\n throw new RangeError(\n 'MCP tools/list cache ttlMs must be a non-negative safe integer.',\n );\n }\n if (\n options?.cacheScope !== undefined &&\n options.cacheScope !== 'private' &&\n options.cacheScope !== 'public'\n ) {\n throw new RangeError(\n \"MCP tools/list cacheScope must be 'private' or 'public'.\",\n );\n }\n\n const cacheScope =\n !hasTenantScopedTools &&\n options?.cacheScope === 'public' &&\n options.publicCatalog === true\n ? 'public'\n : 'private';\n\n return { ttlMs, cacheScope };\n}\n\nexport interface MCPContext {\n db?: unknown;\n ai?: unknown;\n user?: {\n id: string;\n roles?: string[];\n };\n /** Resolved permission slugs held by the caller. */\n permissions?: Iterable<string>;\n /**\n * Tenant the calling principal is scoped to (#1554). When set, tenant-scoped\n * tools run inside this tenant's context. Hosts that authenticate a principal\n * (e.g. `@happyvertical/smrt-app-mcp`) should derive it from the principal —\n * the MCP analogue of the SvelteKit auth hook setting `locals.tenantId`.\n */\n tenantId?: string;\n /**\n * Explicit operator opt-in to cross-tenant access for tenant-scoped tools\n * (#1554). Only set for trusted operator/admin callers. Without a `tenantId`\n * or this flag, tenant-scoped tool calls fail closed when tenancy is enabled.\n */\n allowCrossTenant?: boolean;\n /**\n * Optional durable backing store for the MCP Tasks extension. Core owns\n * task eligibility and action argument projection; jobs-backed runtimes own\n * persistence so `@happyvertical/smrt-core` stays independent of jobs.\n */\n taskStore?: MCPTaskStore;\n}\n\n/** Minimal durable task-store contract implemented by `@smrt-jobs`. */\nexport interface MCPTaskStore {\n createTask(input: {\n objectType: string;\n objectId: string;\n method: string;\n invocationArgs: unknown[];\n tenantId?: string | null;\n }): Promise<MCPTask>;\n}\n\n/** Flat MCP Tasks extension projection shared by generated and app transports. */\nexport interface MCPTask {\n taskId: string;\n status: 'working' | 'input_required' | 'completed' | 'cancelled' | 'failed';\n createdAt: string;\n lastUpdatedAt: string;\n ttlMs: number;\n pollIntervalMs?: number;\n statusMessage?: string;\n}\n\nexport interface MCPTool {\n name: string;\n description: string;\n inputSchema: ToolJsonSchema;\n /** Public result schema for tools/call structuredContent. */\n outputSchema: ToolJsonSchema;\n}\n\n/** Return a copied, canonical tool sequence for byte-stable tools/list output. */\nexport function sortMCPTools<T extends Pick<MCPTool, 'name'>>(tools: T[]): T[] {\n return [...tools].sort((left, right) =>\n left.name < right.name ? -1 : left.name > right.name ? 1 : 0,\n );\n}\n\nexport interface MCPRequest {\n method: string;\n params: {\n name: string;\n arguments: ToolArgs;\n };\n}\n\nexport interface MCPResponse {\n content: Array<{\n type: 'text';\n text: string;\n }>;\n isError?: boolean;\n _meta?: Record<string, unknown>;\n /** Machine-readable projection matching the tool's declared outputSchema. */\n structuredContent?: unknown;\n /** Set only for a Tasks extension CreateTaskResult. */\n resultType?: 'task' | 'complete';\n taskId?: string;\n status?: MCPTask['status'];\n createdAt?: string;\n lastUpdatedAt?: string;\n ttlMs?: number;\n pollIntervalMs?: number;\n statusMessage?: string;\n}\n\nclass CustomActionFailureError extends Error {\n constructor(readonly failure: CustomActionFailure) {\n super(failure.message);\n this.name = 'CustomActionFailureError';\n }\n}\n\n/**\n * MCP tool identifiers are lowercase for stable protocol vocabulary, while\n * JavaScript method names retain their declared casing. Resolve a tool suffix\n * back to the registry's canonical method name before inspecting metadata or\n * invoking it.\n */\nfunction resolveCustomActionMethod(\n methods: Map<string, MethodDefinition>,\n toolAction: string,\n): [methodName: string, method: MethodDefinition | undefined] {\n const direct = methods.get(toolAction);\n if (direct) return [toolAction, direct];\n for (const [methodName, method] of methods) {\n if (methodName.toLowerCase() === toolAction.toLowerCase()) {\n return [methodName, method];\n }\n }\n return [toolAction, undefined];\n}\n\n/** Preserve a declared method's case when a runtime-only class has no manifest. */\nfunction resolveRuntimeMethodName(\n classConstructor: unknown,\n action: string,\n): string {\n let prototype: object | null | undefined = (\n classConstructor as { prototype?: object } | undefined\n )?.prototype;\n while (prototype && prototype !== Object.prototype) {\n const match = Object.getOwnPropertyNames(prototype).find(\n (name) => name.toLowerCase() === action.toLowerCase(),\n );\n if (match) return match;\n prototype = Object.getPrototypeOf(prototype) as object | null;\n }\n return action;\n}\n\n/**\n * Background task methods receive `JobExecutionContext` from TaskRunner, not\n * from untrusted MCP arguments. Keep that conventional trailing parameter out\n * of the persisted positional call so the runner can append its live context.\n */\nfunction buildTaskActionInvocationArgs(\n metadata: CustomActionMetadata,\n args: ToolArgs,\n): unknown[] {\n const parameters = metadata.parameters;\n if (parameters?.at(-1)?.name === 'context') {\n return buildCustomActionInvocationArgs(\n { ...metadata, parameters: parameters.slice(0, -1) },\n args,\n );\n }\n return buildCustomActionInvocationArgs(metadata, args);\n}\n\n/**\n * Generate MCP server from smrt objects\n */\nexport class MCPGenerator {\n private config: MCPConfig;\n private context: MCPContext;\n private collections = new Map<string, SmrtCollection<SmrtObject>>();\n\n constructor(config: MCPConfig = {}, context: MCPContext = {}) {\n this.config = {\n name: 'smrt-mcp-server',\n version: '1.0.0',\n description: 'Auto-generated MCP server from smrt objects',\n server: {\n name: 'smrt-mcp',\n version: '1.0.0',\n },\n ...config,\n };\n this.context = context;\n }\n\n /**\n * Get server name\n */\n get name(): string | undefined {\n return this.config.name;\n }\n\n /**\n * Get server version\n */\n get version(): string | undefined {\n return this.config.version;\n }\n\n /**\n * Generate all available tools from registered objects\n */\n async generateTools(): Promise<MCPTool[]> {\n const tools: MCPTool[] = [];\n const registeredClasses = ObjectRegistry.getAllClasses();\n\n for (const [key, classInfo] of registeredClasses) {\n // Issue #951: Use simple name for tool naming, map key for registry lookups\n const simpleName = classInfo.name || key;\n const config = ObjectRegistry.getConfig(simpleName);\n const mcpConfig = config.mcp;\n\n // `mcp: false` disables MCP generation entirely for the class. Without\n // this gate an `include` list still leaked custom-method tools (the\n // custom-method branch historically only honored `include` when it\n // listed custom methods), so `false` is the only fully fail-closed\n // switch. Mirrors rest.ts's `apiConfig === false` short-circuit\n // (#1540 / #1546).\n if (mcpConfig === false) {\n continue;\n }\n\n // Handle boolean vs object config\n const excluded: string[] =\n typeof mcpConfig === 'object' && mcpConfig?.exclude\n ? mcpConfig.exclude\n : [];\n const included: string[] | undefined =\n typeof mcpConfig === 'object' ? mcpConfig?.include : undefined;\n\n const shouldInclude = (endpoint: string) => {\n if (included && !included.includes(endpoint)) return false;\n if (excluded.includes(endpoint)) return false;\n return true;\n };\n\n const objectTools = await this.generateObjectTools(\n simpleName,\n shouldInclude,\n );\n tools.push(...objectTools);\n }\n\n return sortMCPTools(tools);\n }\n\n /**\n * Generate tools for a specific object\n */\n private async generateObjectTools(\n objectName: string,\n shouldInclude: (endpoint: string) => boolean,\n ): Promise<MCPTool[]> {\n const tools: MCPTool[] = [];\n const fields = ObjectRegistry.getFields(objectName);\n const lowerName = objectName.toLowerCase();\n const classInfo = ObjectRegistry.getClass(objectName);\n\n // LIST tool\n if (shouldInclude('list')) {\n tools.push({\n name: `${lowerName}_list`,\n description: `List ${objectName} objects with optional filtering`,\n inputSchema: this.buildInputSchema(objectName, 'list', fields),\n outputSchema: this.buildOutputSchema(objectName, 'list', fields),\n });\n }\n\n // GET tool\n if (shouldInclude('get')) {\n tools.push({\n name: `${lowerName}_get`,\n description: `Get a specific ${objectName} by ID or slug`,\n inputSchema: this.buildInputSchema(objectName, 'get', fields),\n outputSchema: this.buildOutputSchema(objectName, 'get', fields),\n });\n }\n\n // CREATE tool\n if (shouldInclude('create')) {\n tools.push({\n name: `${lowerName}_create`,\n description: `Create a new ${objectName}`,\n inputSchema: this.buildInputSchema(objectName, 'create', fields),\n outputSchema: this.buildOutputSchema(objectName, 'create', fields),\n });\n }\n\n // UPDATE tool\n if (shouldInclude('update')) {\n tools.push({\n name: `${lowerName}_update`,\n description: `Update an existing ${objectName}`,\n inputSchema: this.buildInputSchema(objectName, 'update', fields),\n outputSchema: this.buildOutputSchema(objectName, 'update', fields),\n });\n }\n\n // DELETE tool\n if (shouldInclude('delete')) {\n tools.push({\n name: `${lowerName}_delete`,\n description: `Delete a ${objectName} by ID`,\n inputSchema: this.buildInputSchema(objectName, 'delete', fields),\n outputSchema: this.buildOutputSchema(objectName, 'delete', fields),\n });\n }\n\n // CUSTOM METHODS - discover from manifest and show by default\n if (classInfo) {\n const config = ObjectRegistry.getConfig(objectName);\n const mcpConfig = config.mcp;\n const included: string[] | undefined =\n typeof mcpConfig === 'object' ? mcpConfig?.include : undefined;\n const excluded: string[] =\n typeof mcpConfig === 'object' && mcpConfig?.exclude\n ? mcpConfig.exclude\n : [];\n\n // When an `include` list is present it is the COMPLETE allowlist for\n // this surface: a custom (non-CRUD) method is exposed ONLY if its name\n // appears in `include`. Without an include list we keep the historical\n // default of auto-exposing every public method. This closes the leak\n // where `mcp: { include: ['list', 'get'] }` still emitted custom-method\n // tools like `payment_recordpayment` because `include` only gated CRUD\n // verbs (#1540 / #1390).\n const crudOperations = ['list', 'get', 'create', 'update', 'delete'];\n const customMethodsInInclude =\n included?.filter((item) => !crudOperations.includes(item)) || [];\n // An include list (even one naming only CRUD verbs) switches custom\n // methods into strict allowlist mode.\n const hasIncludeList = included !== undefined;\n\n // Try to discover methods from manifest (including inherited methods)\n const methods = await ObjectRegistry.getAllMethods(objectName);\n const methodNames = new Set(Array.from(methods.keys()));\n\n // Strict mode: an include list is present, so only the custom methods it\n // names are generated (may be none, e.g. include: ['list', 'get']).\n if (hasIncludeList) {\n for (const methodName of customMethodsInInclude) {\n // Skip if explicitly excluded\n if (excluded.includes(methodName)) continue;\n\n // Check if method exists (in manifest or on class prototype)\n const existsInManifest = methodNames.has(methodName);\n const existsOnClass = this.validateCustomMethod(\n classInfo.constructor,\n methodName,\n );\n\n if (!existsInManifest && !existsOnClass) {\n // Warn about missing methods\n console.warn(\n `Warning: Custom action '${methodName}' specified in MCP config for ${objectName}, but method ${methodName}() not found on class`,\n );\n continue;\n }\n\n // A non-public method must never be exposed as a tool, even when it\n // is explicitly named in `include`. This keeps strict-include mode\n // consistent with the non-strict path below, which gates on\n // `methodDef.isPublic`. Listing a private method in `include` is a\n // config mistake, not an override of method visibility (#1540).\n //\n // The scanner strips private/protected methods from the manifest, so\n // when a non-public method is named in `include` it is absent from\n // `methods` and is only resolvable via validateCustomMethod() on the\n // runtime prototype (TS access modifiers are erased at runtime). Such\n // a method must NOT be emitted. We still allow methods that are\n // present on the class but legitimately absent from the manifest\n // (e.g. inline/dynamically registered classes), so the guard fires\n // only when there is a public manifest entry to anchor on OR the\n // method exists solely as a stripped (non-public) manifest method.\n const methodDef = methods.get(methodName);\n if (methodDef && !methodDef.isPublic) continue;\n\n tools.push(\n this.buildCustomActionTool(\n objectName,\n lowerName,\n methodName,\n methodDef,\n this.hasCollectionReceiver(classInfo),\n ),\n );\n }\n } else {\n // No custom methods in include = show all discovered methods by default\n for (const [methodName, methodDef] of methods) {\n // Skip if not public (private/protected methods shouldn't be in MCP)\n if (!methodDef.isPublic) continue;\n\n // Always respect exclude list\n if (excluded.includes(methodName)) continue;\n\n tools.push(\n this.buildCustomActionTool(\n objectName,\n lowerName,\n methodName,\n methodDef,\n this.hasCollectionReceiver(classInfo),\n ),\n );\n }\n }\n }\n\n return tools;\n }\n\n private buildCustomActionTool(\n objectName: string,\n lowerName: string,\n methodName: string,\n methodDef?: MethodDefinition,\n collectionReceiver = false,\n ): MCPTool {\n const metadata = this.resolveCustomActionMetadata(\n objectName,\n methodName,\n methodDef,\n collectionReceiver,\n );\n return {\n name: `${lowerName}_${methodName}`.toLowerCase(),\n description: `Execute ${methodName} action on ${objectName}`,\n inputSchema: this.buildInputSchema(\n objectName,\n methodName,\n ObjectRegistry.getFields(objectName),\n metadata,\n ),\n outputSchema: this.buildOutputSchema(\n objectName,\n methodName,\n ObjectRegistry.getFields(objectName),\n ),\n };\n }\n\n private resolveCustomActionMetadata(\n objectName: string,\n action: string,\n method?: MethodDefinition,\n collectionReceiver = false,\n ): CustomActionMetadata {\n return resolveCustomActionMetadata({\n actionName: action,\n method,\n apiConfig: ObjectRegistry.getConfig(objectName).api,\n ...(collectionReceiver ? { defaultScope: 'collection' } : {}),\n });\n }\n\n private hasCollectionReceiver(classInfo?: RegisteredClass): boolean {\n return (\n !!classInfo && classInfo.constructor.prototype instanceof SmrtCollection\n );\n }\n\n /**\n * Validate that a custom method exists on a class\n */\n private validateCustomMethod(\n classConstructor: typeof SmrtObject,\n methodName: string,\n ): boolean {\n try {\n // Check if method exists on the prototype\n const prototype = classConstructor.prototype;\n\n // Check if the method exists and is a function. Dynamic name lookup, so\n // index through a record view of the prototype/constructor.\n if (\n typeof (prototype as unknown as Record<string, unknown>)[methodName] ===\n 'function'\n ) {\n return true;\n }\n\n // Also check static methods\n if (\n typeof (classConstructor as unknown as Record<string, unknown>)[\n methodName\n ] === 'function'\n ) {\n return true;\n }\n\n return false;\n } catch (error) {\n console.warn(\n `Error validating method ${methodName} on class ${classConstructor.name}:`,\n error,\n );\n return false;\n }\n }\n\n /** Normalize registry fields for the transport-neutral schema emitter. */\n private toToolFields(fields: Map<string, FieldDefinition>): ToolFieldMeta[] {\n return Array.from(fields, ([name, field]) => ({\n name,\n type: field.type,\n required: field.required ?? field._meta?.required,\n nullable: field._meta?.nullable === true,\n description:\n typeof field._meta?.description === 'string'\n ? field._meta.description\n : undefined,\n default: field._meta?.default,\n maxLength: field._meta?.maxLength,\n minLength: field._meta?.minLength,\n min: field._meta?.min,\n max: field._meta?.max,\n related: field.related,\n }));\n }\n\n /**\n * Add the optional STI discriminator branches to write schemas. The legacy\n * branch preserves existing base-class creates that let SMRT pick the base\n * type; an explicit `_meta_type` selects a known child collection below.\n */\n private buildInputSchema(\n objectName: string,\n action: string,\n fields: Map<string, FieldDefinition>,\n customAction?: CustomActionMetadata,\n ): ToolJsonSchema {\n const schema = buildToolInputSchema(\n action,\n this.toToolFields(fields),\n customAction,\n ObjectRegistry.getConfig(objectName).idType,\n );\n if (action !== 'create' && action !== 'update') return schema;\n\n const variants = this.getStiVariants(objectName);\n if (variants.length === 0) return schema;\n\n const properties = {\n ...((schema.properties as Record<string, ToolJsonSchema> | undefined) ??\n {}),\n _meta_type: {\n type: 'string',\n description:\n 'Optional STI discriminator. When provided for create, selects the declared subtype.',\n },\n };\n return finalizeMcpJsonSchema({\n ...schema,\n properties,\n oneOf: [\n { not: { required: ['_meta_type'] } },\n ...variants.map(({ name, discriminator }) => {\n const variantFields = ObjectRegistry.getFields(name);\n return {\n properties: {\n ...this.buildFieldSchemaProperties(variantFields),\n _meta_type: { const: discriminator },\n },\n required: [\n '_meta_type',\n ...this.toToolFields(variantFields)\n .filter((field) => field.required)\n .map((field) => field.name),\n ],\n };\n }),\n ],\n });\n }\n\n /**\n * Public output schemas follow the actual `toPublicJSON()` boundary: known\n * non-sensitive fields are described, while `additionalProperties` keeps\n * framework/system fields and application transforms honest.\n */\n private buildOutputSchema(\n objectName: string,\n action: string,\n fields: Map<string, FieldDefinition>,\n ): ToolJsonSchema {\n const errorSchema: ToolJsonSchema = {\n type: 'object',\n properties: {\n error: { type: 'object', additionalProperties: true },\n },\n required: ['error'],\n };\n\n if (!['list', 'get', 'create', 'update', 'delete'].includes(action)) {\n // Custom action results are deliberately domain-defined and can be any\n // JSON value. MCP structuredContent itself must be object-rooted, so the\n // machine-readable projection carries that value in `data`; legacy text\n // keeps the original public result unchanged.\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [\n {\n type: 'object',\n properties: { data: {} },\n required: ['data'],\n },\n { $ref: '#/$defs/error' },\n ],\n $defs: { error: errorSchema },\n });\n }\n\n const itemSchema = this.buildPublicItemSchema(objectName, fields);\n\n if (action === 'list') {\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [\n {\n type: 'object',\n properties: {\n data: {\n type: 'array',\n items: { $ref: '#/$defs/publicItem' },\n },\n meta: {\n type: 'object',\n properties: {\n total: { type: 'integer', minimum: 0 },\n limit: { type: 'integer', minimum: 0 },\n offset: { type: 'integer', minimum: 0 },\n count: { type: 'integer', minimum: 0 },\n },\n required: ['total', 'limit', 'offset', 'count'],\n },\n },\n required: ['data', 'meta'],\n },\n { $ref: '#/$defs/error' },\n ],\n $defs: { publicItem: itemSchema, error: errorSchema },\n });\n }\n\n if (action === 'delete') {\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [\n {\n type: 'object',\n properties: {\n success: { const: true },\n message: { type: 'string' },\n },\n required: ['success', 'message'],\n },\n { $ref: '#/$defs/error' },\n ],\n $defs: { error: errorSchema },\n });\n }\n\n return finalizeMcpJsonSchema({\n type: 'object',\n anyOf: [itemSchema, { $ref: '#/$defs/error' }],\n $defs: { error: errorSchema },\n });\n }\n\n private buildPublicItemSchema(\n objectName: string,\n fields: Map<string, FieldDefinition>,\n ): ToolJsonSchema {\n const properties = this.buildFieldSchemaProperties(fields, true);\n\n const variants = this.getStiVariants(objectName);\n if (variants.length > 0) {\n return {\n oneOf: variants.map(({ name, discriminator }) => ({\n type: 'object',\n properties: {\n ...this.buildFieldSchemaProperties(\n ObjectRegistry.getFields(name),\n true,\n ),\n _meta_type: { const: discriminator },\n },\n required: ['_meta_type'],\n additionalProperties: true,\n })),\n };\n }\n\n return { type: 'object', properties, additionalProperties: true };\n }\n\n private buildFieldSchemaProperties(\n fields: Map<string, FieldDefinition>,\n publicOnly = false,\n ): Record<string, ToolJsonSchema> {\n const properties: Record<string, ToolJsonSchema> = {};\n for (const [name, field] of fields) {\n if (\n publicOnly &&\n (field._meta?.sensitive === true || field._meta?.transient === true)\n ) {\n continue;\n }\n const [toolField] = this.toToolFields(new Map([[name, field]]));\n if (!toolField) continue;\n properties[name] = { ...fieldTypeToJsonSchema(toolField) };\n }\n return properties;\n }\n\n private getStiVariants(\n objectName: string,\n ): Array<{ name: string; discriminator: string }> {\n if (ObjectRegistry.getTableStrategy(objectName) !== 'sti') return [];\n\n const base = ObjectRegistry.getClass(objectName);\n const baseNames = new Set(\n [objectName, base?.name, base?.qualifiedName].filter(\n (name): name is string => typeof name === 'string',\n ),\n );\n const variants = new Map<string, { name: string; discriminator: string }>();\n for (const [key, info] of ObjectRegistry.getAllClasses()) {\n const name = info.name || key;\n const chain = ObjectRegistry.getInheritanceChain(name);\n if (!chain.some((ancestor) => baseNames.has(ancestor))) continue;\n const discriminator = info.qualifiedName || name;\n variants.set(discriminator, { name, discriminator });\n }\n return Array.from(variants.values()).sort((left, right) =>\n left.discriminator.localeCompare(right.discriminator),\n );\n }\n\n /**\n * Handle MCP tool calls\n */\n async handleToolCall(request: MCPRequest): Promise<MCPResponse> {\n const { name, arguments: args } = request.params;\n\n try {\n // Check if tool exists\n const availableTools = await this.generateTools();\n const toolExists = availableTools.some((t) => t.name === name);\n\n if (!toolExists) {\n throw new Error(`Unknown tool: ${name}`);\n }\n\n // Parse tool name: `objectname_action`. Split on the FIRST underscore\n // only — a custom method name can itself contain underscores (e.g.\n // `record_payment` → tool `invoice_record_payment`). A naive\n // `name.split('_')` would take `action` as just `record` and mis-route\n // the call. The emitted stdio servers switch on the full tool name, so\n // splitting greedily here also kept the in-process path divergent (#1378).\n const firstUnderscore = name.indexOf('_');\n const objectName =\n firstUnderscore === -1 ? '' : name.slice(0, firstUnderscore);\n const action =\n firstUnderscore === -1 ? '' : name.slice(firstUnderscore + 1);\n\n if (!objectName || !action) {\n throw new Error(`Invalid tool name format: ${name}`);\n }\n\n // Find the registered class (case-insensitive)\n const registeredClasses = ObjectRegistry.getAllClasses();\n let classInfo = null;\n let actualObjectName = '';\n\n for (const [_key, info] of registeredClasses) {\n // Issue #951: Match by simple name, not the qualified map key\n const simpleName = info.name || _key;\n if (simpleName.toLowerCase() === objectName.toLowerCase()) {\n classInfo = info;\n actualObjectName = simpleName;\n break;\n }\n }\n\n if (!classInfo) {\n throw new Error(`Object type '${objectName}' not found`);\n }\n\n // Get or create collection\n const collection = await this.getCollection(actualObjectName, classInfo);\n\n // Execute the action\n const result = await this.executeAction(\n collection,\n action,\n args,\n actualObjectName,\n );\n const publicResult = this.toJsonValue(result);\n const structuredContent = this.toStructuredContent(action, publicResult);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(publicResult, null, 2),\n },\n ],\n structuredContent,\n };\n } catch (error) {\n if (error instanceof CustomActionFailureError) {\n const structuredContent = { error: error.failure };\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(structuredContent),\n },\n ],\n isError: true,\n structuredContent,\n _meta: {\n [SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY]: error.failure,\n },\n };\n }\n const message = error instanceof Error ? error.message : 'Unknown error';\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${message}`,\n },\n ],\n isError: true,\n structuredContent: { error: { message } },\n };\n }\n }\n\n /** Whether a visible tool has explicitly opted into durable task execution. */\n async supportsTaskTool(name: string): Promise<boolean> {\n return (\n (await this.resolveTaskAction(name, { id: '__mcp_task_probe__' })) !==\n null\n );\n }\n\n /**\n * Create a durable MCP task for an explicitly enabled item custom action.\n * The caller is responsible for checking the client's extension capability\n * before exposing this result on the wire.\n */\n async createTask(request: MCPRequest): Promise<MCPResponse> {\n if (!this.context.taskStore) {\n throw new Error(\n 'MCP Tasks is enabled but no durable task store is configured',\n );\n }\n const resolved = await this.resolveTaskAction(\n request.params.name,\n request.params.arguments,\n );\n if (!resolved) {\n throw new Error(\n `MCP task execution is not enabled for tool: ${request.params.name}`,\n );\n }\n const task = await this.context.taskStore.createTask({\n objectType: resolved.objectType,\n objectId: resolved.objectId,\n method: resolved.methodName,\n invocationArgs: resolved.invocationArgs,\n tenantId: this.context.tenantId ?? null,\n });\n return {\n content: [],\n structuredContent: {},\n resultType: 'task',\n ...task,\n };\n }\n\n private async resolveTaskAction(\n toolName: string,\n args: ToolArgs,\n ): Promise<{\n objectType: string;\n objectId: string;\n methodName: string;\n invocationArgs: unknown[];\n } | null> {\n const separator = toolName.indexOf('_');\n if (separator <= 0) return null;\n const objectPrefix = toolName.slice(0, separator);\n const action = toolName.slice(separator + 1);\n if (['list', 'get', 'create', 'update', 'delete'].includes(action)) {\n return null;\n }\n const classEntry = Array.from(\n ObjectRegistry.getAllClasses().entries(),\n ).find(\n ([key, info]) =>\n (info.name || key).toLowerCase() === objectPrefix.toLowerCase(),\n );\n if (!classEntry) return null;\n const [key, classInfo] = classEntry;\n const objectName = classInfo.name || key;\n const mcpConfig = ObjectRegistry.getConfig(objectName).mcp;\n const configuredTasks =\n typeof mcpConfig === 'object' ? mcpConfig.tasks : undefined;\n if (\n configuredTasks !== true &&\n (!Array.isArray(configuredTasks) ||\n !configuredTasks.some(\n (method) => method.toLowerCase() === action.toLowerCase(),\n ))\n ) {\n return null;\n }\n\n // The action must already be visible through the normal MCP surface. This\n // keeps `tasks: true` from silently widening a class's configured tool set.\n const tools = await this.generateTools();\n if (!tools.some((tool) => tool.name === toolName)) return null;\n\n const [resolvedMethodName, method] = resolveCustomActionMethod(\n await ObjectRegistry.getAllMethods(objectName),\n action,\n );\n const methodName = method\n ? resolvedMethodName\n : resolveRuntimeMethodName(classInfo.constructor, action);\n const metadata = this.resolveCustomActionMetadata(\n objectName,\n methodName,\n method,\n this.hasCollectionReceiver(classInfo),\n );\n // TaskRunner preserves the canonical persisted-object hydration invariant.\n // Collection/static receivers do not have that target and intentionally do\n // not claim Tasks support until a separate durable receiver contract exists.\n if (\n !metadata.idRequired ||\n metadata.isStatic ||\n typeof args.id !== 'string'\n ) {\n return null;\n }\n return {\n objectType: classInfo.qualifiedName || objectName,\n objectId: args.id,\n methodName,\n invocationArgs: buildTaskActionInvocationArgs(metadata, args),\n };\n }\n\n /** Convert runtime values to the JSON values MCP structuredContent permits. */\n private toJsonValue(value: unknown): unknown {\n const serialized = JSON.stringify(value);\n return serialized === undefined ? null : JSON.parse(serialized);\n }\n\n /** Build the MCP-required object root without changing legacy text payloads. */\n private toStructuredContent(\n action: string,\n publicResult: unknown,\n ): Record<string, unknown> {\n if (!['list', 'get', 'create', 'update', 'delete'].includes(action)) {\n return { data: publicResult };\n }\n if (\n publicResult === null ||\n typeof publicResult !== 'object' ||\n Array.isArray(publicResult)\n ) {\n throw new Error(`Expected object result for MCP ${action} action`);\n }\n return publicResult as Record<string, unknown>;\n }\n\n /**\n * Get or create collection for an object\n */\n private async getCollection(\n objectName: string,\n classInfo: RegisteredClass,\n ): Promise<SmrtCollection<SmrtObject>> {\n if (!this.collections.has(objectName)) {\n // Ensure we have a valid collection constructor\n if (\n !classInfo.collectionConstructor ||\n typeof classInfo.collectionConstructor !== 'function'\n ) {\n throw new Error(\n `No valid collection constructor found for ${objectName}`,\n );\n }\n\n const collection = new classInfo.collectionConstructor({\n ai: this.context.ai,\n db: this.context.db,\n });\n\n // Verify the collection is actually a SmrtCollection instance\n if (!(collection instanceof SmrtCollection)) {\n throw new Error(\n `Collection for ${objectName} must extend SmrtCollection`,\n );\n }\n\n // Initialize the collection (database setup, etc.)\n await collection.initialize();\n\n this.collections.set(objectName, collection);\n }\n const collection = this.collections.get(objectName);\n if (!collection) {\n throw new Error(`Collection for ${objectName} not found`);\n }\n return collection;\n }\n\n /**\n * Serialize a tool-response payload, excluding sensitive fields (#1540).\n * Recurses through arrays and plain objects so a SmrtObject nested inside a\n * custom-action result (e.g. `{ item }`) is also stripped — `JSON.stringify`\n * would otherwise call its `toJSON()`. Non-plain instances (Date, etc.) and\n * primitives pass through unchanged; a cycle guard prevents infinite loops.\n */\n private toPublicData(\n value: unknown,\n seen: WeakSet<object> = new WeakSet(),\n options: PublicJsonOptions = this.getPublicJsonOptions(),\n ): unknown {\n if (value === null || typeof value !== 'object') return value;\n const publicSource = value as {\n toPublicJSON?: (options?: PublicJsonOptions) => unknown;\n };\n if (typeof publicSource.toPublicJSON === 'function') {\n return publicSource.toPublicJSON(options);\n }\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((entry) => this.toPublicData(entry, seen, options));\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n if (seen.has(value)) return value;\n seen.add(value);\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n out[key] = this.toPublicData(entry, seen, options);\n }\n return out;\n }\n\n private getPublicJsonOptions(): PublicJsonOptions {\n return { permissions: this.context.permissions };\n }\n\n /**\n * Mass-assignment guard (#1540): strip framework/server-managed and\n * `@field({ readonly: true })` fields from a create/update body, and — when an\n * `@smrt({ api: { writable: [...] } })` allowlist is set — intersect with it.\n */\n private applyWritablePolicy(\n objectName: string | undefined,\n data: unknown,\n ): Record<string, unknown> {\n if (!data || typeof data !== 'object') {\n return {};\n }\n\n const serverManaged = new Set([\n 'id',\n 'tenantId',\n 'tenant_id',\n 'createdAt',\n 'created_at',\n 'updatedAt',\n 'updated_at',\n ]);\n\n const readonly = new Set<string>();\n let writable: string[] | null = null;\n\n if (objectName) {\n const apiConfig = ObjectRegistry.getConfig(objectName)?.api;\n if (\n apiConfig &&\n typeof apiConfig === 'object' &&\n Array.isArray((apiConfig as { writable?: unknown }).writable)\n ) {\n writable = (apiConfig as { writable: string[] }).writable;\n }\n\n for (const [name, def] of ObjectRegistry.getFields(objectName)) {\n if (def && (def.readonly === true || def._meta?.readonly === true)) {\n readonly.add(name);\n }\n }\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (key.startsWith('_')) continue;\n if (serverManaged.has(key)) continue;\n if (readonly.has(key)) continue;\n if (writable && !writable.includes(key)) continue;\n result[key] = value;\n }\n return result;\n }\n\n /**\n * Execute action on collection\n */\n /**\n * Fail-closed authorization for tool calls (#1540). Mutating tools\n * (create/update/delete + custom actions) require an authenticated principal\n * (`context.user`) unless the object opts out via `@smrt({ api: { public } })`.\n * Reads are allowed when `public` is `true` or `'read'`.\n */\n private requireToolAuth(\n objectName: string | undefined,\n mutating: boolean,\n ): void {\n const apiConfig = objectName\n ? ObjectRegistry.getConfig(objectName)?.api\n : undefined;\n const publicAccess =\n apiConfig && typeof apiConfig === 'object'\n ? (apiConfig as { public?: boolean | 'read' }).public\n : undefined;\n\n if (publicAccess === true) return;\n if (publicAccess === 'read' && !mutating) return;\n if (!this.context.user) {\n throw new Error('Authentication required');\n }\n }\n\n private async executeAction(\n collection: SmrtCollection<SmrtObject>,\n action: string,\n args: ToolArgs,\n objectName?: string,\n ): Promise<unknown> {\n let targetCollection = collection;\n let targetObjectName = objectName;\n if (\n action === 'create' &&\n objectName &&\n typeof args._meta_type === 'string'\n ) {\n const variant = this.getStiVariants(objectName).find(\n (candidate) => candidate.discriminator === args._meta_type,\n );\n if (!variant) {\n throw new Error(`Unknown STI discriminator: ${args._meta_type}`);\n }\n const classInfo = ObjectRegistry.getClass(variant.name);\n if (!classInfo) {\n throw new Error(`STI subtype '${variant.name}' is not registered`);\n }\n targetCollection = await this.getCollection(variant.name, classInfo);\n targetObjectName = variant.name;\n }\n\n const mutating = action !== 'list' && action !== 'get';\n this.requireToolAuth(targetObjectName, mutating);\n\n // Fail-closed tenant context (#1554). For tenant-scoped objects, establish\n // the context from the principal's tenant (or an explicit cross-tenant\n // opt-in); without either, this throws when tenancy is enabled rather than\n // letting an optional-scoped read range across all tenants. Tenant-scoping\n // is resolved inside tenancy by class name so it matches the interceptor.\n return runWithTenantGate(\n {\n className: targetObjectName,\n tenantId: this.context.tenantId,\n allowCrossTenant: this.context.allowCrossTenant,\n surface: 'MCP',\n },\n () => this.runAction(targetCollection, action, args, targetObjectName),\n );\n }\n\n /**\n * Derive the set of tenant-scoped object names (lowercased simple names) from\n * a generated tool list, for the emitted runtime template's tenant gate\n * (#1554). Tool names are `objectname_action`.\n *\n * Detection uses ONLY tenancy's `isTenantScopedClass` (the authoritative\n * source the interceptor uses; covers `@TenantScoped`), consulted via an\n * optional dynamic import. We deliberately do NOT fall back to core's\n * `ObjectRegistry.isTenantScoped`: a `@smrt({ tenantScoped })` model can exist\n * in an app that has NOT installed `@happyvertical/smrt-tenancy`, and emitting\n * the static `import { runTenantScopedEntryPoint } from '@happyvertical/smrt-tenancy'`\n * gate for it would crash the generated server at import time. When tenancy is\n * absent there is also nothing to enforce, so emitting no gate is correct.\n */\n private async tenantScopedObjectNames(tools: MCPTool[]): Promise<string[]> {\n let isTenantScopedClass: ((name: string) => boolean) | undefined;\n try {\n // Held in a variable so neither TypeScript's declaration emit (TS2307 —\n // core deliberately does not depend on tenancy) nor the bundler tries to\n // statically resolve this optional sibling package. Same pattern as\n // `tenant-gate.ts` / `embeddings/provider.ts`.\n const tenancySpecifier = '@happyvertical/smrt-tenancy';\n const tenancy = (await import(/* @vite-ignore */ tenancySpecifier)) as {\n isTenantScopedClass?: (name: string) => boolean;\n };\n isTenantScopedClass = tenancy.isTenantScopedClass;\n } catch {\n isTenantScopedClass = undefined;\n }\n\n // No tenancy package installed → no gate can run, emit none.\n if (typeof isTenantScopedClass !== 'function') return [];\n\n const scoped = new Set<string>();\n for (const tool of tools) {\n const [objectName] = tool.name.split('_');\n if (!objectName) continue;\n // Resolve the registered simple name (case-insensitive) and test scoping.\n for (const [key, info] of ObjectRegistry.getAllClasses()) {\n const simpleName = info.name || key;\n if (simpleName.toLowerCase() === objectName.toLowerCase()) {\n if (isTenantScopedClass(simpleName)) {\n scoped.add(simpleName.toLowerCase());\n }\n break;\n }\n }\n }\n return Array.from(scoped);\n }\n\n /**\n * Whether a catalog contains a tenant-scoped class for cache isolation.\n *\n * Unlike the emitted runtime tenant gate, cache visibility must also fail\n * closed for core-declared `@smrt({ tenantScoped })` models when the optional\n * tenancy package is not installed. The registry covers that form, while\n * `tenantScopedObjectNames()` covers the tenancy-owned decorator form.\n */\n private async hasTenantScopedTools(tools: MCPTool[]): Promise<boolean> {\n if ((await this.tenantScopedObjectNames(tools)).length > 0) return true;\n\n for (const tool of tools) {\n const [objectName] = tool.name.split('_');\n if (!objectName) continue;\n for (const [key, info] of ObjectRegistry.getAllClasses()) {\n const simpleName = info.name || key;\n if (simpleName.toLowerCase() === objectName.toLowerCase()) {\n if (ObjectRegistry.isTenantScoped(simpleName)) return true;\n break;\n }\n }\n }\n\n return false;\n }\n\n /**\n * Execute a resolved MCP action (CRUD or custom) against a collection. Always\n * invoked inside the tenant gate established by {@link executeAction}.\n */\n private async runAction(\n collection: SmrtCollection<SmrtObject>,\n action: string,\n args: ToolArgs,\n objectName?: string,\n ): Promise<unknown> {\n switch (action) {\n case 'list': {\n // Args arrive as untyped JSON; narrow each query field at this\n // boundary. `where`/`orderBy` are passed through to the collection's\n // typed query API.\n const listOptions: Parameters<typeof collection.list>[0] = {\n limit: Math.min((args.limit as number | undefined) || 50, 1000),\n offset: (args.offset as number | undefined) || 0,\n };\n\n if (args.where) {\n listOptions.where = args.where as (typeof listOptions)['where'];\n }\n\n if (args.orderBy) {\n listOptions.orderBy = args.orderBy as string | string[];\n }\n\n const results = await collection.list(listOptions);\n const total = await collection.count({\n where: (args.where as (typeof listOptions)['where']) || {},\n });\n\n return {\n data: results.map((result) => this.toPublicData(result)),\n meta: {\n total,\n limit: listOptions.limit,\n offset: listOptions.offset,\n count: results.length,\n },\n };\n }\n\n case 'get': {\n if (!args.id && !args.slug) {\n throw new Error('Either id or slug is required');\n }\n\n const filter = (args.id ? args.id : args.slug) as string;\n const item = await collection.get(filter);\n\n if (!item) {\n throw new Error('Object not found');\n }\n\n return this.toPublicData(item);\n }\n\n case 'create': {\n // Mass-assignment guard (#1540): only writable fields from the caller.\n const createData: Record<string, unknown> = this.applyWritablePolicy(\n objectName,\n args,\n );\n // Server-set ownership context (not caller-controlled).\n if (this.context.user) {\n createData.created_by = this.context.user.id;\n createData.owner_id = this.context.user.id;\n }\n\n // The writable-policy output is a dynamically-shaped record of caller\n // data; cast to the collection's create input at this boundary.\n const newItem = await collection.create(\n createData as Parameters<typeof collection.create>[0],\n );\n await newItem.save();\n\n return this.toPublicData(newItem);\n }\n\n case 'update': {\n const id = args.id as string | undefined;\n if (!id) {\n throw new Error('ID is required for update');\n }\n\n const existing = await collection.get(id);\n if (!existing) {\n throw new Error('Object not found');\n }\n\n // Mass-assignment guard (#1540): strip server-managed/read-only keys\n // (incl. `id`) before applying caller-supplied updates.\n const updateData = this.applyWritablePolicy(objectName, args);\n Object.assign(existing, updateData);\n\n // Add user context. `updated_by` is a server-set audit column, not a\n // declared model field, so assign it through a record view.\n if (this.context.user) {\n (existing as unknown as Record<string, unknown>).updated_by =\n this.context.user.id;\n }\n\n await existing.save();\n\n return this.toPublicData(existing);\n }\n\n case 'delete': {\n if (!args.id) {\n throw new Error('ID is required for delete');\n }\n\n const toDelete = await collection.get(args.id as string);\n if (!toDelete) {\n throw new Error('Object not found');\n }\n\n await toDelete.delete();\n\n return { success: true, message: 'Object deleted successfully' };\n }\n\n default: {\n // Handle custom actions. The method may return a SmrtObject (or array),\n // so serialize through toPublicData to strip sensitive fields (#1540).\n const result = await this.executeCustomAction(\n collection,\n action,\n args,\n objectName,\n );\n return this.toPublicData(result);\n }\n }\n }\n\n /**\n * Execute a custom action on a collection/object\n */\n private async executeCustomAction(\n collection: SmrtCollection<SmrtObject>,\n action: string,\n args: ToolArgs,\n objectName?: string,\n ): Promise<unknown> {\n const id = args.id;\n const [methodName, methodDef] = objectName\n ? resolveCustomActionMethod(\n await ObjectRegistry.getAllMethods(objectName),\n action,\n )\n : [action, undefined];\n const metadata = this.resolveCustomActionMetadata(\n objectName ?? '',\n methodName,\n methodDef,\n objectName\n ? this.hasCollectionReceiver(ObjectRegistry.getClass(objectName))\n : false,\n );\n const methodArgs = buildCustomActionInvocationArgs(metadata, args);\n\n try {\n if (methodDef && metadata.idRequired && !id) {\n throw new Error(`ID is required for custom action '${action}'`);\n }\n if (!metadata.idRequired && id && methodDef) {\n throw new Error(\n `Custom action '${action}' is collection-scoped and does not accept an ID`,\n );\n }\n\n // If an ID is provided, get the specific object and call the method on it\n if (id) {\n const object = await collection.get(id as string);\n if (!object) {\n throw new Error('Object not found');\n }\n\n // Custom action names are resolved dynamically, so index the instance\n // through a record view and narrow the value to a callable after the\n // `typeof === 'function'` guard.\n const objectWithMethods = object as unknown as Record<string, unknown>;\n const objectMethod = objectWithMethods[methodName];\n if (typeof objectMethod === 'function') {\n // `.call(object, …)` preserves the receiver binding of the original\n // member call (`object[action](…)`) — the method relies on `this`.\n const result = await (objectMethod as InstanceCallable).call(\n object,\n ...methodArgs,\n );\n const failure = normalizeCustomActionFailure(result);\n if (failure) throw new CustomActionFailureError(failure);\n return result;\n } else {\n throw new Error(\n `Method '${methodName}' not found on object instance`,\n );\n }\n } else if (metadata.isStatic && objectName) {\n const classInfo = ObjectRegistry.getClass(objectName);\n const classMethod = (\n classInfo?.constructor as unknown as\n | Record<string, unknown>\n | undefined\n )?.[methodName];\n if (typeof classMethod !== 'function') {\n throw new Error(\n `Static method '${methodName}' not found on ${objectName}`,\n );\n }\n const result = await (classMethod as InstanceCallable).call(\n classInfo?.constructor,\n ...methodArgs,\n );\n const failure = normalizeCustomActionFailure(result);\n if (failure) throw new CustomActionFailureError(failure);\n return result;\n } else {\n // No ID provided, try to call the method on the collection\n const collectionMethod = (\n collection as unknown as Record<string, unknown>\n )[methodName];\n if (typeof collectionMethod === 'function') {\n // `.call(collection, …)` preserves the receiver binding of the\n // original member call (`collection[action](…)`).\n const result = await (collectionMethod as InstanceCallable).call(\n collection,\n ...methodArgs,\n );\n const failure = normalizeCustomActionFailure(result);\n if (failure) throw new CustomActionFailureError(failure);\n return result;\n } else {\n throw new Error(\n `Method '${methodName}' not found on collection. For object-specific actions, provide an 'id' parameter.`,\n );\n }\n }\n } catch (error) {\n if (error instanceof CustomActionFailureError) throw error;\n throw new Error(\n `Failed to execute custom action '${action}': ${error instanceof Error ? error.message : 'Unknown error'}`,\n );\n }\n }\n\n /**\n * Generate MCP server info\n */\n getServerInfo() {\n return {\n name: this.config.server?.name,\n version: this.config.server?.version,\n description: this.config.description,\n };\n }\n\n /**\n * Generate complete MCP server with stdio transport\n *\n * Creates a runnable Node.js script that exposes SMRT objects as MCP tools.\n * The generated server includes:\n * - Stdio transport integration\n * - Tool registration from ObjectRegistry\n * - Error handling and logging\n * - Graceful shutdown\n *\n * @param options - Server generation options\n * @returns Promise that resolves when all files are written\n *\n * @example\n * ```typescript\n * const generator = new MCPGenerator({\n * name: 'my-app',\n * version: '1.0.0'\n * });\n *\n * await generator.generateServer({\n * outputPath: '.smrt/mcp-server/index.js',\n * serverName: 'my-app-mcp',\n * debug: true\n * });\n * ```\n */\n async generateServer(\n options: {\n /**\n * Path to output server file (relative or absolute).\n *\n * The extension decides the emitted language: `.ts`/`.mts`/`.cts` keep\n * the generated TypeScript, anything else is transpiled to JavaScript so\n * plain `node <path>` runs it (#2279).\n */\n outputPath?: string;\n\n /** Server name for configuration */\n serverName?: string;\n\n /** Server version */\n serverVersion?: string;\n\n /** Enable debug logging */\n debug?: boolean;\n\n /** Generate Claude Desktop configuration example */\n generateClaudeConfigFile?: boolean;\n\n /** Generate README documentation */\n generateReadme?: boolean;\n\n /** Generate modular directory structure (tools/, handlers/, config) */\n modular?: boolean;\n } = {},\n ): Promise<void> {\n const {\n outputPath = '.smrt/mcp-server/index.js',\n serverName = this.config.name || 'smrt-mcp-server',\n serverVersion = this.config.version || '1.0.0',\n debug = false,\n generateClaudeConfigFile = false,\n generateReadme = false,\n modular = false,\n } = options;\n\n // Resolve output path\n const resolvedPath = resolve(process.cwd(), outputPath);\n const outputDir = dirname(resolvedPath);\n\n // The requested extension decides whether the generated TypeScript is\n // written verbatim or transpiled to runnable JavaScript first (#2279).\n const language = resolveGeneratedSourceLanguage(resolvedPath);\n\n // Ensure output directory exists\n await mkdir(outputDir, { recursive: true });\n\n if (modular) {\n // Generate modular structure: tools/, handlers/, config, entry point\n await this.generateModularServer(\n resolvedPath,\n serverName,\n serverVersion,\n debug,\n language,\n );\n } else {\n // Generate single-file server with static tools\n const tools = await this.generateTools();\n const tenantScopedObjects = await this.tenantScopedObjectNames(tools);\n const hasTenantScopedTools =\n tenantScopedObjects.length > 0 ||\n (await this.hasTenantScopedTools(tools));\n\n const runtimeOptions: RuntimeOptions = {\n name: serverName,\n version: serverVersion,\n description: this.config.description,\n config: this.config,\n context: this.context,\n debug,\n tools,\n customActions: await this.runtimeCustomActions(tools),\n taskActions: await this.runtimeTaskActions(tools),\n tenantScopedObjects,\n stiTargets: this.runtimeStiTargets(tools),\n toolListCacheHint: resolveMCPToolListCacheHint(\n this.config.cache?.toolsList,\n hasTenantScopedTools,\n ),\n };\n\n const serverCode = generateRuntimeBootstrap(runtimeOptions);\n\n // Write server file\n await writeGeneratedFile(resolvedPath, serverCode, language);\n console.log(`✅ Generated MCP server: ${resolvedPath}`);\n }\n\n // Generate Claude Desktop configuration example\n if (generateClaudeConfigFile) {\n const claudeConfig = generateClaudeConfig(serverName, resolvedPath);\n const claudeConfigPath = resolve(outputDir, 'claude-config.example.json');\n await writeFile(\n claudeConfigPath,\n JSON.stringify(claudeConfig, null, 2),\n 'utf-8',\n );\n console.log(`✅ Generated Claude config example: ${claudeConfigPath}`);\n }\n\n // Generate README documentation\n if (generateReadme) {\n const readme = generateMCPDocumentation(serverName, outputPath);\n const readmePath = resolve(outputDir, 'MCP-README.md');\n await writeFile(readmePath, readme, 'utf-8');\n console.log(`✅ Generated MCP documentation: ${readmePath}`);\n }\n\n // Generate npm script suggestion\n const mcpScript = generateMCPScript(outputPath);\n console.log(`\\n📝 Add this to your package.json scripts:`);\n console.log(` \"mcp\": \"${mcpScript}\"\\n`);\n }\n\n private async runtimeCustomActions(\n tools: MCPTool[],\n ): Promise<NonNullable<RuntimeOptions['customActions']>> {\n const metadata: NonNullable<RuntimeOptions['customActions']> = {};\n const crudActions = new Set(['list', 'get', 'create', 'update', 'delete']);\n const classes = ObjectRegistry.getAllClasses();\n\n for (const tool of tools) {\n const separator = tool.name.indexOf('_');\n if (separator === -1) continue;\n const objectPrefix = tool.name.slice(0, separator);\n const action = tool.name.slice(separator + 1);\n if (crudActions.has(action)) continue;\n const matched = Array.from(classes.entries()).find(\n ([key, info]) => (info.name || key).toLowerCase() === objectPrefix,\n );\n if (!matched) continue;\n const [key, classInfo] = matched;\n const objectName = classInfo.name || key;\n const [methodName, method] = resolveCustomActionMethod(\n await ObjectRegistry.getAllMethods(objectName),\n action,\n );\n const resolved = this.resolveCustomActionMetadata(\n objectName,\n methodName,\n method,\n this.hasCollectionReceiver(classInfo),\n );\n metadata[tool.name] = {\n scope: resolved.scope,\n isStatic: resolved.isStatic,\n methodName,\n ...(resolved.parameters\n ? {\n parameterNames: resolved.parameters.map(\n (parameter) => parameter.name,\n ),\n optionsParameter:\n resolved.parameters.length === 1 &&\n resolved.parameters[0]?.name === 'options',\n }\n : {}),\n legacyOptions: !resolved.parameters,\n };\n }\n return metadata;\n }\n\n /** Emit only task-enabled item custom actions for the generated runtime. */\n private async runtimeTaskActions(\n tools: MCPTool[],\n ): Promise<NonNullable<RuntimeOptions['taskActions']>> {\n const actions: NonNullable<RuntimeOptions['taskActions']> = {};\n const classes = ObjectRegistry.getAllClasses();\n for (const tool of tools) {\n if (!(await this.supportsTaskTool(tool.name))) continue;\n const separator = tool.name.indexOf('_');\n if (separator <= 0) continue;\n const objectPrefix = tool.name.slice(0, separator).toLowerCase();\n const matched = Array.from(classes.entries()).find(\n ([key, info]) => (info.name || key).toLowerCase() === objectPrefix,\n );\n if (!matched) continue;\n const [key, classInfo] = matched;\n const objectName = classInfo.name || key;\n actions[tool.name] = {\n objectName,\n objectType: classInfo.qualifiedName || objectName,\n };\n }\n return actions;\n }\n\n /**\n * Emit only the STI discriminator targets advertised by create-tool schemas.\n * Generated processes start with an empty registry, so resolving the\n * qualified target through `getCollection()` both validates the declaration\n * and lets the public registry loader register the selected subtype.\n */\n private runtimeStiTargets(\n tools: MCPTool[],\n ): Record<string, Record<string, string>> {\n const targets: Record<string, Record<string, string>> = {};\n const classes = ObjectRegistry.getAllClasses();\n\n for (const tool of tools) {\n const separator = tool.name.indexOf('_');\n if (separator === -1 || tool.name.slice(separator + 1) !== 'create') {\n continue;\n }\n const objectPrefix = tool.name.slice(0, separator);\n const matched = Array.from(classes.entries()).find(\n ([key, info]) => (info.name || key).toLowerCase() === objectPrefix,\n );\n if (!matched) continue;\n\n const [key, classInfo] = matched;\n const variants = this.getStiVariants(classInfo.name || key);\n if (variants.length === 0) continue;\n\n targets[objectPrefix] = Object.fromEntries(\n variants.map((variant) => [\n variant.discriminator,\n variant.discriminator,\n ]),\n );\n }\n\n return targets;\n }\n\n /**\n * Generate modular MCP server structure\n *\n * Creates separate files for tools, handlers, configuration, and main entry point.\n * This makes the generated server easier to customize and extend.\n *\n * The sibling modules use the entry point's own extension and the entry\n * emits matching relative specifiers, so its imports resolve to files that\n * exist and load with the same module semantics (#2279).\n *\n * @param indexPath - Absolute path of the entry point to generate\n * @param serverName - Server name\n * @param serverVersion - Server version\n * @param debug - Enable debug logging\n * @param language - Language the generated files are written in\n */\n private async generateModularServer(\n indexPath: string,\n serverName: string,\n serverVersion: string,\n debug: boolean,\n language: GeneratedSourceLanguage,\n ): Promise<void> {\n const outputDir = dirname(indexPath);\n const extension = generatedSiblingExtension(indexPath);\n\n // Create subdirectories\n const toolsDir = resolve(outputDir, 'tools');\n const handlersDir = resolve(outputDir, 'handlers');\n\n await mkdir(toolsDir, { recursive: true });\n await mkdir(handlersDir, { recursive: true });\n\n // Generate config module\n const configPath = resolve(outputDir, `config${extension}`);\n const configCode = this.generateConfigFile(\n serverName,\n serverVersion,\n debug,\n );\n await writeGeneratedFile(configPath, configCode, language);\n console.log(`✅ Generated config: ${configPath}`);\n\n const generatedTools = await this.generateTools();\n\n // Generate tools module with tool definitions\n const toolsPath = resolve(toolsDir, `index${extension}`);\n const toolsCode = this.generateToolsFile(generatedTools);\n await writeGeneratedFile(toolsPath, toolsCode, language);\n console.log(`✅ Generated tools: ${toolsPath}`);\n\n // Generate handlers module with tool call handlers\n const handlersPath = resolve(handlersDir, `index${extension}`);\n const tenantScopedObjects =\n await this.tenantScopedObjectNames(generatedTools);\n const hasTenantScopedTools =\n tenantScopedObjects.length > 0 ||\n (await this.hasTenantScopedTools(generatedTools));\n const handlersCode = await this.generateHandlersFile(tenantScopedObjects);\n await writeGeneratedFile(handlersPath, handlersCode, language);\n console.log(`✅ Generated handlers: ${handlersPath}`);\n\n // Generate main entry point\n const indexCode = this.generateModularIndex(\n resolveMCPToolListCacheHint(\n this.config.cache?.toolsList,\n hasTenantScopedTools,\n ),\n extension,\n );\n await writeGeneratedFile(indexPath, indexCode, language);\n console.log(`✅ Generated MCP server: ${indexPath}`);\n }\n\n /**\n * Generate configuration file for modular server\n */\n private generateConfigFile(\n serverName: string,\n serverVersion: string,\n debug: boolean,\n ): string {\n return `/**\n * MCP Server Configuration\n * Auto-generated by @happyvertical/smrt-core\n */\n\nexport const SERVER_NAME = ${JSON.stringify(serverName)};\nexport const SERVER_VERSION = ${JSON.stringify(serverVersion)};\nexport const SERVER_DESCRIPTION = ${JSON.stringify(this.config.description)};\nexport const DEBUG = ${debug};\n`;\n }\n\n /**\n * Generate tools definitions file for modular server\n */\n private generateToolsFile(tools: MCPTool[]): string {\n return `/**\n * MCP Tools Definitions\n * Auto-generated from SMRT objects\n */\n\nexport const tools: Array<{\n name: string;\n description: string;\n inputSchema: any;\n outputSchema: any;\n}> = ${JSON.stringify(tools, null, 2)};\n`;\n }\n\n /**\n * Generate switch cases for tool execution\n */\n private async generateToolSwitchCases(\n indent: string = ' ',\n generatedTools?: MCPTool[],\n ): Promise<string> {\n const tools = generatedTools ?? (await this.generateTools());\n\n const capitalize = (str: string) =>\n str.charAt(0).toUpperCase() + str.slice(1);\n\n const switchCases = (\n await Promise.all(\n tools.map(async (tool) => {\n const separator = tool.name.indexOf('_');\n const objectName = tool.name.slice(0, separator);\n const action = tool.name.slice(separator + 1);\n\n switch (action) {\n case 'list':\n return `${indent}case '${tool.name}': {\n${indent} const limit = args.limit ?? 50;\n${indent} const offset = args.offset ?? 0;\n${indent} const where = args.where ?? {};\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const items = await collection.list({ where, limit, offset });\n${indent} const itemsPublic = items.map((item) => item.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent} const structuredContent = {\n${indent} data: itemsPublic,\n${indent} meta: { total: await collection.count({ where }), limit, offset, count: items.length },\n${indent} };\n${indent} return successResult(structuredContent, JSON.stringify(itemsPublic));\n${indent}}`;\n\n case 'get':\n return `${indent}case '${tool.name}': {\n${indent} if (!args.id && !args.slug) {\n${indent} throw new Error('Either id or slug is required');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const filter = args.id || args.slug;\n${indent} const item = await collection.get(filter);\n\n${indent} if (!item) {\n${indent} throw new Error('Object not found');\n${indent} }\n\n${indent} return successResult(item.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent}}`;\n\n case 'create':\n return `${indent}case '${tool.name}': {\n${indent} const { collection, objectName: targetObjectName } = await resolveCreateTarget('${objectName}', args, aiConfig);\n\n${indent} const newItem = await collection.create(applyWritablePolicy(targetObjectName, args));\n${indent} await newItem.save();\n\n${indent} return successResult(newItem.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent}}`;\n\n case 'update':\n return `${indent}case '${tool.name}': {\n${indent} const { id, ...updateData } = args;\n${indent} if (!id) {\n${indent} throw new Error('ID is required for update');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const existing = await collection.get(id);\n${indent} if (!existing) {\n${indent} throw new Error('Object not found');\n${indent} }\n\n${indent} Object.assign(existing, applyWritablePolicy('${capitalize(objectName)}', updateData));\n${indent} await existing.save();\n\n${indent} return successResult(existing.toPublicJSON(PUBLIC_JSON_OPTIONS));\n${indent}}`;\n\n case 'delete':\n return `${indent}case '${tool.name}': {\n${indent} if (!args.id) {\n${indent} throw new Error('ID is required for delete');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection('${capitalize(objectName)}', {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const toDelete = await collection.get(args.id);\n${indent} if (!toDelete) {\n${indent} throw new Error('Object not found');\n${indent} }\n\n${indent} await toDelete.delete();\n\n${indent} return successResult({ success: true, message: 'Object deleted successfully' });\n${indent}}`;\n\n default: {\n // Custom actions use the same canonical receiver/argument contract\n // as the in-process and standalone MCP runtimes. In particular,\n // a route config cannot turn an instance method into a static one.\n const matched = Array.from(\n ObjectRegistry.getAllClasses().entries(),\n ).find(\n ([key, info]) =>\n (info.name || key).toLowerCase() === objectName.toLowerCase(),\n );\n if (!matched) {\n throw new Error(\n `Unable to resolve custom-action target for tool '${tool.name}'`,\n );\n }\n const [classKey, classInfo] = matched;\n const registeredName = classInfo.name || classKey;\n const [methodName, method] = resolveCustomActionMethod(\n await ObjectRegistry.getAllMethods(registeredName),\n action,\n );\n const metadata = this.resolveCustomActionMetadata(\n registeredName,\n methodName,\n method,\n this.hasCollectionReceiver(classInfo),\n );\n const methodArgs = !metadata.parameters\n ? 'Object.keys(options ?? {}).length > 0 ? options : directArgs'\n : metadata.parameters.length === 1 &&\n metadata.parameters[0]?.name === 'options'\n ? 'options'\n : `[${metadata.parameters\n .map(\n (parameter) =>\n `args[${JSON.stringify(\n customActionParameterInputName(\n metadata,\n parameter.name,\n ),\n )}]`,\n )\n .join(', ')}]`;\n return `${indent}case '${tool.name}': {\n${indent} const { id, options, ...directArgs } = args;\n\n${indent} if (${JSON.stringify(metadata.scope)} === 'item' && !id) {\n${indent} throw new Error('ID is required for custom action ${action}');\n${indent} }\n${indent} if (${JSON.stringify(metadata.scope)} === 'collection' && id) {\n${indent} throw new Error('Custom action ${action} is collection-scoped and does not accept an ID');\n${indent} }\n\n${indent} const collection = await ObjectRegistry.getCollection(${JSON.stringify(registeredName)}, {\n${indent} persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n${indent} ai: aiConfig\n${indent} });\n\n${indent} const target = ${JSON.stringify(metadata.scope)} === 'item'\n${indent} ? await collection.get(id)\n${indent} : ${metadata.isStatic}\n${indent} ? ObjectRegistry.getClass(${JSON.stringify(registeredName)})?.constructor\n${indent} : collection;\n${indent} if (!target) {\n${indent} throw new Error(${JSON.stringify(\n metadata.scope === 'item'\n ? 'Object not found'\n : 'Custom action target not found',\n )});\n${indent} }\n\n${indent} const actionMethod = target[${JSON.stringify(methodName)}];\n${indent} if (typeof actionMethod !== 'function') {\n${indent} throw new Error('Method ${methodName} not found on custom action target');\n${indent} }\n\n${indent} const methodArgs = ${methodArgs.startsWith('[') ? methodArgs : `[${methodArgs}]`};\n${indent} const result = await actionMethod.call(target, ...methodArgs);\n${indent} const failure = normalizeCustomActionFailure(result);\n${indent} if (failure) {\n${indent} return errorResult(\n${indent} { error: failure },\n${indent} JSON.stringify({ error: failure }),\n${indent} { [SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY]: failure },\n${indent} );\n${indent} }\n\n${indent} const publicResult = toPublicResult(result);\n${indent} return successResult({ data: publicResult }, JSON.stringify(publicResult));\n${indent}}`;\n }\n }\n }),\n )\n ).join('\\n\\n');\n\n return switchCases;\n }\n\n /**\n * Generate handlers file for modular server\n */\n private async generateHandlersFile(\n tenantScopedObjects: string[] = [],\n ): Promise<string> {\n const tools = await this.generateTools();\n const switchCases = await this.generateToolSwitchCases(' ', tools);\n const stiTargets = this.runtimeStiTargets(tools);\n const tenantScopedSet = Array.from(\n new Set(tenantScopedObjects.map((n) => n.toLowerCase())),\n );\n const hasTenantScoped = tenantScopedSet.length > 0;\n\n return `/**\n * MCP Tool Call Handlers\n * Auto-generated from SMRT objects\n *\n * SECURITY (#1540): responses exclude @field({ sensitive }) fields and\n * create/update bodies are mass-assignment guarded. This handler has no\n * per-call authentication principal — the generated stdio MCP server's trust\n * boundary is the host process / MCP client. Run it only in a trusted context\n * or behind an authenticated gateway.\n *\n * SECURITY (#1554): tenant-scoped tools run inside a fail-closed tenant gate;\n * the tenant is taken from SMRT_MCP_TENANT_ID (this server has no auth\n * principal) and tenancy is enabled so the interceptor enforces filtering.\n */\n\nimport { ObjectRegistry, normalizeCustomActionFailure, SMRT_CUSTOM_ACTION_ERROR_METADATA_KEY } from '@happyvertical/smrt-core';\n${hasTenantScoped ? \"import { enableTenancy, runTenantScopedEntryPoint } from '@happyvertical/smrt-tenancy';\\n\" : ''}${\n hasTenantScoped\n ? `\n// Install the tenancy interceptor so tenant-scoped tools are filtered and the\n// gate fail-closes when no tenant is supplied (#1554).\nenableTenancy();\nconst TENANT_SCOPED = new Set(${JSON.stringify(tenantScopedSet)});\nconst MCP_TENANT_ID = process.env.SMRT_MCP_TENANT_ID || undefined;\nconst MCP_ALLOW_CROSS_TENANT = process.env.SMRT_MCP_ALLOW_CROSS_TENANT === 'true';\n`\n : ''\n}\n\nconst PUBLIC_JSON_OPTIONS = {\n permissions: (process.env.SMRT_MCP_PERMISSIONS || '')\n .split(',')\n .map((permission) => permission.trim())\n .filter(Boolean),\n};\nconst STI_TARGETS: Record<string, Record<string, string>> = ${JSON.stringify(stiTargets)};\n\n/**\n * Mass-assignment guard (#1540): strip framework/server-managed and\n * \\`@field({ readonly: true })\\` fields from create/update bodies, intersecting\n * with the optional \\`@smrt({ api: { writable: [...] } })\\` allowlist.\n */\nfunction applyWritablePolicy(objectName: string, data: any): Record<string, any> {\n if (!data || typeof data !== 'object') return {};\n const serverManaged = new Set<string>([\n 'id', 'tenantId', 'tenant_id',\n 'createdAt', 'created_at', 'updatedAt', 'updated_at',\n ]);\n const readonly = new Set<string>();\n let writable: string[] | null = null;\n const apiConfig = ObjectRegistry.getConfig(objectName)?.api as any;\n if (apiConfig && typeof apiConfig === 'object' && Array.isArray(apiConfig.writable)) {\n writable = apiConfig.writable;\n }\n for (const [name, def] of ObjectRegistry.getFields(objectName)) {\n if (def && ((def as any).readonly === true || (def as any)._meta?.readonly === true)) {\n readonly.add(name);\n }\n }\n const result: Record<string, any> = {};\n for (const [key, value] of Object.entries(data as Record<string, any>)) {\n if (key.startsWith('_')) continue;\n if (serverManaged.has(key)) continue;\n if (readonly.has(key)) continue;\n if (writable && !writable.includes(key)) continue;\n result[key] = value;\n }\n return result;\n}\n\n/** Resolve an advertised STI discriminator to its registered subtype collection. */\nasync function resolveCreateTarget(baseObjectName: string, args: Record<string, any>, aiConfig: any) {\n let objectName = baseObjectName;\n const discriminator = args._meta_type;\n const targets = STI_TARGETS[baseObjectName];\n if (typeof discriminator === 'string' && targets) {\n const target = targets[discriminator];\n if (!target) throw new Error('Unknown STI discriminator: ' + discriminator);\n objectName = target;\n }\n const collection = await ObjectRegistry.getCollection(objectName, {\n persistence: { type: process.env.DATABASE_TYPE || 'sqlite', url: process.env.DATABASE_URL || ':memory:' },\n ai: aiConfig,\n });\n return { collection, objectName };\n}\n\n/**\n * Sensitive-field-safe serialization for custom-action results (#1540).\n * Recurses through arrays and plain objects so nested SmrtObjects are stripped\n * too; non-plain instances (Date, etc.) and primitives pass through. Cycle-safe.\n */\nfunction toPublicResult(value: any, seen: WeakSet<object> = new WeakSet()): any {\n if (value === null || typeof value !== 'object') return value;\n if (typeof value.toPublicJSON === 'function') return value.toPublicJSON(PUBLIC_JSON_OPTIONS);\n if (Array.isArray(value)) {\n if (seen.has(value)) return value;\n seen.add(value);\n return value.map((entry: any) => toPublicResult(entry, seen));\n }\n const proto = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) return value;\n if (seen.has(value)) return value;\n seen.add(value);\n const out: Record<string, any> = {};\n for (const [key, entry] of Object.entries(value as Record<string, any>)) {\n out[key] = toPublicResult(entry, seen);\n }\n return out;\n}\n\nfunction successResult(structuredContent: any, text = JSON.stringify(structuredContent)) {\n return {\n content: [{ type: 'text', text }],\n structuredContent,\n };\n}\n\nfunction errorResult(structuredContent: any, text: string, _meta?: Record<string, any>) {\n return {\n content: [{ type: 'text', text }],\n isError: true,\n structuredContent,\n ...(_meta ? { _meta } : {}),\n };\n}\n\n/**\n * Handle tool call request\n */\nexport async function handleToolCall(\n name: string,\n toolArguments: any = {},\n aiConfig: any = {}\n) {\n try {\n const args = toolArguments;\n\n const runToolBody = async () => {\n switch (name) {\n${switchCases}\n\n default:\n throw new Error(\\`Unknown tool: \\${name}\\`);\n }\n };\n${\n hasTenantScoped\n ? `\n // Fail-closed tenant context for tenant-scoped tools (#1554).\n const [toolObject] = name.split('_');\n const result =\n toolObject && TENANT_SCOPED.has(toolObject.toLowerCase())\n ? await runTenantScopedEntryPoint(\n { tenantScoped: true, tenantId: MCP_TENANT_ID, allowCrossTenant: MCP_ALLOW_CROSS_TENANT, surface: 'MCP' },\n runToolBody,\n )\n : await runToolBody();`\n : `\n const result = await runToolBody();`\n}\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n\n return errorResult(\n { error: { message: errorMessage } },\n \\`Error executing tool \\${name}: \\${errorMessage}\\`,\n );\n }\n}\n`;\n }\n\n /**\n * Generate modular index file (main entry point)\n *\n * @param toolListCacheHint - Cache hint emitted for `tools/list` results\n * @param extension - Extension of the sibling modules this entry imports\n */\n private generateModularIndex(\n toolListCacheHint: MCPToolListCacheHint,\n extension: GeneratedSourceExtension = '.js',\n ): string {\n return `#!/usr/bin/env node\n/**\n * Auto-generated MCP Server\n * Generated by @happyvertical/smrt-core MCPGenerator\n *\n * This server exposes SMRT objects as MCP tools for AI integration.\n */\n\nimport { Server } from '@modelcontextprotocol/server';\nimport { serveStdio } from '@modelcontextprotocol/server/stdio';\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\nimport { loadConfig } from '@happyvertical/smrt-config';\n\nimport { SERVER_NAME, SERVER_VERSION, DEBUG } from './config${extension}';\nimport { tools } from './tools/index${extension}';\nimport { handleToolCall } from './handlers/index${extension}';\n\nconst TOOL_LIST_CACHE_HINT = ${JSON.stringify(toolListCacheHint)};\n\n/**\n * Main server startup function\n */\nexport async function createServer() {\n if (DEBUG) {\n console.error(\\`[MCP] Starting server: \\${SERVER_NAME} v\\${SERVER_VERSION}\\`);\n console.error(\\`[MCP] Available tools:\\`, tools.map(t => t.name).join(', '));\n }\n\n // Register the application package manifest before resolving generated\n // object names. Generated servers are commonly run from the application\n // package itself, which is not a node_modules dependency of its process.\n const localManifestPaths = [\n resolve(process.cwd(), 'dist', 'manifest.json'),\n resolve(process.cwd(), '.smrt', 'manifest.json'),\n ].filter(existsSync);\n if (localManifestPaths.length > 0) {\n ObjectRegistry.loadAllManifests({ manifestPaths: localManifestPaths });\n }\n\n // Load configuration from environment and .smrt.config files\n const appConfig = await loadConfig();\n const aiConfig = appConfig?.ai || {};\n\n // Create MCP server\n const server = new Server(\n {\n name: SERVER_NAME,\n version: SERVER_VERSION,\n },\n {\n capabilities: {\n tools: {},\n },\n cacheHints: {\n 'tools/list': TOOL_LIST_CACHE_HINT,\n },\n }\n );\n\n // Register ListTools handler\n server.setRequestHandler('tools/list', async () => {\n if (DEBUG) {\n console.error(\\`[MCP] ListTools request received\\`);\n }\n\n return {\n tools: [...tools].sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0).map(tool => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n })),\n };\n });\n\n // Register CallTool handler\n server.setRequestHandler('tools/call', async (request) => {\n const { name, arguments: args = {} } = request.params;\n\n if (DEBUG) {\n console.error(\\`[MCP] CallTool request: \\${name}\\`);\n console.error(\\`[MCP] Arguments:\\`, JSON.stringify(args, null, 2));\n }\n\n return await handleToolCall(name, args, aiConfig);\n });\n\n return server;\n}\n\nasync function main() {\n try {\n const handle = serveStdio(() => createServer(), {\n onerror: (error) => console.error('[MCP] Protocol error:', error),\n });\n const shutdown = async () => {\n if (DEBUG) console.error('[MCP] Shutting down gracefully');\n await handle.close();\n process.exit(0);\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n } catch (error) {\n console.error('[MCP] Fatal error during server startup:', error);\n process.exit(1);\n }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().catch((error) => {\n console.error('[MCP] Unhandled error:', error);\n process.exit(1);\n });\n}\n`;\n }\n}\n"],"mappings":"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"}
@@ -8,6 +8,11 @@ export interface ManifestBuilderOptions {
8
8
  include?: string[];
9
9
  exclude?: string[];
10
10
  followImports?: boolean;
11
+ /**
12
+ * Follow symbolic links while discovering sources. Defaults to `false` —
13
+ * see `OxcScannerOptions.followSymbolicLinks` (#2275).
14
+ */
15
+ followSymbolicLinks?: boolean;
11
16
  baseClasses?: string[];
12
17
  loadViteConfig?: boolean;
13
18
  discoverExternalPackages?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/manifest/generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAwB/D;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IAErC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IAGxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAG/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC;AAuCD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACG,QAAQ,CACZ,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC;IAkC/B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAUrB;;OAEG;YACW,gBAAgB;IAoD9B;;;;;OAKG;YACW,oBAAoB;IAyElC;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAiCtB;;OAEG;YACW,WAAW;IAyCzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuCxB;;OAEG;YACW,yBAAyB;IA6EvC;;OAEG;YACW,uBAAuB;IAwCrC;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAuB5B"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/manifest/generator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAwB/D;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IAErC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAG9B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAG/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC;AAuCD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B;;OAEG;IACG,QAAQ,CACZ,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,mBAAmB,CAAC;IAkC/B,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,iBAAiB;IAmBzB;;OAEG;YACW,aAAa;IAc3B;;OAEG;YACW,gBAAgB;IAoD9B;;;;;OAKG;YACW,oBAAoB;IA0ElC;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAiCtB;;OAEG;YACW,WAAW;IAyCzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAuCxB;;OAEG;YACW,yBAAyB;IA6EvC;;OAEG;YACW,uBAAuB;IAwCrC;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAuB5B"}