@tigerdata/mcp-boilerplate 1.6.0 → 1.6.2

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 (57) hide show
  1. package/dist/StatusError.js +1 -0
  2. package/dist/StatusError.js.map +1 -0
  3. package/dist/cliEntrypoint.js +1 -0
  4. package/dist/cliEntrypoint.js.map +1 -0
  5. package/dist/eslintPlugin.js +1 -0
  6. package/dist/eslintPlugin.js.map +1 -0
  7. package/dist/http/api.js +1 -0
  8. package/dist/http/api.js.map +1 -0
  9. package/dist/http/mcp.js +1 -0
  10. package/dist/http/mcp.js.map +1 -0
  11. package/dist/httpServer.js +1 -0
  12. package/dist/httpServer.js.map +1 -0
  13. package/dist/httpServer.spec.js +1 -0
  14. package/dist/httpServer.spec.js.map +1 -0
  15. package/dist/index.js +1 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/instrumentation.js +1 -0
  18. package/dist/instrumentation.js.map +1 -0
  19. package/dist/logger.js +1 -0
  20. package/dist/logger.js.map +1 -0
  21. package/dist/mcpServer.js +1 -0
  22. package/dist/mcpServer.js.map +1 -0
  23. package/dist/migrate.js +1 -0
  24. package/dist/migrate.js.map +1 -0
  25. package/dist/registerExitHandlers.js +1 -0
  26. package/dist/registerExitHandlers.js.map +1 -0
  27. package/dist/skills/index.js +1 -0
  28. package/dist/skills/index.js.map +1 -0
  29. package/dist/skills/prompts.js +1 -0
  30. package/dist/skills/prompts.js.map +1 -0
  31. package/dist/skills/resource.js +1 -0
  32. package/dist/skills/resource.js.map +1 -0
  33. package/dist/skills/tool.js +1 -0
  34. package/dist/skills/tool.js.map +1 -0
  35. package/dist/skills/tool.spec.js +1 -0
  36. package/dist/skills/tool.spec.js.map +1 -0
  37. package/dist/skills/types.js +1 -0
  38. package/dist/skills/types.js.map +1 -0
  39. package/dist/skills/utils.d.ts +1 -0
  40. package/dist/skills/utils.js +16 -2
  41. package/dist/skills/utils.js.map +1 -0
  42. package/dist/skills/utils.spec.js +1 -0
  43. package/dist/skills/utils.spec.js.map +1 -0
  44. package/dist/stdio.js +1 -0
  45. package/dist/stdio.js.map +1 -0
  46. package/dist/store.d.ts +1 -0
  47. package/dist/store.js +12 -7
  48. package/dist/store.js.map +1 -0
  49. package/dist/testSetup.js +1 -0
  50. package/dist/testSetup.js.map +1 -0
  51. package/dist/tracing.js +1 -0
  52. package/dist/tracing.js.map +1 -0
  53. package/dist/types.js +1 -0
  54. package/dist/types.js.map +1 -0
  55. package/dist/types.spec.js +1 -0
  56. package/dist/types.spec.js.map +1 -0
  57. package/package.json +1 -1
@@ -5,3 +5,4 @@ export class StatusError extends Error {
5
5
  this.status = status;
6
6
  }
7
7
  }
8
+ //# sourceMappingURL=StatusError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusError.js","sourceRoot":"","sources":["../src/StatusError.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,WAAY,SAAQ,KAAK;IAG3B;IAFT,YACE,OAAe,EACR,SAAS,GAAG;QAEnB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFR,WAAM,GAAN,MAAM,CAAM;IAGrB,CAAC;CACF","sourcesContent":["export class StatusError extends Error {\n constructor(\n message: string,\n public status = 500,\n ) {\n super(message);\n }\n}\n"]}
@@ -47,3 +47,4 @@ export async function cliEntrypoint(stdioEntrypoint, httpEntrypoint, instrumenta
47
47
  process.exit(1);
48
48
  }
49
49
  }
50
+ //# sourceMappingURL=cliEntrypoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliEntrypoint.js","sourceRoot":"","sources":["../src/cliEntrypoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGlC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,eAAuB,EACvB,cAAsB,EACtB,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,EACzD,QAA2B;IAE3B,qCAAqC;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IACtC,IAAI,CAAC;QACH,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;YACxD,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YAC/B,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;QACvC,CAAC;QAED,wFAAwF;QACxF,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,kCAAkC;gBAClC,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;gBAC9B,MAAM;YACR,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,IAAI,OAA0C,CAAC;gBAC/C,IACE,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;oBAC7B,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,MAAM,EACvD,CAAC;oBACD,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;oBACrD,CAAC,EAAE,OAAO,EAAE,GAAG,UAAU,EAAE,CAAC,CAAC;gBAC/B,CAAC;gBACD,iCAAiC;gBACjC,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;gBAC3D,IAAI,OAAO,IAAI,iBAAiB,EAAE,CAAC;oBACjC,iBAAiB,CAAC,OAAO,CAAC,CAAC;gBAC7B,CAAC;gBACD,MAAM;YACR,CAAC;YACD,OAAO,CAAC,CAAC,CAAC;gBACR,OAAO,CAAC,KAAK,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC;gBAC/C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC","sourcesContent":["import { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { log } from './logger.js';\nimport type { MigrationsConfig } from './types.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport async function cliEntrypoint(\n stdioEntrypoint: string,\n httpEntrypoint: string,\n instrumentation = join(__dirname, './instrumentation.js'),\n dbConfig?: MigrationsConfig,\n): Promise<void> {\n // Parse command line arguments first\n const args = process.argv.slice(2);\n const scriptName = args[0] || 'stdio';\n try {\n if (dbConfig) {\n const { createMigrator } = await import('./migrate.js');\n log.info('starting server...');\n await createMigrator(dbConfig).run();\n }\n\n // Dynamically import only the requested module to prevent all modules from initializing\n switch (scriptName) {\n case 'stdio': {\n // Import and run the stdio server\n await import(stdioEntrypoint);\n break;\n }\n case 'http': {\n let cleanup: (() => Promise<void>) | undefined;\n if (\n args.includes('--instrument') ||\n process.env.INSTRUMENT?.toLowerCase().trim() === 'true'\n ) {\n const { instrument } = await import(instrumentation);\n ({ cleanup } = instrument());\n }\n // Import and run the HTTP server\n const { registerCleanupFn } = await import(httpEntrypoint);\n if (cleanup && registerCleanupFn) {\n registerCleanupFn(cleanup);\n }\n break;\n }\n default: {\n console.error(`Unknown script: ${scriptName}`);\n console.log('Available scripts:');\n console.log('- stdio');\n console.log('- http');\n process.exit(1);\n }\n }\n } catch (error) {\n console.error('Error running script:', error);\n process.exit(1);\n }\n}\n"]}
@@ -154,3 +154,4 @@ export const rules = {
154
154
  export default {
155
155
  rules,
156
156
  };
157
+ //# sourceMappingURL=eslintPlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslintPlugin.js","sourceRoot":"","sources":["../src/eslintPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * TypeScript ESLint plugin for custom rules specific to this project\n */\n\nimport type { TSESTree } from '@typescript-eslint/typescript-estree';\nimport type { Rule } from 'eslint';\nimport type * as ESTree from 'estree';\n\n/**\n * Rule: no-optional-in-input-schema\n *\n * Detects when `.optional()`, `.default()`, or `.nullish()` are called on zod schemas\n * that are used in the `inputSchema` property of ApiFactory config objects.\n *\n * Some LLMs (like GPT-5) require all tool input parameters to be marked as required\n * in the schema, otherwise the tools become completely unusable. Using .optional(),\n * .default(), or .nullish() makes parameters optional in the JSON schema, breaking\n * compatibility with these LLMs.\n */\nconst noOptionalInputSchema: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow .optional(), .default(), and .nullish() on zod schemas in ApiFactory inputSchema',\n recommended: true,\n },\n messages: {\n noOptional:\n 'Avoid using .optional(), .default(), or .nullish() on zod schemas in inputSchema. Some LLMs (like GPT-5) require all tool parameters to be marked as required, and tools become unusable otherwise. Use .nullable() instead if you need to accept null values, or handle empty/missing values in your function implementation.',\n },\n schema: [], // no options\n },\n create(context: Rule.RuleContext): Rule.RuleListener {\n // Track variables that are used as the Input type parameter in ApiFactory<Context, Input, Output>\n const apiFactoryInputSchemas = new Set<string>();\n const problematicCalls: ESTree.CallExpression[] = [];\n\n return {\n // Detect ApiFactory type annotations and extract the Input type parameter\n VariableDeclarator(node: ESTree.Node): void {\n const varNode = node as ESTree.VariableDeclarator;\n\n // Check if this variable has a TypeScript type annotation\n if (\n varNode.id &&\n (varNode.id as TSESTree.Identifier).typeAnnotation?.typeAnnotation\n ) {\n const typeAnn = (varNode.id as TSESTree.Identifier).typeAnnotation\n ?.typeAnnotation;\n\n // Look for ApiFactory type reference\n if (\n typeAnn?.type === 'TSTypeReference' &&\n typeAnn.typeName &&\n 'name' in typeAnn.typeName &&\n typeAnn.typeName.name === 'ApiFactory'\n ) {\n // Get the type parameters\n const typeParams = typeAnn.typeArguments?.params;\n if (typeParams && typeParams.length >= 2) {\n const inputTypeParam = typeParams[1];\n\n // Check if it's a typeof reference (e.g., typeof inputSchema2)\n if (\n inputTypeParam.type === 'TSTypeQuery' &&\n inputTypeParam.exprName?.type === 'Identifier'\n ) {\n apiFactoryInputSchemas.add(inputTypeParam.exprName.name);\n }\n }\n }\n }\n },\n\n // Collect all .optional(), .default(), and .nullish() calls on zod schemas\n CallExpression(node: ESTree.Node): void {\n const callNode = node as ESTree.CallExpression;\n\n // Check if this is a .optional(), .default(), or .nullish() call\n if (callNode.callee.type === 'MemberExpression') {\n const memberNode = callNode.callee;\n if (\n memberNode.property.type === 'Identifier' &&\n ['optional', 'default', 'nullish'].includes(\n memberNode.property.name,\n )\n ) {\n // Check if it's being called on a zod schema\n const isZodSchema = isLikelyZodSchema(memberNode.object);\n if (isZodSchema) {\n problematicCalls.push(callNode);\n }\n }\n }\n },\n\n // After processing the entire file, check all problematic calls\n 'Program:exit'(): void {\n for (const node of problematicCalls) {\n if (\n isInsideApiFactoryInputSchema(node, context, apiFactoryInputSchemas)\n ) {\n const memberNode = node.callee as ESTree.MemberExpression;\n context.report({\n node: memberNode.property as ESTree.Node,\n messageId: 'noOptional',\n });\n }\n }\n },\n };\n },\n};\n\n/**\n * Check if a node is inside a schema that's used as an ApiFactory Input type parameter\n */\nfunction isInsideApiFactoryInputSchema(\n node: ESTree.Node,\n context: Rule.RuleContext,\n apiFactoryInputSchemas: Set<string>,\n): boolean {\n const sourceCode = context.sourceCode;\n const ancestors = sourceCode?.getAncestors?.(node) ?? [];\n\n // Check ancestors for variables that are ApiFactory input schemas\n for (const ancestor of ancestors) {\n // Check if ancestor is a VariableDeclarator whose name is in apiFactoryInputSchemas\n if (ancestor.type === 'VariableDeclarator') {\n const varNode = ancestor as ESTree.VariableDeclarator;\n if (\n varNode.id?.type === 'Identifier' &&\n apiFactoryInputSchemas.has((varNode.id as ESTree.Identifier).name)\n ) {\n return true;\n }\n }\n }\n\n // Fallback: walk up parent chain if node.parent is available\n type NodeWithParent = ESTree.Node & { parent?: ESTree.Node };\n let current = (node as NodeWithParent).parent;\n while (current) {\n // Variable that's an ApiFactory input schema\n if (current.type === 'VariableDeclarator') {\n const varNode = current as ESTree.VariableDeclarator;\n if (\n varNode.id?.type === 'Identifier' &&\n apiFactoryInputSchemas.has((varNode.id as ESTree.Identifier).name)\n ) {\n return true;\n }\n }\n\n current = (current as NodeWithParent).parent;\n }\n\n return false;\n}\n\n/**\n * Heuristic to determine if a node is likely a zod schema\n */\nfunction isLikelyZodSchema(\n node: ESTree.Node | ESTree.Expression | ESTree.PrivateIdentifier,\n): boolean {\n if (!node || node.type === 'PrivateIdentifier') return false;\n\n // Direct z identifier (the base of all zod schemas)\n if (node.type === 'Identifier') {\n return node.name === 'z';\n }\n\n // Direct z.* calls (e.g., z.string)\n if (node.type === 'MemberExpression') {\n if (node.object.type === 'Identifier' && node.object.name === 'z') {\n return true;\n }\n // Member expressions that might be chained zod methods (e.g., z.string)\n return isLikelyZodSchema(node.object);\n }\n\n // Chained method calls on zod schemas (e.g., z.string().describe())\n if (node.type === 'CallExpression') {\n if (node.callee.type === 'MemberExpression') {\n // Recursively check the object of the member expression\n return isLikelyZodSchema(node.callee.object);\n }\n // Also check if the callee itself is 'z'\n if (node.callee.type === 'Identifier') {\n return node.callee.name === 'z';\n }\n }\n\n return false;\n}\n\nexport const rules = {\n 'no-optional-input-schema': noOptionalInputSchema,\n};\n\nexport default {\n rules,\n};\n"]}
package/dist/http/api.js CHANGED
@@ -35,3 +35,4 @@ export const apiRouterFactory = async (context, apiFactories) => {
35
35
  }
36
36
  return [router, () => { }];
37
37
  };
38
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/http/api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,OAAgB,EAChB,YAAgD,EAClB,EAAE;IAChC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IAE9B,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,SAAS;QAE1C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;YACjD,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAChD,MAAM,KAAK,GAAG;gBACZ,GAAG,GAAG,CAAC,MAAM;gBACb,GAAG,GAAG,CAAC,KAAK;gBACZ,GAAG,GAAG,CAAC,IAAI;aACZ,CAAC;YAEF,IAAI,WAAkC,CAAC;YACvC,IAAI,CAAC;gBACH,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,KAAK,EAAE,wBAAwB;oBAC/B,MAAM,EAAG,KAAoB,CAAC,MAAM;iBACrC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,MAAM,EAAE,GAAS,EAAE,GAAE,CAAC,CAAC,CAAC;AAClC,CAAC,CAAC","sourcesContent":["/**\n * REST API alternative to MCP for direct use of the same tools.\n */\n\nimport bodyParser from 'body-parser';\nimport { Router } from 'express';\nimport { z } from 'zod';\nimport type { BaseApiFactory, RouterFactoryResult } from '../types.js';\n\nexport const apiRouterFactory = async <Context extends Record<string, unknown>>(\n context: Context,\n apiFactories: readonly BaseApiFactory<Context>[],\n): Promise<RouterFactoryResult> => {\n const router = Router();\n\n router.use(bodyParser.json());\n\n for (const factory of apiFactories) {\n const tool = await factory(context, {});\n if (!tool.method || !tool.route) continue;\n\n router[tool.method](tool.route, async (req, res) => {\n const Input = z.object(tool.config.inputSchema);\n const input = {\n ...req.params,\n ...req.query,\n ...req.body,\n };\n\n let parsedInput: z.infer<typeof Input>;\n try {\n parsedInput = Input.parse(input);\n } catch (error) {\n res.status(400).json({\n error: 'zod validation failure',\n issues: (error as z.ZodError).issues,\n });\n return;\n }\n const result = await tool.fn(parsedInput);\n res.json(tool.pickResult ? tool.pickResult(result) : result);\n });\n }\n\n return [router, (): void => {}];\n};\n"]}
package/dist/http/mcp.js CHANGED
@@ -229,3 +229,4 @@ export const mcpRouterFactory = (context, createServer, { name, stateful = true,
229
229
  };
230
230
  return [router, cleanup];
231
231
  };
232
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/http/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';\nimport {\n context as otelContext,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n} from '@opentelemetry/api';\nimport { ATTR_HTTP_RESPONSE_STATUS_CODE } from '@opentelemetry/semantic-conventions';\nimport { type Request, type Response, Router } from 'express';\nimport getRawBody from 'raw-body';\nimport { log } from '../logger.js';\nimport type {\n McpFeatureFlags,\n ParsedQs,\n RouterFactoryResult,\n} from '../types.js';\n\nconst name = process.env.OTEL_SERVICE_NAME;\nconst tracer = trace.getTracer(name ? `${name}.router.mcp` : 'router.mcp');\n\nexport const mcpRouterFactory = <Context extends Record<string, unknown>>(\n context: Context,\n createServer: (\n context: Context,\n featureFlags: McpFeatureFlags,\n ) => Promise<{ server: McpServer }>,\n {\n name,\n stateful = true,\n inspector = false,\n }: {\n name?: string;\n stateful?: boolean;\n inspector?: boolean;\n } = {},\n): RouterFactoryResult => {\n const router = Router();\n\n const transports: Map<string, StreamableHTTPServerTransport> = new Map<\n string,\n StreamableHTTPServerTransport\n >();\n\n const sessionFeatureFlags: Map<string, McpFeatureFlags> = new Map<\n string,\n McpFeatureFlags\n >();\n\n const toSet = (flag: ParsedQs[string]): Set<string> | null =>\n flag\n ? Array.isArray(flag)\n ? new Set(flag as string[])\n : typeof flag === 'string'\n ? new Set(flag.split(',').map((s) => s.trim()))\n : null\n : null;\n\n const parseFeatureFlags = (req: Request): McpFeatureFlags => ({\n prompts: req.query.prompts !== 'false' && req.query.prompts !== '0',\n enabledPrompts: toSet(req.query.enabled_prompts),\n disabledPrompts: toSet(req.query.disabled_prompts),\n resources: req.query.resources !== 'false' && req.query.resources !== '0',\n enabledResources: toSet(req.query.enabled_resources),\n disabledResources: toSet(req.query.disabled_resources),\n tools: req.query.tools !== 'false' && req.query.tools !== '0',\n enabledTools: toSet(req.query.enabled_tools),\n disabledTools: toSet(req.query.disabled_tools),\n query: req.query,\n });\n\n const handleStatelessRequest = async (\n req: Request,\n res: Response,\n ): Promise<void> => {\n const featureFlags = parseFeatureFlags(req);\n const { server } = await createServer(context, featureFlags);\n const transport: StreamableHTTPServerTransport =\n new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n });\n res.on('close', () => {\n transport.close();\n server.close();\n });\n await server.connect(transport);\n await transport.handleRequest(req, res, req.body);\n };\n\n const handleStatefulRequest = async (\n req: Request,\n res: Response,\n ): Promise<void> => {\n const sessionId = req.headers['mcp-session-id'] as string | undefined;\n let transport: StreamableHTTPServerTransport;\n let body = req.body;\n\n if (sessionId) {\n const t = transports.get(sessionId);\n if (!t) {\n res.status(404).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Not Found: No session found for that ID',\n },\n id: sessionId,\n });\n return;\n }\n transport = t;\n } else {\n if (!body) {\n body = await getRawBody(req, {\n limit: '4mb',\n encoding: 'utf-8',\n });\n body = JSON.parse(body.toString());\n }\n if (!isInitializeRequest(body)) {\n res.status(400).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Invalid request: Missing session ID',\n },\n id: null,\n });\n return;\n }\n\n const featureFlags = parseFeatureFlags(req);\n\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: (): string => randomUUID(),\n onsessioninitialized: (sessionId: string): void => {\n log.info(`Session initialized with ID: ${sessionId}`);\n transports.set(sessionId, transport);\n sessionFeatureFlags.set(sessionId, featureFlags);\n },\n onsessionclosed: (sessionId: string): void => {\n if (sessionId && transports.has(sessionId)) {\n log.info(\n `Transport closed for session ${sessionId}, removing from transports map`,\n );\n transports.delete(sessionId);\n sessionFeatureFlags.delete(sessionId);\n }\n },\n });\n\n const { server } = await createServer(context, featureFlags);\n await server.connect(transport);\n }\n\n await transport.handleRequest(req, res, body);\n };\n\n router.post('/', async (req: Request, res: Response) => {\n let traceContext = otelContext.active();\n if (req.headers.traceparent) {\n // Some MCP clients (e.g. pydantic) pass the parent trace context\n traceContext = propagation.extract(traceContext, {\n traceparent: req.headers.traceparent,\n });\n }\n await tracer.startActiveSpan(\n 'mcp.http.post',\n { kind: SpanKind.SERVER },\n traceContext,\n async (span) => {\n try {\n await (stateful\n ? handleStatefulRequest(req, res)\n : handleStatelessRequest(req, res));\n span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, res.statusCode);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (error) {\n log.error('Error handling MCP request:', error as Error);\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n });\n if (!res.headersSent) {\n res.status(500).json({\n jsonrpc: '2.0',\n error: {\n code: -32603,\n message: 'Internal server error',\n },\n id: null,\n });\n }\n } finally {\n span.end();\n }\n },\n );\n });\n\n // Reusable handler for GET and DELETE requests\n const handleSessionRequest = async (\n req: Request,\n res: Response,\n ): Promise<void> => {\n const sessionId = req.headers['mcp-session-id'] as string | undefined;\n if (!stateful) {\n res.status(405).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Method not allowed.',\n },\n id: null,\n });\n return;\n }\n\n if (!sessionId) {\n res.status(400).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Invalid request: Missing session ID',\n },\n id: null,\n });\n return;\n }\n\n if (!transports.get(sessionId)) {\n res.status(404).json({\n jsonrpc: '2.0',\n error: {\n code: -32000,\n message: 'Not Found: No session found for that ID',\n },\n id: sessionId,\n });\n return;\n }\n\n await transports.get(sessionId)?.handleRequest(req, res);\n };\n\n // Handle GET requests for server-to-client notifications via SSE\n router.get('/', (req, res) => {\n if (req.accepts('html')) {\n const proto = req.headers['x-forwarded-proto'] || req.protocol;\n const host = req.headers['x-forwarded-host'] || req.get('host');\n const path =\n req.headers['x-original-request-uri'] ||\n req.headers['x-original-uri'] ||\n req.originalUrl;\n const fullUrl = `${proto}://${host}${path}`;\n res.send(`<!DOCTYPE html>\n<html>\n<head>\n <link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/water.css@2/out/water.css\">\n</head>\n<body>\n <h1>${name}</h1>\n <h2>Model Context Protocol (MCP) Server</h2>\n <p>This endpoint is used for MCP communication. Please use an MCP-compatible client to interact with this server.</p>\n ${\n inspector\n ? `\n <h3>Inspector</h3>\n <p>You can use the <a href=\"/inspector?server=${encodeURIComponent(fullUrl)}\">MCP Inspector</a> for testing purposes.</p>`\n : ''\n }\n <h3>Claude Code</h3>\n <p>To connect to this MCP server using Claude Code, run the following command in your terminal:</p>\n <pre><code>claude mcp add --transport http ${name || req.get('host')} ${fullUrl}</code></pre>\n</body>\n</html>`);\n return;\n }\n handleSessionRequest(req, res);\n });\n\n // Handle DELETE requests for session termination\n router.delete('/', handleSessionRequest);\n\n const cleanup = async (): Promise<void> => {\n // Close all active transports to properly clean up resources\n for (const sessionId in transports) {\n try {\n log.info(`Closing transport for session ${sessionId}`);\n await transports.get(sessionId)?.close();\n transports.delete(sessionId);\n } catch (error) {\n log.error(\n `Error closing transport for session ${sessionId}:`,\n error as Error,\n );\n }\n }\n };\n\n return [router, cleanup];\n};\n"]}
@@ -163,3 +163,4 @@ export const httpServerFactory = async ({ name, version, context, apiFactories =
163
163
  },
164
164
  };
165
165
  };
166
+ //# sourceMappingURL=httpServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpServer.js","sourceRoot":"","sources":["../src/httpServer.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\nimport type { Server } from 'node:http';\nimport { hostHeaderValidation } from '@modelcontextprotocol/sdk/server/middleware/hostHeaderValidation.js';\nimport bodyParser from 'body-parser';\nimport express, {\n type NextFunction,\n type Request,\n type RequestHandler,\n type Response,\n type Router,\n} from 'express';\nimport { apiRouterFactory } from './http/api.js';\nimport { mcpRouterFactory } from './http/mcp.js';\nimport { log } from './logger.js';\nimport { type AdditionalSetupArgs, mcpServerFactory } from './mcpServer.js';\nimport { registerExitHandlers } from './registerExitHandlers.js';\nimport { StatusError } from './StatusError.js';\nimport type {\n BaseApiFactory,\n BasePromptFactory,\n ResourceFactory,\n} from './types.js';\n\ninterface HttpServerOptions<Context extends Record<string, unknown>> {\n name: string;\n version?: string;\n context: Context;\n apiFactories?: readonly BaseApiFactory<Context>[];\n promptFactories?: readonly BasePromptFactory<Context>[];\n resourceFactories?: readonly ResourceFactory<Context>[];\n additionalSetup?: (args: AdditionalSetupArgs<Context>) => void;\n cleanupFn?: () => void | Promise<void>;\n stateful?: boolean;\n instructions?: string;\n /**\n * When provided, mount routers on this app/router instead of creating a new\n * one. The caller owns the server lifecycle — `httpServerFactory` will not\n * call `app.listen()`. The returned `server` will be `null`.\n */\n app?: Router;\n /**\n * Path to mount the MCP router at. Defaults to `\"/mcp\"`.\n */\n mcpPath?: string;\n /**\n * Path to mount the API router at. Defaults to `\"/api\"`.\n */\n apiPath?: string;\n /**\n * DNS rebinding protection via Host header validation. DNS rebinding\n * attacks can bypass the browser same-origin policy by pointing a domain at\n * a localhost address, letting a malicious website reach a local server.\n * Validating the Host header against an allow-list prevents this. This is\n * especially important for servers without authorization or HTTPS.\n *\n * Protection is **disabled by default** (opt-in). This library is primarily\n * used by hosted MCP servers served on arbitrary public hostnames, where a\n * Host allow-list would reject legitimate traffic and the DNS rebinding\n * threat (a victim's browser reaching an unauthenticated `localhost`\n * server) does not apply. Localhost/development servers should opt in.\n *\n * The `MCP_ALLOWED_HOSTS` environment variable (a comma-separated list of\n * hostnames) is consulted when this option is omitted or `true`, and is\n * ignored when an explicit `string[]` or `false` is passed:\n *\n * - omitted (default): disabled, unless `MCP_ALLOWED_HOSTS` is set — in\n * which case protection is enabled using that allow-list.\n * - `true`: enabled. Uses the `MCP_ALLOWED_HOSTS` allow-list when set,\n * otherwise defaults to localhost (`localhost`, `127.0.0.1`, `[::1]`).\n * - `string[]`: enabled, validating against exactly these hostnames\n * (`MCP_ALLOWED_HOSTS` is ignored). Hostnames only, without ports; for\n * IPv6, use bracket notation (e.g. `\"[::1]\"`).\n * - `false`: disabled. Always wins, even if `MCP_ALLOWED_HOSTS` is set.\n */\n dnsRebindingProtection?: boolean | readonly string[];\n /**\n * Network interface (hostname or IP address) to bind the HTTP server to.\n * Forwarded to `app.listen()`. For example, `\"127.0.0.1\"` restricts the\n * server to loopback so it is unreachable from other machines — a strong,\n * OS-level defense for localhost/development servers.\n *\n * Defaults to the `HOST` environment variable, or undefined (bind all\n * available interfaces) when unset. Ignored when an external `app` is\n * provided, since the caller owns the server lifecycle.\n */\n host?: string;\n}\n\nconst LOCALHOST_HOSTNAMES = ['localhost', '127.0.0.1', '[::1]'];\n\nconst hostnamesFromEnv = (): string[] | null => {\n const fromEnv = process.env.MCP_ALLOWED_HOSTS?.split(',')\n .map((hostname) => hostname.trim())\n .filter(Boolean);\n return fromEnv?.length ? fromEnv : null;\n};\n\n/**\n * Resolves the Host header allow-list for DNS rebinding protection.\n * Returns `null` when protection is disabled. Protection is disabled by\n * default (opt-in); it is enabled by passing `true`, passing an explicit\n * allow-list, or setting the `MCP_ALLOWED_HOSTS` environment variable.\n */\nconst resolveAllowedHostnames = (\n dnsRebindingProtection: boolean | readonly string[] | undefined,\n): string[] | null => {\n // Explicit custom allow-list.\n if (Array.isArray(dnsRebindingProtection)) {\n return [...dnsRebindingProtection];\n }\n // Explicit opt-out wins over the env var.\n if (dnsRebindingProtection === false) {\n return null;\n }\n // Explicitly enabled: use the env-configured allow-list when present,\n // otherwise fall back to localhost-only.\n if (dnsRebindingProtection === true) {\n return hostnamesFromEnv() ?? [...LOCALHOST_HOSTNAMES];\n }\n // Disabled by default (omitted), unless the env var opts in.\n return hostnamesFromEnv();\n};\n\ninterface HttpServerResult {\n app: Router;\n /** `null` when an external `app` was provided (caller owns the server). */\n server: Server | null;\n apiRouter: express.Router;\n mcpRouter: express.Router;\n registerCleanupFn: (fn: () => Promise<void>) => void;\n}\n\nexport const httpServerFactory = async <\n Context extends Record<string, unknown>,\n>({\n name,\n version,\n context,\n apiFactories = [],\n promptFactories,\n resourceFactories,\n additionalSetup,\n cleanupFn,\n stateful = true,\n instructions,\n app: externalApp,\n mcpPath = '/mcp',\n apiPath = '/api',\n dnsRebindingProtection,\n host = process.env.HOST,\n}: HttpServerOptions<Context>): Promise<HttpServerResult> => {\n const cleanupFns: (() => void | Promise<void>)[] = cleanupFn\n ? [cleanupFn]\n : [];\n const exitHandler = registerExitHandlers(cleanupFns);\n\n let app: Router;\n let ownApp: express.Express | undefined;\n if (externalApp) {\n app = externalApp;\n } else {\n ownApp = express();\n ownApp.enable('trust proxy');\n app = ownApp;\n }\n\n const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3001;\n if (!Number.isInteger(PORT) || PORT < 0 || PORT > 65535) {\n throw new Error(`Invalid PORT environment variable: ${process.env.PORT}`);\n }\n\n // DNS rebinding protection: validate the Host header against an allow-list.\n // Scoped to the MCP and API mount paths so callers providing an external\n // app keep full control over their other routes.\n const allowedHostnames = resolveAllowedHostnames(dnsRebindingProtection);\n const hostValidation: RequestHandler | null = allowedHostnames\n ? hostHeaderValidation(allowedHostnames)\n : null;\n if (allowedHostnames) {\n log.info('DNS rebinding protection enabled', { allowedHostnames });\n }\n\n const inspector =\n process.env.NODE_ENV !== 'production' ||\n ['1', 'true'].includes(process.env.ENABLE_INSPECTOR ?? '0');\n\n const [mcpRouter, mcpCleanup] = mcpRouterFactory(\n context,\n (context, featureFlags) =>\n mcpServerFactory({\n name,\n version,\n context,\n apiFactories,\n promptFactories,\n resourceFactories,\n additionalSetup,\n featureFlags,\n instructions,\n }),\n { name, stateful, inspector },\n );\n cleanupFns.push(mcpCleanup);\n if (hostValidation) {\n app.use(mcpPath, hostValidation);\n }\n app.use(mcpPath, mcpRouter);\n\n const [apiRouter, apiCleanup] = await apiRouterFactory(context, apiFactories);\n cleanupFns.push(apiCleanup);\n if (hostValidation) {\n app.use(apiPath, hostValidation);\n }\n app.use(apiPath, apiRouter);\n\n // Error handler\n app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {\n if (err instanceof StatusError && err.status < 500) {\n log.info('HTTP error response', {\n message: err.message,\n status: err.status,\n });\n } else {\n log.error('Unexpected HTTP handler error', err);\n }\n res\n .status(err instanceof StatusError ? err.status : 500)\n .json({ error: err.message });\n });\n\n if (inspector && 'listen' in app) {\n const expressApp = app as express.Express;\n process.env.MCP_USE_ANONYMIZED_TELEMETRY = 'false';\n import('@mcp-use/inspector')\n .then(({ mountInspector }) => {\n expressApp.use(bodyParser.json());\n mountInspector(expressApp, {\n autoConnectUrl:\n process.env.MCP_PUBLIC_URL ?? `http://localhost:${PORT}/mcp`,\n });\n })\n .catch(log.error);\n }\n\n // When an external app is provided, the caller owns the server lifecycle.\n if (externalApp) {\n return {\n app,\n server: null,\n apiRouter,\n mcpRouter,\n registerCleanupFn: (fn: () => Promise<void>): void => {\n cleanupFns.push(fn);\n },\n };\n }\n\n // Start the server (ownApp is guaranteed to exist here — we returned early for external apps)\n if (!ownApp) throw new Error('Expected own Express app');\n const onListen = async (error?: Error): Promise<void> => {\n if (error) {\n log.error('Error starting HTTP server:', error);\n exitHandler(1);\n } else {\n log.info(\n `HTTP Server listening on ${host ? `${host}:${PORT}` : `port ${PORT}`}`,\n );\n if (inspector) {\n log.info(\n `🌐 MCP inspector running at http://localhost:${PORT}/inspector`,\n );\n }\n }\n };\n // `app.listen` overloads differ by whether a host is provided; calling with\n // an explicit `undefined` host binds all interfaces (Node's default).\n const server = host\n ? ownApp.listen(PORT, host, onListen)\n : ownApp.listen(PORT, onListen);\n cleanupFns.push(\n () =>\n new Promise<void>((resolve, reject) => {\n server.close((error) => (error ? reject(error) : resolve()));\n }),\n );\n\n return {\n app,\n server,\n apiRouter,\n mcpRouter,\n registerCleanupFn: (fn: () => Promise<void>): void => {\n cleanupFns.push(fn);\n },\n };\n};\n"]}
@@ -133,3 +133,4 @@ describe('httpServerFactory interface binding', () => {
133
133
  }
134
134
  });
135
135
  });
136
+ //# sourceMappingURL=httpServer.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpServer.spec.js","sourceRoot":"","sources":["../src/httpServer.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, describe, expect, it } from 'bun:test';\nimport express from 'express';\nimport { httpServerFactory } from './httpServer.js';\n\ninterface StartedServer {\n port: number;\n cleanup: () => Promise<void>;\n}\n\nconst startServer = async (\n dnsRebindingProtection: boolean | readonly string[] | undefined,\n): Promise<StartedServer> => {\n const app = express();\n await httpServerFactory({\n name: 'test-server',\n context: {},\n app,\n dnsRebindingProtection,\n });\n\n const server = app.listen(0);\n await new Promise<void>((resolve) => server.once('listening', resolve));\n const address = server.address();\n if (!address || typeof address === 'string') {\n throw new Error('Expected a TCP server address');\n }\n\n return {\n port: address.port,\n cleanup: async () => {\n await new Promise<void>((resolve, reject) => {\n server.close((err) => (err ? reject(err) : resolve()));\n });\n },\n };\n};\n\nconst postMcp = (port: number, host: string | undefined): Promise<Response> => {\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n accept: 'application/json, text/event-stream',\n };\n if (host !== undefined) {\n headers.host = host;\n }\n // Use 127.0.0.1 so the request reaches the server, while overriding the\n // Host header to exercise validation.\n return fetch(`http://127.0.0.1:${port}/mcp`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'initialize',\n params: {\n protocolVersion: '2025-06-18',\n capabilities: {},\n clientInfo: { name: 'test', version: '1.0.0' },\n },\n }),\n });\n};\n\ndescribe('httpServerFactory DNS rebinding protection', () => {\n const started: StartedServer[] = [];\n\n afterEach(async () => {\n while (started.length > 0) {\n const s = started.pop();\n await s?.cleanup();\n }\n });\n\n const track = (s: StartedServer): StartedServer => {\n started.push(s);\n return s;\n };\n\n it('rejects disallowed Host headers when protection is enabled', async () => {\n const { port } = track(await startServer(true));\n\n const res = await postMcp(port, 'evil.example.com');\n expect(res.status).toBe(403);\n const body = (await res.json()) as { error?: { message?: string } };\n expect(body.error?.message).toContain('Invalid Host');\n });\n\n it('is disabled by default when the option is omitted', async () => {\n const { port } = track(await startServer(undefined));\n\n const res = await postMcp(port, 'evil.example.com');\n expect(res.status).not.toBe(403);\n });\n\n it('allows localhost Host headers when protection is enabled', async () => {\n const { port } = track(await startServer(true));\n\n const res = await postMcp(port, `127.0.0.1:${port}`);\n // Not a 403 — the request passes Host validation and reaches the MCP\n // handler (which then negotiates the session normally).\n expect(res.status).not.toBe(403);\n });\n\n it('allows any Host header when protection is disabled', async () => {\n const { port } = track(await startServer(false));\n\n const res = await postMcp(port, 'evil.example.com');\n expect(res.status).not.toBe(403);\n });\n\n it('validates against a custom allow-list', async () => {\n const { port } = track(await startServer(['mcp.internal']));\n\n const allowed = await postMcp(port, 'mcp.internal');\n expect(allowed.status).not.toBe(403);\n\n const denied = await postMcp(port, 'localhost');\n expect(denied.status).toBe(403);\n });\n});\n\ndescribe('httpServerFactory interface binding', () => {\n it('binds to the requested host', async () => {\n const prevPort = process.env.PORT;\n process.env.PORT = '0';\n try {\n const { server } = await httpServerFactory({\n name: 'test-server',\n context: {},\n host: '127.0.0.1',\n });\n if (!server) {\n throw new Error('Expected own server');\n }\n try {\n if (!server.listening) {\n await new Promise<void>((resolve, reject) => {\n server.once('listening', resolve);\n server.once('error', reject);\n });\n }\n const address = server.address();\n if (!address || typeof address === 'string') {\n throw new Error('Expected a TCP server address');\n }\n expect(address.address).toBe('127.0.0.1');\n } finally {\n await new Promise<void>((resolve, reject) =>\n server.close((err) => (err ? reject(err) : resolve())),\n );\n }\n } finally {\n if (prevPort === undefined) {\n delete process.env.PORT;\n } else {\n process.env.PORT = prevPort;\n }\n }\n });\n});\n"]}
package/dist/index.js CHANGED
@@ -6,3 +6,4 @@ export { StatusError } from './StatusError.js';
6
6
  export { stdioServerFactory } from './stdio.js';
7
7
  export { ArrayStore, Store } from './store.js';
8
8
  export { addAiResultToSpan, withSpan } from './tracing.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export { cliEntrypoint } from './cliEntrypoint.js';\nexport { httpServerFactory } from './httpServer.js';\nexport { log } from './logger.js';\nexport type { AdditionalSetupArgs } from './mcpServer.js';\nexport { registerExitHandlers } from './registerExitHandlers.js';\nexport { StatusError } from './StatusError.js';\nexport { stdioServerFactory } from './stdio.js';\nexport { ArrayStore, Store } from './store.js';\nexport { addAiResultToSpan, withSpan } from './tracing.js';\nexport type {\n ApiFactory,\n InferSchema,\n McpFeatureFlags,\n MigrationsConfig,\n ParsedQs,\n PromptFactory,\n ResourceFactory,\n} from './types.js';\n"]}
@@ -66,3 +66,4 @@ export const instrument = (options = {}) => {
66
66
  sdk,
67
67
  };
68
68
  };
69
+ //# sourceMappingURL=instrumentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instrumentation.js","sourceRoot":"","sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getNodeAutoInstrumentations,\n type InstrumentationConfigMap,\n} from '@opentelemetry/auto-instrumentations-node';\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\nimport { OTLPTraceExporter as GrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';\nimport { OTLPTraceExporter as HttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport {\n BatchLogRecordProcessor,\n type LogRecordProcessor,\n} from '@opentelemetry/sdk-logs';\nimport { NodeSDK } from '@opentelemetry/sdk-node';\nimport {\n BatchSpanProcessor,\n type SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\nimport { log } from './logger.js';\n\ninterface Options {\n environment?: string;\n instrumentations?: Instrumentation[];\n nodeAutoInstrumentationsOptions?: InstrumentationConfigMap;\n}\n\nexport const instrument = (\n options: Options = {},\n): {\n cleanup: () => Promise<void>;\n sdk: NodeSDK;\n} => {\n const spanProcessors: SpanProcessor[] = [];\n const logRecordProcessors: LogRecordProcessor[] = [];\n\n if (process.env.OTEL_EXPORTER_OTLP_ENDPOINT) {\n spanProcessors.push(new BatchSpanProcessor(new GrpcTraceExporter()));\n }\n if (process.env.JAEGER_TRACES_ENDPOINT) {\n spanProcessors.push(\n new BatchSpanProcessor(\n new GrpcTraceExporter({\n url: process.env.JAEGER_TRACES_ENDPOINT,\n }),\n ),\n );\n }\n if (process.env.LOGFIRE_TRACES_ENDPOINT) {\n spanProcessors.push(\n new BatchSpanProcessor(\n new HttpTraceExporter({\n url: process.env.LOGFIRE_TRACES_ENDPOINT,\n headers: process.env.LOGFIRE_TOKEN\n ? { Authorization: `Bearer ${process.env.LOGFIRE_TOKEN}` }\n : {},\n }),\n ),\n );\n }\n if (process.env.LOGFIRE_LOGS_ENDPOINT) {\n logRecordProcessors.push(\n new BatchLogRecordProcessor(\n new OTLPLogExporter({\n url: process.env.LOGFIRE_LOGS_ENDPOINT,\n headers: process.env.LOGFIRE_TOKEN\n ? { Authorization: `Bearer ${process.env.LOGFIRE_TOKEN}` }\n : {},\n }),\n ),\n );\n }\n\n const sdk = new NodeSDK({\n instrumentations: options.instrumentations || [\n getNodeAutoInstrumentations(options.nodeAutoInstrumentationsOptions),\n ],\n spanProcessors,\n logRecordProcessors,\n resource: resourceFromAttributes({\n 'deployment.environment.name':\n options.environment ||\n process.env.LOGFIRE_ENVIRONMENT ||\n process.env.NODE_ENV ||\n 'development',\n 'service.instance.id': process.env.HOSTNAME,\n }),\n });\n\n // Initialize the SDK and register with the OpenTelemetry API\n sdk.start();\n\n log.info('OpenTelemetry initialized');\n\n return {\n cleanup: async (): Promise<void> => {\n try {\n await Promise.all(spanProcessors.map((sp) => sp.shutdown()));\n await Promise.all(logRecordProcessors.map((lp) => lp.shutdown()));\n await sdk.shutdown();\n log.info('OpenTelemetry terminated');\n } catch (error) {\n log.error('Error terminating OpenTelemetry', error as Error);\n }\n },\n sdk,\n };\n};\n"]}
package/dist/logger.js CHANGED
@@ -85,3 +85,4 @@ export const log = {
85
85
  });
86
86
  },
87
87
  };
88
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type LogAttributes,\n logs,\n SeverityNumber,\n} from '@opentelemetry/api-logs';\n\nconst name = process.env.OTEL_SERVICE_NAME || 'mcp-app';\nconst logger = logs.getLogger(name);\n\n// The CONSOLE_LOG_LEVEL environment variable controls the minimum severity that\n// is written to the console: 'debug', 'info', 'warn', 'error', or 'none' to\n// disable console output entirely. Defaults to 'debug' (everything). The\n// OpenTelemetry log records are always emitted regardless of this setting.\ntype ConsoleLogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\nconst consoleLogLevelSeverity: Record<ConsoleLogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n};\n\nconst configuredConsoleLogLevel = (\n process.env.CONSOLE_LOG_LEVEL || 'debug'\n).toLowerCase() as ConsoleLogLevel;\n\nif (!(configuredConsoleLogLevel in consoleLogLevelSeverity)) {\n throw new Error(\n `Invalid CONSOLE_LOG_LEVEL '${process.env.CONSOLE_LOG_LEVEL}'. ` +\n `Expected one of: ${Object.keys(consoleLogLevelSeverity).join(', ')}.`,\n );\n}\n\nconst minConsoleLogSeverity =\n consoleLogLevelSeverity[configuredConsoleLogLevel];\n\nconst writeToConsole = (\n level: Exclude<ConsoleLogLevel, 'none'>,\n ...args: Parameters<typeof console.error>\n): void => {\n if (consoleLogLevelSeverity[level] >= minConsoleLogSeverity) {\n console.error(...args);\n }\n};\n\ninterface LogInterface {\n debug: (body: string, attributes?: LogAttributes) => void;\n info: (body: string, attributes?: LogAttributes) => void;\n warn: (body: string, attributes?: LogAttributes) => void;\n error: (\n body: string,\n error?: Error | null,\n attributes?: LogAttributes,\n ) => void;\n}\n\n// Helper functions to replace console.log\n// We use console.error for all levels so that messages are written to stderr\n// and not stdout, which would interfere with the stdio MCP transport.\nexport const log: LogInterface = {\n debug: (...args) => {\n writeToConsole('debug', ...args);\n const [body, attributes] = args;\n logger.emit({\n severityText: 'DEBUG',\n severityNumber: SeverityNumber.DEBUG,\n body,\n attributes: {\n 'log.level': 'debug',\n 'service.name': name,\n ...attributes,\n },\n });\n },\n\n info: (...args) => {\n writeToConsole('info', ...args);\n const [body, attributes] = args;\n logger.emit({\n severityText: 'INFO',\n severityNumber: SeverityNumber.INFO,\n body,\n attributes: {\n 'log.level': 'info',\n 'service.name': name,\n ...attributes,\n },\n });\n },\n\n warn: (...args) => {\n writeToConsole('warn', ...args);\n const [body, attributes] = args;\n logger.emit({\n severityText: 'WARN',\n severityNumber: SeverityNumber.WARN,\n body,\n attributes: {\n 'log.level': 'warn',\n 'service.name': name,\n ...attributes,\n },\n });\n },\n\n error: (...args) => {\n writeToConsole('error', ...args);\n const [body, error, attributes] = args;\n logger.emit({\n severityText: 'ERROR',\n severityNumber: SeverityNumber.ERROR,\n body,\n attributes: {\n 'log.level': 'error',\n 'service.name': name,\n ...(error && {\n 'error.name': error.name,\n 'error.message': error.message,\n 'error.stack': error.stack,\n }),\n ...attributes,\n },\n });\n },\n};\n"]}
package/dist/mcpServer.js CHANGED
@@ -229,3 +229,4 @@ export const mcpServerFactory = async ({ name, version = '1.0.0', context, apiFa
229
229
  additionalSetup?.({ context, server, featureFlags });
230
230
  return { server };
231
231
  };
232
+ //# sourceMappingURL=mcpServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpServer.js","sourceRoot":"","sources":["../src/mcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,gBAAgB,GAEjB,MAAM,yCAAyC,CAAC;AAWjD,OAAO,EACL,OAAO,IAAI,WAAW,EACtB,WAAW,EACX,QAAQ,EACR,cAAc,EACd,KAAK,GACN,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAQlC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AAEzE,MAAM,KAAK,GAAG,CAAC,GAAuB,EAAsB,EAAE,CAC5D,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAE5D,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC1D,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAC5D,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AAC9D,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAChE,MAAM,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAClE,MAAM,iBAAiB,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;AAEpE,MAAM,UAAU,GAAG,CACjB,IAA0C,EAC1C,WAA+C,EAC/C,YAAgD,EACvC,EAAE;IACX,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC/B,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,IAAI,WAAW,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAQF,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAEnC,EACA,IAAI,EACJ,OAAO,GAAG,OAAO,EACjB,OAAO,EACP,YAAY,GAAG,EAAE,EACjB,eAAe,GAAG,EAAE,EACpB,iBAAiB,GAAG,EAAE,EACtB,eAAe,EACf,sBAAsB,GAAG,EAAE,EAC3B,YAAY,GAAG,EAAE,EACjB,YAAY,GAYb,EAAkC,EAAE;IACnC,MAAM,aAAa,GAAG,YAAY,CAAC,OAAO,KAAK,KAAK,CAAC;IACrD,MAAM,eAAe,GAAG,YAAY,CAAC,SAAS,KAAK,KAAK,CAAC;IACzD,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,KAAK,KAAK,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI;QACJ,OAAO;KACR,EACD;QACE,YAAY,EAAE;YACZ,GAAG,CAAC,WAAW,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAC9D,GAAG,CAAC,aAAa,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YACrE,GAAG,CAAC,eAAe,IAAI,iBAAiB,CAAC,MAAM;gBAC7C,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;gBACnB,CAAC,CAAC,IAAI,CAAC;YACT,GAAG,sBAAsB;SAC1B;QACD,YAAY;KACb,CACF,CAAC;IAEF,IAAI,WAAW,EAAE,CAAC;QAChB,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YAClD,IACE,UAAU,CACR,IAAI,EACJ,CAAC,YAAY,EAAE,YAAY,CAAC,YAAY,CAAC,EACzC,CAAC,aAAa,EAAE,YAAY,CAAC,aAAa,CAAC,CAC5C,EACD,CAAC;gBACD,SAAS;YACX,CAAC;YACD,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;gBACE,GAAG,IAAI,CAAC,MAAM;gBACd,WAAW,EAAE;oBACX,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW;oBAC1B,qEAAqE;oBACrE,iEAAiE;oBACjE,qEAAqE;oBACrE,cAAc;oBACd,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;iBACzB;aACF,EACD,CAAC,KAAK,EACJ,IAA6B,EAC7B,KAA6D,EACpC,EAAE;gBAC3B,IAAI,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;gBACxC,IAAI,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;oBAC9B,iEAAiE;oBACjE,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE;wBAC/C,WAAW,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW;wBACpC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,UAAU;qBACnC,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO,MAAM,CAAC,eAAe,CAC3B,YAAY,IAAI,CAAC,IAAI,EAAE,EACvB,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,EACzB,YAAY,EACZ,KAAK,EAAE,IAAI,EAA2B,EAAE;oBACtC,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;oBACzD,IAAI,CAAC;wBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;wBACnC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;wBACpC,IAAI,CAAC,YAAY,CAAC,wBAAwB,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;wBACzD,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC5C,OAAO;4BACL,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,MAAM;oCACZ,IAAI;iCACL;6BACF;4BACD,iBAAiB,EAAE,MAAM;yBAC1B,CAAC;oBACJ,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,GAAG,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAc,CAAC,CAAC;wBAClD,IAAI,CAAC,eAAe,CAAC,KAAc,CAAC,CAAC;wBACrC,IAAI,CAAC,SAAS,CAAC;4BACb,IAAI,EAAE,cAAc,CAAC,KAAK;4BAC1B,OAAO,EAAG,KAAe,CAAC,OAAO;yBAClC,CAAC,CAAC;wBACH,OAAO;4BACL,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,MAAM;oCACZ,IAAI,EAAE,UAAW,KAAe,CAAC,OAAO,IAAI,eAAe,EAAE;iCAC9D;6BACF;4BACD,OAAO,EAAE,IAAI;yBACd,CAAC;oBACJ,CAAC;4BAAS,CAAC;wBACT,IAAI,CAAC,GAAG,EAAE,CAAC;oBACb,CAAC;gBACH,CAAC,CACF,CAAC;YACJ,CAAC,CAAiD,CACnD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;YACtC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACpD,IACE,UAAU,CACR,MAAM,EACN,CAAC,cAAc,EAAE,YAAY,CAAC,cAAc,CAAC,EAC7C,CAAC,eAAe,EAAE,YAAY,CAAC,eAAe,CAAC,CAChD,EACD,CAAC;gBACD,SAAS;YACX,CAAC;YACD,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAC/D,MAAM,CAAC,eAAe,CACpB,cAAc,MAAM,CAAC,IAAI,EAAE,EAC3B,KAAK,EAAE,IAAI,EAA4B,EAAE;gBACvC,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC3D,IAAI,CAAC;oBACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,CAAC,IAA+B,CAAC,CAAC;oBAChE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC5C,OAAO,MAAM,CAAC;gBAChB,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,GAAG,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAc,CAAC,CAAC;oBACpD,IAAI,CAAC,eAAe,CAAC,KAAc,CAAC,CAAC;oBACrC,IAAI,CAAC,SAAS,CAAC;wBACb,IAAI,EAAE,cAAc,CAAC,KAAK;wBAC1B,OAAO,EAAG,KAAe,CAAC,OAAO;qBAClC,CAAC,CAAC;oBACH,MAAM,KAAK,CAAC;gBACd,CAAC;wBAAS,CAAC;oBACT,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC;YACH,CAAC,CACF,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,eAAe,EAAE,CAAC;QACpB,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACxC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACtD,IACE,UAAU,CACR,QAAQ,EACR,CAAC,gBAAgB,EAAE,YAAY,CAAC,gBAAgB,CAAC,EACjD,CAAC,iBAAiB,EAAE,YAAY,CAAC,iBAAiB,CAAC,CACpD,EACD,CAAC;gBACD,SAAS;YACX,CAAC;YACD,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACtB,KAAK,QAAQ,CAAC,CAAC,CAAC;oBACd,MAAM,CAAC,gBAAgB,CACrB,QAAQ,CAAC,IAAI,EACb,QAAQ,CAAC,GAAG,EACZ,QAAQ,CAAC,MAAM,EACf,KAAK,EAAE,GAAQ,EAAE,KAAK,EAAE,EAAE,CACxB,MAAM,CAAC,eAAe,CACpB,uBAAuB,QAAQ,CAAC,IAAI,EAAE,EACtC,KAAK,EAAE,IAAI,EAA+B,EAAE;wBAC1C,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;wBACtD,IAAI,CAAC,YAAY,CACf,oBAAoB,EACpB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CACtB,CAAC;wBACF,IAAI,CAAC;4BACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;4BAC/C,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC5C,OAAO,MAAM,CAAC;wBAChB,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,GAAG,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAc,CAAC,CAAC;4BACtD,IAAI,CAAC,eAAe,CAAC,KAAc,CAAC,CAAC;4BACrC,IAAI,CAAC,SAAS,CAAC;gCACb,IAAI,EAAE,cAAc,CAAC,KAAK;gCAC1B,OAAO,EAAG,KAAe,CAAC,OAAO;6BAClC,CAAC,CAAC;4BACH,MAAM,KAAK,CAAC;wBACd,CAAC;gCAAS,CAAC;4BACT,IAAI,CAAC,GAAG,EAAE,CAAC;wBACb,CAAC;oBACH,CAAC,CACF,CACJ,CAAC;oBACF,MAAM;gBACR,CAAC;gBACD,KAAK,WAAW,CAAC,CAAC,CAAC;oBACjB,MAAM,CAAC,gBAAgB,CACrB,QAAQ,CAAC,IAAI,EACb,IAAI,gBAAgB,CAAC,QAAQ,CAAC,WAAW,EAAE;wBACzC,IAAI,EACF,QAAQ,CAAC,IAAI;4BACb,CAAC,CAAC,KAAK,EAAgC,EAAE,CACvC,MAAM,CAAC,eAAe,CACpB,0BAA0B,QAAQ,CAAC,IAAI,OAAO,EAC9C,KAAK,EAAE,IAAI,EAAgC,EAAE;gCAC3C,IAAI,CAAC;oCACH,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;wCACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;oCAClD,CAAC;oCACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oCAC1C,IAAI,CAAC,YAAY,CACf,wBAAwB,EACxB,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC9C,CAAC;oCACF,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;oCAC5C,OAAO,MAAM,CAAC;gCAChB,CAAC;gCAAC,OAAO,KAAK,EAAE,CAAC;oCACf,GAAG,CAAC,KAAK,CACP,+BAA+B,EAC/B,KAAc,CACf,CAAC;oCACF,IAAI,CAAC,eAAe,CAAC,KAAc,CAAC,CAAC;oCACrC,IAAI,CAAC,SAAS,CAAC;wCACb,IAAI,EAAE,cAAc,CAAC,KAAK;wCAC1B,OAAO,EAAG,KAAe,CAAC,OAAO;qCAClC,CAAC,CAAC;oCACH,MAAM,KAAK,CAAC;gCACd,CAAC;wCAAS,CAAC;oCACT,IAAI,CAAC,GAAG,EAAE,CAAC;gCACb,CAAC;4BACH,CAAC,CACF,CAAC;wBACN,QAAQ,EAAE,QAAQ,CAAC,QAAQ;qBAC5B,CAAC,EACF,QAAQ,CAAC,MAAM,EACf,KAAK,EAAE,GAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CACnC,MAAM,CAAC,eAAe,CACpB,0BAA0B,QAAQ,CAAC,IAAI,EAAE,EACzC,KAAK,EAAE,IAAI,EAA+B,EAAE;wBAC1C,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;wBACtD,IAAI,CAAC,YAAY,CACf,wBAAwB,EACxB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAC1B,CAAC;wBACF,IAAI,CAAC,YAAY,CACf,oBAAoB,EACpB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CACtB,CAAC;wBACF,IAAI,CAAC;4BACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;4BAC1D,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC5C,OAAO,MAAM,CAAC;wBAChB,CAAC;wBAAC,OAAO,KAAK,EAAE,CAAC;4BACf,GAAG,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAc,CAAC,CAAC;4BACtD,IAAI,CAAC,eAAe,CAAC,KAAc,CAAC,CAAC;4BACrC,IAAI,CAAC,SAAS,CAAC;gCACb,IAAI,EAAE,cAAc,CAAC,KAAK;gCAC1B,OAAO,EAAG,KAAe,CAAC,OAAO;6BAClC,CAAC,CAAC;4BACH,MAAM,KAAK,CAAC;wBACd,CAAC;gCAAS,CAAC;4BACT,IAAI,CAAC,GAAG,EAAE,CAAC;wBACb,CAAC;oBACH,CAAC,CACF,CACJ,CAAC;oBACF,MAAM;gBACR,CAAC;gBACD,OAAO,CAAC,CAAC,CAAC;oBACR,oCAAoC;oBACpC,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,eAAe,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IAErD,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC,CAAC","sourcesContent":["import {\n McpServer,\n ResourceTemplate,\n type ToolCallback,\n} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';\nimport type {\n CallToolResult,\n GetPromptResult,\n ListResourcesResult,\n ReadResourceResult,\n ServerCapabilities,\n ServerNotification,\n ServerRequest,\n} from '@modelcontextprotocol/sdk/types.js';\nimport {\n context as otelContext,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n} from '@opentelemetry/api';\nimport { log } from './logger.js';\nimport type {\n BaseApiFactory,\n BasePromptFactory,\n McpFeatureFlags,\n ResourceFactory,\n} from './types.js';\n\nconst name = process.env.OTEL_SERVICE_NAME;\nconst tracer = trace.getTracer(name ? `${name}.mcpServer` : 'mcpServer');\n\nconst toSet = (str: string | undefined): Set<string> | null =>\n str ? new Set(str.split(',').map((s) => s.trim())) : null;\n\nconst enabledTools = toSet(process.env.MCP_ENABLED_TOOLS);\nconst disabledTools = toSet(process.env.MCP_DISABLED_TOOLS);\nconst enabledPrompts = toSet(process.env.MCP_ENABLED_PROMPTS);\nconst disabledPrompts = toSet(process.env.MCP_DISABLED_PROMPTS);\nconst enabledResources = toSet(process.env.MCP_ENABLED_RESOURCES);\nconst disabledResources = toSet(process.env.MCP_DISABLED_RESOURCES);\n\nconst shouldSkip = (\n item: { name: string; disabled?: boolean },\n enabledSets: (Set<string> | null | undefined)[],\n disabledSets: (Set<string> | null | undefined)[],\n): boolean => {\n if (item.disabled) return true;\n for (const enabledSet of enabledSets) {\n if (enabledSet && !enabledSet.has(item.name)) {\n return true;\n }\n }\n for (const disabledSet of disabledSets) {\n if (disabledSet?.has(item.name)) {\n return true;\n }\n }\n return false;\n};\n\nexport interface AdditionalSetupArgs<Context extends Record<string, unknown>> {\n context: Context;\n server: McpServer;\n featureFlags: McpFeatureFlags;\n}\n\nexport const mcpServerFactory = async <\n Context extends Record<string, unknown>,\n>({\n name,\n version = '1.0.0',\n context,\n apiFactories = [],\n promptFactories = [],\n resourceFactories = [],\n additionalSetup,\n additionalCapabilities = {},\n featureFlags = {},\n instructions,\n}: {\n name: string;\n version?: string;\n context: Context;\n apiFactories?: readonly BaseApiFactory<Context>[];\n promptFactories?: readonly BasePromptFactory<Context>[];\n resourceFactories?: readonly ResourceFactory<Context>[];\n additionalSetup?: (args: AdditionalSetupArgs<Context>) => void;\n additionalCapabilities?: ServerCapabilities;\n featureFlags?: McpFeatureFlags;\n instructions?: string;\n}): Promise<{ server: McpServer }> => {\n const enablePrompts = featureFlags.prompts !== false;\n const enableResources = featureFlags.resources !== false;\n const enableTools = featureFlags.tools !== false;\n const server = new McpServer(\n {\n name,\n version,\n },\n {\n capabilities: {\n ...(enableTools && apiFactories.length ? { tools: {} } : null),\n ...(enablePrompts && promptFactories.length ? { prompts: {} } : null),\n ...(enableResources && resourceFactories.length\n ? { resources: {} }\n : null),\n ...additionalCapabilities,\n },\n instructions,\n },\n );\n\n if (enableTools) {\n for (const factory of apiFactories) {\n const tool = await factory(context, featureFlags);\n if (\n shouldSkip(\n tool,\n [enabledTools, featureFlags.enabledTools],\n [disabledTools, featureFlags.disabledTools],\n )\n ) {\n continue;\n }\n server.registerTool(\n tool.name,\n {\n ...tool.config,\n annotations: {\n ...tool.config.annotations,\n // Some clients (e.g. claude code) do not yet support the title field\n // at the top level and instead expect it in annotations. We also\n // don't allow setting different titles in two places as that doesn't\n // make sense.\n title: tool.config.title,\n },\n },\n (async (\n args: Record<string, unknown>,\n extra: RequestHandlerExtra<ServerRequest, ServerNotification>,\n ): Promise<CallToolResult> => {\n let traceContext = otelContext.active();\n if (extra?._meta?.traceparent) {\n // Some MCP clients (e.g. pydantic) pass the parent trace context\n traceContext = propagation.extract(traceContext, {\n traceparent: extra._meta.traceparent,\n tracestate: extra._meta.tracestate,\n });\n }\n return tracer.startActiveSpan(\n `mcp.tool.${tool.name}`,\n { kind: SpanKind.SERVER },\n traceContext,\n async (span): Promise<CallToolResult> => {\n span.setAttribute('mcp.tool.args', JSON.stringify(args));\n try {\n const result = await tool.fn(args);\n const text = JSON.stringify(result);\n span.setAttribute('mcp.tool.responseBytes', text.length);\n span.setStatus({ code: SpanStatusCode.OK });\n return {\n content: [\n {\n type: 'text',\n text,\n },\n ],\n structuredContent: result,\n };\n } catch (error) {\n log.error('Error invoking tool:', error as Error);\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n });\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${(error as Error).message || 'Unknown error'}`,\n },\n ],\n isError: true,\n };\n } finally {\n span.end();\n }\n },\n );\n }) as ToolCallback<typeof tool.config.inputSchema>,\n );\n }\n }\n\n if (enablePrompts) {\n for (const factory of promptFactories) {\n const prompt = await factory(context, featureFlags);\n if (\n shouldSkip(\n prompt,\n [enabledPrompts, featureFlags.enabledPrompts],\n [disabledPrompts, featureFlags.disabledPrompts],\n )\n ) {\n continue;\n }\n server.registerPrompt(prompt.name, prompt.config, async (args) =>\n tracer.startActiveSpan(\n `mcp.prompt.${prompt.name}`,\n async (span): Promise<GetPromptResult> => {\n span.setAttribute('mcp.prompt.args', JSON.stringify(args));\n try {\n const result = await prompt.fn(args as Record<string, unknown>);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n log.error('Error invoking prompt:', error as Error);\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n });\n throw error;\n } finally {\n span.end();\n }\n },\n ),\n );\n }\n }\n\n if (enableResources) {\n for (const factory of resourceFactories) {\n const resource = await factory(context, featureFlags);\n if (\n shouldSkip(\n resource,\n [enabledResources, featureFlags.enabledResources],\n [disabledResources, featureFlags.disabledResources],\n )\n ) {\n continue;\n }\n switch (resource.type) {\n case 'static': {\n server.registerResource(\n resource.name,\n resource.uri,\n resource.config,\n async (uri: URL, extra) =>\n tracer.startActiveSpan(\n `mcp.resource.static.${resource.name}`,\n async (span): Promise<ReadResourceResult> => {\n span.setAttribute('mcp.resource.uri', uri.toString());\n span.setAttribute(\n 'mcp.resource.extra',\n JSON.stringify(extra),\n );\n try {\n const result = await resource.read(uri, extra);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n log.error('Error invoking resource:', error as Error);\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n });\n throw error;\n } finally {\n span.end();\n }\n },\n ),\n );\n break;\n }\n case 'templated': {\n server.registerResource(\n resource.name,\n new ResourceTemplate(resource.uriTemplate, {\n list:\n resource.list &&\n ((extra): Promise<ListResourcesResult> =>\n tracer.startActiveSpan(\n `mcp.resource.templated.${resource.name}.list`,\n async (span): Promise<ListResourcesResult> => {\n try {\n if (!resource.list) {\n throw new Error('resource.list is not defined');\n }\n const result = await resource.list(extra);\n span.setAttribute(\n 'mcp.resource.list.uris',\n result.resources.map((r) => r.uri).join(', '),\n );\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n log.error(\n 'Error invoking resource list:',\n error as Error,\n );\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n });\n throw error;\n } finally {\n span.end();\n }\n },\n )),\n complete: resource.complete,\n }),\n resource.config,\n async (uri: URL, variables, extra) =>\n tracer.startActiveSpan(\n `mcp.resource.templated.${resource.name}`,\n async (span): Promise<ReadResourceResult> => {\n span.setAttribute('mcp.resource.uri', uri.toString());\n span.setAttribute(\n 'mcp.resource.variables',\n JSON.stringify(variables),\n );\n span.setAttribute(\n 'mcp.resource.extra',\n JSON.stringify(extra),\n );\n try {\n const result = await resource.read(uri, variables, extra);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n log.error('Error invoking resource:', error as Error);\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n });\n throw error;\n } finally {\n span.end();\n }\n },\n ),\n );\n break;\n }\n default: {\n // @ts-expect-error exhaustive check\n throw new Error(`Unknown resource type: ${resource.type}`);\n }\n }\n }\n }\n\n additionalSetup?.({ context, server, featureFlags });\n\n return { server };\n};\n"]}
package/dist/migrate.js CHANGED
@@ -108,3 +108,4 @@ export const createMigrator = (config) => {
108
108
  }),
109
109
  };
110
110
  };
111
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'node:crypto';\nimport type { FileStore, MigrationSet } from 'migrate';\nimport migrate from 'migrate';\nimport { Client } from 'pg';\nimport { log } from './logger.js';\nimport type { MigrationsConfig } from './types.js';\n\ninterface Store extends FileStore {\n close(): Promise<void>;\n}\n\nconst createStateStore = (name: string, schema: string = 'public'): Store => {\n let client: Client;\n\n // Use a hash of the project name to create a lock\n const hash = createHash('sha256').update(name).digest('hex');\n const advisoryLockId = parseInt(hash.substring(0, 15), 16);\n\n return {\n async load(callback: Parameters<FileStore['load']>[0]): Promise<void> {\n try {\n client = new Client();\n await client.connect();\n\n // Acquire advisory lock to prevent concurrent migrations\n await client.query(/* sql */ `SELECT pg_advisory_lock($1)`, [\n advisoryLockId,\n ]);\n\n // Ensure migrations table exists\n await client.query(/* sql */ `\n CREATE SCHEMA IF NOT EXISTS ${schema};\n\n CREATE TABLE IF NOT EXISTS ${schema}.migrations (\n id SERIAL PRIMARY KEY,\n set JSONB NOT NULL,\n applied_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP\n );\n `);\n\n // Load the most recent migration set\n const result = await client.query(\n /* sql */ `SELECT set FROM ${schema}.migrations ORDER BY applied_at DESC LIMIT 1`,\n );\n\n const set = result.rows.length > 0 ? result.rows[0].set : {};\n callback(null, set);\n } catch (error) {\n callback(error as Error);\n }\n },\n\n async save(\n set: MigrationSet,\n callback: (err: Error | null) => void,\n ): Promise<void> {\n try {\n // Insert the entire set as JSONB\n await client.query(\n /* sql */ `INSERT INTO ${schema}.migrations (set) VALUES ($1)`,\n [JSON.stringify(set)],\n );\n\n callback(null);\n } catch (error) {\n callback(error as Error);\n }\n },\n\n async close(): Promise<void> {\n if (client) {\n // Release advisory lock\n await client.query(/* sql */ `SELECT pg_advisory_unlock($1)`, [\n advisoryLockId,\n ]);\n await client.end();\n }\n },\n };\n};\n\nexport const createMigrator = (config: MigrationsConfig) => {\n const { schema, migrationsDirectory, serviceName } = config;\n const stateStore = createStateStore(serviceName, schema);\n return {\n run: async () =>\n new Promise<void>((resolve, reject) => {\n log.info('Running database migrations...');\n\n // Set search_path via PGOPTIONS so every pg.Client created by migration\n // files picks it up automatically, without touching the migration files.\n const prevPgOptions = process.env.PGOPTIONS;\n if (schema) {\n process.env.PGOPTIONS =\n `${prevPgOptions ?? ''} --search_path=${schema},public`.trim();\n }\n\n const restore = () => {\n if (schema) {\n if (prevPgOptions === undefined) {\n delete process.env.PGOPTIONS;\n } else {\n process.env.PGOPTIONS = prevPgOptions;\n }\n }\n };\n\n migrate.load(\n {\n stateStore,\n migrationsDirectory: migrationsDirectory ?? './migrations',\n },\n (err, set) => {\n if (err) {\n restore();\n log.error('Database migration failed:', err as Error);\n stateStore.close().finally(() => reject(err));\n return;\n }\n\n set.up((err) => {\n restore();\n stateStore.close().finally(() => {\n if (err) {\n log.error('Database migration failed:', err as Error);\n reject(err);\n } else {\n log.info('Database migrations completed successfully');\n resolve();\n }\n });\n });\n },\n );\n }),\n };\n};\n"]}
@@ -24,3 +24,4 @@ export const registerExitHandlers = (cleanupFns) => {
24
24
  });
25
25
  return exitHandler;
26
26
  };
27
+ //# sourceMappingURL=registerExitHandlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registerExitHandlers.js","sourceRoot":"","sources":["../src/registerExitHandlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,IAAI,YAAY,GAAG,KAAK,CAAC;AAEzB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,UAA0C,EACf,EAAE;IAC7B,MAAM,WAAW,GAAG,CAAC,IAAI,GAAG,CAAC,EAAQ,EAAE;QACrC,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QAEpB,GAAG,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QAEpC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;YAC5D,GAAG,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,yBAAyB;IACzB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,WAAW,EAAE,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;QACtC,GAAG,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACtC,WAAW,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC","sourcesContent":["import { log } from './logger.js';\n\nlet handlingExit = false;\n\nexport const registerExitHandlers = (\n cleanupFns: (() => void | Promise<void>)[],\n): ((code?: number) => void) => {\n const exitHandler = (code = 0): void => {\n if (handlingExit) return;\n handlingExit = true;\n\n log.info('Shutting down server...');\n\n Promise.allSettled(cleanupFns.map((fn) => fn())).finally(() => {\n log.info('Server shutdown complete');\n process.exit(code);\n });\n };\n\n // Handle server shutdown\n process.on('SIGINT', () => {\n exitHandler();\n });\n process.on('SIGTERM', () => {\n exitHandler();\n });\n process.on('uncaughtException', (err) => {\n log.error('Uncaught Exception:', err);\n exitHandler(1);\n });\n\n return exitHandler;\n};\n"]}
@@ -3,3 +3,4 @@ export * from './resource.js';
3
3
  export * from './tool.js';
4
4
  export * from './types.js';
5
5
  export * from './utils.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC","sourcesContent":["export * from './prompts.js';\nexport * from './resource.js';\nexport * from './tool.js';\nexport * from './types.js';\nexport * from './utils.js';\n"]}
@@ -29,3 +29,4 @@ export const createSkillsPromptFactories = async (options = {}) => {
29
29
  },
30
30
  }));
31
31
  };
32
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/skills/prompts.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAkB5E,+DAA+D;AAC/D,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,EAC9C,UAAmB,EAAE,EAGrB,EAAE;IACF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAErC,CAAC,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACpD,IAAI;QACJ,MAAM,EAAE;YACN,qFAAqF;YACrF,4DAA4D;YAC5D,KAAK,EAAE,IAAI;YACX,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,WAAW,EAAE,EAAE,EAAE,iCAAiC;SACnD;QACD,EAAE,EAAE,KAAK,IAA2B,EAAE;YACpC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;YACtC,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,OAAO;gBACL,WAAW,EAAE,SAAS,CAAC,WAAW,IAAI,IAAI;gBAC1C,QAAQ,EAAE;oBACR;wBACE,IAAI,EAAE,MAAe;wBACrB,OAAO,EAAE;4BACP,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,OAAO;yBACd;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC,CAAC;AACN,CAAC,CAAC","sourcesContent":["import type { Octokit } from '@octokit/rest';\nimport type { PromptFactory } from '../types.js';\nimport type { ServerContextWithOctokit } from './types.js';\nimport { loadSkills, parseSkillsFlags, viewSkillContent } from './utils.js';\n\ninterface Options {\n octokit?: Octokit;\n}\n\ninterface PromptResult {\n [x: string]: unknown;\n description: string;\n messages: {\n role: 'user';\n content: {\n type: 'text';\n text: string;\n };\n }[];\n}\n\n// Create a prompt for each skill from the main SKILL.md files.\nexport const createSkillsPromptFactories = async (\n options: Options = {},\n): Promise<\n PromptFactory<ServerContextWithOctokit, Record<string, never>>[]\n> => {\n const skills = await loadSkills(options);\n return Array.from(skills.entries()).map<\n PromptFactory<ServerContextWithOctokit, Record<string, never>>\n >(([name, skillData]) => ({ octokit }, { query }) => ({\n name,\n config: {\n // Using the dash-separated name as the title to work around a problem in Claude Code\n // See https://github.com/anthropics/claude-code/issues/7464\n title: name,\n description: skillData.description,\n inputSchema: {}, // No arguments for static skills\n },\n fn: async (): Promise<PromptResult> => {\n const flags = parseSkillsFlags(query);\n const content = await viewSkillContent({ octokit, flags, name });\n return {\n description: skillData.description || name,\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: content,\n },\n },\n ],\n };\n },\n }));\n};\n"]}
@@ -45,3 +45,4 @@ export const createSkillsResourceFactory = (options = {}) => async (ctx, mcpFlag
45
45
  },
46
46
  };
47
47
  };
48
+ //# sourceMappingURL=resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/skills/resource.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAapB,MAAM,CAAC,MAAM,2BAA2B,GACtC,CACE,UAA4B,EAAE,EACa,EAAE,CAC/C,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE;IACtB,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;IACxB,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;IAC3B,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,QAAQ;QAC9B,QAAQ,EACN,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU;YACpC,CAAC,CAAC,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAc,EAAE,QAAQ,CAAC;YAClD,CAAC,CAAC,OAAO,CAAC,QAAQ;QACtB,MAAM,EAAE;YACN,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,QAAQ;YAChC,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,IAAI,iBAAiB,GACtD,OAAO,CAAC,6BAA6B;gBACnC,CAAC,CAAC,8BAA8B,MAAM,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE;gBAC/F,CAAC,CAAC,EACN,EAAE;SACH;QACD,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,kBAAkB;QAC/D,IAAI,EAAE,KAAK,IAQR,EAAE;YACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;YAC7C,OAAO;gBACL,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;qBACnC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;qBAC1C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;oBACf,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,MAAM,KAAK,CAAC,IAAI,gBAAgB;oBACrE,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,KAAK,EAAE,KAAK,CAAC,IAAI;oBACjB,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,QAAQ,EAAE,eAAe;iBAC1B,CAAC,CAAC;aACN,CAAC;QACJ,CAAC;QACD,IAAI,EAAE,KAAK,EACT,GAAG,EACH,EAAE,IAAI,EAAE,IAAI,EAAE,EAC0C,EAAE;YAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACxD,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACxC,CAAC;YACD,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,IAAI,EAAE,MAAM,gBAAgB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;qBAC7D;iBACF;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import type { McpFeatureFlags, ResourceFactory } from '../types.js';\nimport type { ServerContextWithOctokit } from './types.js';\nimport {\n listSkills,\n loadSkills,\n parseSkillsFlags,\n skillsDescription,\n skillVisible,\n viewSkillContent,\n} from './utils.js';\n\ninterface Options<Context extends ServerContextWithOctokit> {\n appendSkillsListToDescription?: boolean;\n description?: string;\n disabled?:\n | boolean\n | ((ctx: Context, flags: McpFeatureFlags) => boolean | Promise<boolean>);\n name?: string;\n title?: string;\n uriScheme?: string;\n}\n\nexport const createSkillsResourceFactory =\n <Context extends ServerContextWithOctokit>(\n options: Options<Context> = {},\n ): ResourceFactory<ServerContextWithOctokit> =>\n async (ctx, mcpFlags) => {\n const { octokit } = ctx;\n const { query } = mcpFlags;\n const flags = parseSkillsFlags(query);\n return {\n type: 'templated',\n name: options.name || 'skills',\n disabled:\n typeof options.disabled === 'function'\n ? await options.disabled(ctx as Context, mcpFlags)\n : options.disabled,\n config: {\n title: options.title || 'Skills',\n description: `${options.description || skillsDescription}${\n options.appendSkillsListToDescription\n ? `\\n\\n## Available Skills\\n\\n${await listSkills({ octokit, flags: parseSkillsFlags(query) })}`\n : ''\n }`,\n },\n uriTemplate: `${options.uriScheme || 'skills'}://{name}{?path}`,\n list: async (): Promise<{\n resources: Array<{\n uri: string;\n name: string;\n title: string;\n description: string;\n mimeType: string;\n }>;\n }> => {\n const skills = await loadSkills({ octokit });\n return {\n resources: Array.from(skills.values())\n .filter((s) => skillVisible(s.name, flags))\n .map((skill) => ({\n uri: `${options.uriScheme || 'skills'}://${skill.name}?path=SKILL.md`,\n name: skill.name,\n title: skill.name,\n description: skill.description,\n mimeType: 'text/markdown',\n })),\n };\n },\n read: async (\n uri,\n { name, path },\n ): Promise<{ contents: { uri: string; text: string }[] }> => {\n if (Array.isArray(name) || Array.isArray(path) || !name) {\n throw new Error('Invalid parameters');\n }\n return {\n contents: [\n {\n uri: uri.href,\n text: await viewSkillContent({ octokit, flags, name, path }),\n },\n ],\n };\n },\n };\n };\n"]}
@@ -78,3 +78,4 @@ export const createViewSkillToolFactory = (options = {}) => async (ctx, mcpFlags
78
78
  },
79
79
  };
80
80
  };
81
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/skills/tool.ts"],"names":[],"mappings":"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","sourcesContent":["import { log } from '../logger.js';\nimport type { ApiFactory, McpFeatureFlags } from '../types.js';\nimport {\n type ServerContextWithOctokit,\n type ViewSkillOutputSchema,\n zViewSkillInputSchema,\n zViewSkillOutputSchema,\n} from './types.js';\nimport {\n getAvailableSkillNames,\n InvalidPathError,\n listSkills,\n PathNotFoundError,\n parseSkillsFlags,\n SkillNotFoundError,\n SkillsApiError,\n skillsDescription,\n viewSkillContent,\n} from './utils.js';\n\ninterface Options<Context extends ServerContextWithOctokit> {\n appendSkillsListToDescription?: boolean;\n description?: string;\n disabled?:\n | boolean\n | ((ctx: Context, flags: McpFeatureFlags) => boolean | Promise<boolean>);\n method?: 'get' | 'post';\n name?: string;\n route?: string;\n title?: string;\n}\n\nexport const createViewSkillToolFactory =\n <Context extends ServerContextWithOctokit>(\n options: Options<Context> = {},\n ): ApiFactory<\n ServerContextWithOctokit,\n typeof zViewSkillInputSchema,\n typeof zViewSkillOutputSchema\n > =>\n async (ctx, mcpFlags) => {\n const { octokit } = ctx;\n const flags = parseSkillsFlags(mcpFlags.query);\n return {\n name: options.name || 'view',\n disabled:\n typeof options.disabled === 'function'\n ? await options.disabled(ctx as Context, mcpFlags)\n : options.disabled,\n method: options.method || 'get',\n route: options.route || '/view',\n config: {\n title: options.title || 'View Skill',\n description: `${options.description || skillsDescription}${\n options.appendSkillsListToDescription\n ? `\\n\\n## Available Skills\\n\\n${await listSkills({ octokit, flags })}`\n : ''\n }`,\n inputSchema: zViewSkillInputSchema,\n outputSchema: zViewSkillOutputSchema,\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n },\n },\n fn: async ({\n skill_name: name,\n path,\n }): Promise<ViewSkillOutputSchema> => {\n if (!name || name === '.') {\n return {\n content: await listSkills({ octokit, flags }),\n };\n }\n try {\n return {\n content: await viewSkillContent({\n octokit,\n flags,\n name,\n path,\n }),\n };\n } catch (err) {\n if (!(err instanceof SkillsApiError)) {\n throw err;\n }\n if (err instanceof SkillNotFoundError) {\n log.warn(`Skill not found: ${err.skillName}`, {\n error: err.constructor.name,\n skill: err.skillName,\n });\n const available = await getAvailableSkillNames({ octokit, flags });\n return {\n content: `Skill not found: ${err.skillName}. Available skills: ${available}. Use one of these names.`,\n };\n }\n if (err instanceof PathNotFoundError) {\n log.warn(`Path not found: ${err.path} in skill ${err.skill}`, {\n error: err.constructor.name,\n skill: err.skill,\n path: err.path,\n });\n return {\n content: `Path not found: ${err.path}. Contents of skill \"${err.skill}\":\\n${err.listing}\\n\\nUse path \"SKILL.md\" to read the main skill document.`,\n };\n }\n if (err instanceof InvalidPathError) {\n log.warn(`Invalid path: ${err.path}`, {\n error: err.constructor.name,\n path: err.path,\n });\n const available = await getAvailableSkillNames({ octokit, flags });\n return {\n content: `${err.message} Available skills: ${available}. Use name \".\" to list skills; use path \".\" to list a skill's contents.`,\n };\n }\n throw err;\n }\n },\n };\n };\n"]}
@@ -84,3 +84,4 @@ describe('createViewSkillToolFactory', () => {
84
84
  }));
85
85
  });
86
86
  });
87
+ //# sourceMappingURL=tool.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.spec.js","sourceRoot":"","sources":["../../src/skills/tool.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n afterAll,\n beforeAll,\n beforeEach,\n describe,\n expect,\n it,\n spyOn,\n} from 'bun:test';\nimport Path from 'node:path';\nimport { log } from '../logger.js';\nimport { createViewSkillToolFactory } from './tool.js';\nimport type { ViewSkillOutputSchema } from './types.js';\n\nprocess.env.SKILLS_FILE = Path.resolve(\n import.meta.dir,\n '__fixtures__',\n 'skills.yaml',\n);\n\ndescribe('createViewSkillToolFactory', () => {\n let warnSpy: ReturnType<typeof spyOn<typeof log, 'warn'>>;\n let fn: (args: {\n skill_name: string;\n path: string;\n }) => Promise<ViewSkillOutputSchema>;\n\n beforeAll(async () => {\n const factory = createViewSkillToolFactory();\n const tool = await factory({ octokit: null }, { query: {} });\n fn = tool.fn;\n warnSpy = spyOn(log, 'warn');\n });\n\n beforeEach(() => {\n warnSpy.mockClear();\n });\n\n afterAll(() => {\n warnSpy.mockRestore();\n });\n\n it('lists skills when skill_name is \".\"', async () => {\n const result = await fn({ skill_name: '.', path: '' });\n expect(result.content).toContain('<available_skills>');\n expect(result.content).toContain('first-skill');\n expect(result.content).toContain('second-skill');\n });\n\n it('lists skills when skill_name is empty', async () => {\n const result = await fn({ skill_name: '', path: '' });\n expect(result.content).toContain('<available_skills>');\n expect(result.content).toContain('first-skill');\n expect(result.content).toContain('second-skill');\n });\n\n it('returns skill content for valid name and path', async () => {\n const result = await fn({ skill_name: 'first-skill', path: 'SKILL.md' });\n expect(result.content).toBe('First skill content\\n');\n });\n\n it('returns recovery string with available skills for nonexistent skill', async () => {\n const result = await fn({ skill_name: 'nonexistent', path: 'SKILL.md' });\n expect(result.content).toContain('Skill not found: nonexistent');\n expect(result.content).toContain('first-skill');\n expect(result.content).toContain('second-skill');\n expect(warnSpy).toHaveBeenCalledWith(\n 'Skill not found: nonexistent',\n expect.objectContaining({\n error: 'SkillNotFoundError',\n skill: 'nonexistent',\n }),\n );\n });\n\n it('returns recovery string with directory listing for nonexistent path', async () => {\n const result = await fn({\n skill_name: 'first-skill',\n path: 'does-not-exist',\n });\n expect(result.content).toContain('Path not found: does-not-exist');\n expect(result.content).toContain('first-skill');\n expect(result.content).toContain('SKILL.md');\n expect(warnSpy).toHaveBeenCalledWith(\n 'Path not found: does-not-exist in skill first-skill',\n expect.objectContaining({\n error: 'PathNotFoundError',\n skill: 'first-skill',\n path: 'does-not-exist',\n }),\n );\n });\n\n it('returns recovery string for directory traversal path', async () => {\n const result = await fn({\n skill_name: 'first-skill',\n path: '../../etc/passwd',\n });\n expect(result.content).toContain('Invalid path: ../../etc/passwd.');\n expect(result.content).toContain('first-skill');\n expect(result.content).toContain('second-skill');\n expect(warnSpy).toHaveBeenCalledWith(\n 'Invalid path: ../../etc/passwd',\n expect.objectContaining({\n error: 'InvalidPathError',\n path: '../../etc/passwd',\n }),\n );\n });\n\n it('returns recovery string for null byte path', async () => {\n const result = await fn({\n skill_name: 'first-skill',\n path: 'SKILL.md\\x00.txt',\n });\n expect(result.content).toContain('Invalid path: SKILL.md\\x00.txt.');\n expect(result.content).toContain('first-skill');\n expect(warnSpy).toHaveBeenCalledWith(\n 'Invalid path: SKILL.md\\x00.txt',\n expect.objectContaining({\n error: 'InvalidPathError',\n path: 'SKILL.md\\x00.txt',\n }),\n );\n });\n});\n"]}
@@ -58,3 +58,4 @@ Use \`.\` to list the root directory of the skill.
58
58
  export const zViewSkillOutputSchema = {
59
59
  content: z.string().describe('The content of the file or directory listing.'),
60
60
  };
61
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/skills/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Octokit } from '@octokit/rest';\nimport { z } from 'zod';\nimport type { InferSchema } from '../types.js';\n\nexport const zSkillType = z.enum([\n 'local',\n 'local_collection',\n 'github',\n 'github_collection',\n]);\n\nexport type SkillType = z.infer<typeof zSkillType>;\n\nexport const zLocalSkillCfg = z.object({\n type: z.literal('local'),\n path: z.string(),\n});\nexport type LocalSkillCfg = z.infer<typeof zLocalSkillCfg>;\n\nconst zCollectionFlagsCfg = z.object({\n enabled_skills: z.array(z.string()).optional(),\n disabled_skills: z.array(z.string()).optional(),\n ignored_paths: z.array(z.string()).optional(),\n});\nexport type CollectionFlagsCfg = z.infer<typeof zCollectionFlagsCfg>;\n\nexport interface CollectionFlags {\n enabledSkills: Set<string> | null;\n disabledSkills: Set<string> | null;\n ignoredPaths: Set<string> | null;\n}\n\nexport const zLocalCollectionSkillCfg = zCollectionFlagsCfg.extend({\n type: z.literal('local_collection'),\n path: z.string(),\n});\nexport type LocalCollectionSkillCfg = z.infer<typeof zLocalCollectionSkillCfg>;\n\nexport const zGitHubSkillCfg = z.object({\n type: z.literal('github'),\n repo: z.string(),\n path: z.string().optional(),\n ref: z.string().optional(),\n});\nexport type GitHubSkillCfg = z.infer<typeof zGitHubSkillCfg>;\n\nexport const zGitHubCollectionSkillCfg = zCollectionFlagsCfg.extend({\n type: z.literal('github_collection'),\n repo: z.string(),\n path: z.string().optional(),\n ref: z.string().optional(),\n});\nexport type GitHubCollectionSkillCfg = z.infer<\n typeof zGitHubCollectionSkillCfg\n>;\n\nexport const zSkillCfg = z.discriminatedUnion('type', [\n zLocalSkillCfg,\n zLocalCollectionSkillCfg,\n zGitHubSkillCfg,\n zGitHubCollectionSkillCfg,\n]);\nexport type SkillCfg = z.infer<typeof zSkillCfg>;\n\nexport const zSkillCfgMap = z.record(z.string(), zSkillCfg);\nexport type SkillCfgMap = z.infer<typeof zSkillCfgMap>;\n\nexport const zSkillMatter = z.object({\n name: z.string().trim().min(1),\n description: z.string(),\n});\nexport type SkillMatter = z.infer<typeof zSkillMatter>;\n\nexport const zLocalSkill = zSkillMatter.extend(zLocalSkillCfg.shape);\nexport type LocalSkill = z.infer<typeof zLocalSkill>;\n\nexport const zGitHubSkill = zSkillMatter.extend(zGitHubSkillCfg.shape);\nexport type GitHubSkill = z.infer<typeof zGitHubSkill>;\n\nexport const zSkill = z.discriminatedUnion('type', [zLocalSkill, zGitHubSkill]);\nexport type Skill = z.infer<typeof zSkill>;\n\nexport const zSkillMap = z.record(z.string(), zSkill);\nexport type SkillMap = z.infer<typeof zSkillMap>;\n\nexport interface SkillsFlags {\n enabledSkills?: Set<string> | null;\n disabledSkills?: Set<string> | null;\n}\n\nexport interface ServerContextWithOctokit extends Record<string, unknown> {\n octokit?: Octokit | null;\n}\n\nexport const zViewSkillInputSchema = {\n skill_name: z\n .string()\n .describe(\n 'The name of the skill to browse, or `.` to list all available skills.',\n ),\n path: z.string().describe(\n `\nA relative path to a file or directory within the skill to view.\nIf empty, will view the \\`SKILL.md\\` file by default.\nUse \\`.\\` to list the root directory of the skill.\n`.trim(),\n ),\n} as const;\nexport type ViewSkillInputSchema = InferSchema<typeof zViewSkillInputSchema>;\n\nexport const zViewSkillOutputSchema = {\n content: z.string().describe('The content of the file or directory listing.'),\n} as const;\nexport type ViewSkillOutputSchema = InferSchema<typeof zViewSkillOutputSchema>;\n"]}
@@ -1,6 +1,7 @@
1
1
  import type { Octokit } from '@octokit/rest';
2
2
  import { type McpFeatureFlags } from '@tigerdata/mcp-boilerplate';
3
3
  import { type CollectionFlags, type CollectionFlagsCfg, type Skill, type SkillCfgMap, type SkillMatter, type SkillsFlags } from './types.js';
4
+ export declare const setSkillConfigReadOverride: (fn: (() => Promise<SkillCfgMap>) | null) => void;
4
5
  export declare const getSkillConfig: (configFilePath?: string) => Promise<SkillCfgMap>;
5
6
  export declare const parseSkillFile: (fileContent: string) => Promise<{
6
7
  matter: SkillMatter;
@@ -10,11 +10,24 @@ const TTL = process.env.SKILLS_TTL
10
10
  : 5 * 60 * 1000;
11
11
  let lastFetchCfg = 0;
12
12
  let skillCfgMap = null;
13
+ let getSkillOverride = null;
14
+ // added so that the consumer can control where the skill config comes from
15
+ // e.g. programmatically, rather than from a file
16
+ // chose to use a setter pattern to minimize changing signatures everywhere,
17
+ // this approach has a minimal footprint
18
+ export const setSkillConfigReadOverride = (fn) => {
19
+ getSkillOverride = fn;
20
+ };
13
21
  export const getSkillConfig = async (configFilePath = process.env.SKILLS_FILE || './skills.yaml') => {
14
22
  if (skillCfgMap && Date.now() - lastFetchCfg < TTL)
15
23
  return skillCfgMap;
16
- const data = await readFile(configFilePath, 'utf-8');
17
- skillCfgMap = zSkillCfgMap.parse(YAML.parse(data));
24
+ if (getSkillOverride !== null) {
25
+ skillCfgMap = await getSkillOverride();
26
+ }
27
+ else {
28
+ const data = await readFile(configFilePath, 'utf-8');
29
+ skillCfgMap = zSkillCfgMap.parse(YAML.parse(data));
30
+ }
18
31
  lastFetchCfg = Date.now();
19
32
  return skillCfgMap;
20
33
  };
@@ -459,3 +472,4 @@ export const parseCollectionFlags = (cfg) => ({
459
472
  disabledSkills: toSet(cfg.disabled_skills),
460
473
  ignoredPaths: toSet(cfg.ignored_paths),
461
474
  });
475
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/skills/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Stats } from 'node:fs';\nimport { readdir, readFile, stat } from 'node:fs/promises';\nimport Path from 'node:path';\nimport type { Octokit } from '@octokit/rest';\nimport {\n log,\n type McpFeatureFlags,\n type ParsedQs,\n} from '@tigerdata/mcp-boilerplate';\nimport { encode } from '@toon-format/toon';\nimport matter from 'gray-matter';\nimport YAML from 'yaml';\nimport {\n type CollectionFlags,\n type CollectionFlagsCfg,\n type GitHubSkill,\n type LocalSkill,\n type Skill,\n type SkillCfgMap,\n type SkillMatter,\n type SkillsFlags,\n zSkillCfgMap,\n zSkillMatter,\n} from './types.js';\n\nconst TTL = process.env.SKILLS_TTL\n ? parseInt(process.env.SKILLS_TTL, 10)\n : 5 * 60 * 1000;\n\nlet lastFetchCfg = 0;\nlet skillCfgMap: SkillCfgMap | null = null;\nlet getSkillOverride: (() => Promise<SkillCfgMap>) | null = null;\n\n// added so that the consumer can control where the skill config comes from\n// e.g. programmatically, rather than from a file\n// chose to use a setter pattern to minimize changing signatures everywhere,\n// this approach has a minimal footprint\nexport const setSkillConfigReadOverride = (\n fn: (() => Promise<SkillCfgMap>) | null,\n) => {\n getSkillOverride = fn;\n};\n\nexport const getSkillConfig = async (\n configFilePath = process.env.SKILLS_FILE || './skills.yaml',\n): Promise<SkillCfgMap> => {\n if (skillCfgMap && Date.now() - lastFetchCfg < TTL) return skillCfgMap;\n\n if (getSkillOverride !== null) {\n skillCfgMap = await getSkillOverride();\n } else {\n const data = await readFile(configFilePath, 'utf-8');\n skillCfgMap = zSkillCfgMap.parse(YAML.parse(data));\n }\n\n lastFetchCfg = Date.now();\n\n return skillCfgMap;\n};\n\nexport const parseSkillFile = async (\n fileContent: string,\n): Promise<{\n matter: SkillMatter;\n content: string;\n}> => {\n const { data, content } = matter(fileContent);\n const skillMatter = zSkillMatter.parse(data);\n if (!/^[a-zA-Z0-9-_]+$/.test(skillMatter.name)) {\n const normalized = skillMatter.name\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-_]/g, '_')\n .replace(/-[-_]+/g, '-')\n .replace(/_[_-]+/g, '_')\n .replace(/(^[-_]+)|([-_]+$)/g, '');\n log.warn(\n `Skill name \"${skillMatter.name}\" contains invalid characters. Normalizing to \"${normalized}\".`,\n );\n skillMatter.name = normalized;\n }\n return {\n matter: skillMatter,\n content,\n };\n};\n\n// skill name/path -> content\nconst skillContentCache: Map<string, string> = new Map();\n\nlet lastFetchSkillMap = 0;\nlet skillMap: Promise<Map<string, Skill>> | null = null;\nexport const loadSkills = async ({\n octokit,\n force = false,\n}: {\n octokit?: Octokit | null;\n force?: boolean;\n} = {}): Promise<Map<string, Skill>> => {\n if (skillMap && !force && Date.now() - lastFetchSkillMap < TTL)\n return skillMap;\n skillMap = doLoadSkills(octokit).then(\n (result) => {\n lastFetchSkillMap = Date.now();\n return result;\n },\n (err) => {\n log.error('Failed to load skills, returning empty skill map', err);\n skillMap = null;\n return new Map<string, Skill>();\n },\n );\n return skillMap;\n};\n\nconst doLoadSkills = async (\n octokit?: Octokit | null,\n): Promise<Map<string, Skill>> => {\n const skillCfgs = await getSkillConfig();\n\n skillContentCache.clear();\n const skills = new Map<string, Skill>();\n\n const alreadyExists = (\n name: string,\n path: string,\n description: string,\n ): boolean => {\n const existing = skills.get(name);\n if (existing) {\n log.warn(\n `Skill with name \"${name}\" already loaded from path \"${existing.path}\". Skipping duplicate at path \"${path}\".`,\n { existing, duplicate: { path, name, description } },\n );\n return true;\n }\n return false;\n };\n\n const shouldIgnorePath = (path: string, flags?: CollectionFlags): boolean => {\n if (flags?.ignoredPaths?.has(path)) {\n log.debug(`Ignoring path \"${path}\" in ignoredPaths`);\n return true;\n }\n return false;\n };\n\n const shouldIgnoreSkill = (\n name: string,\n flags?: CollectionFlags,\n ): boolean => {\n if (flags?.enabledSkills && !flags.enabledSkills.has(name)) {\n log.debug(`Ignoring skill \"${name}\" not in enabledSkills`);\n return true;\n }\n if (flags?.disabledSkills?.has(name)) {\n log.debug(`Ignoring skill \"${name}\" in disabledSkills`);\n return true;\n }\n return false;\n };\n\n const loadLocalPath = async (\n path: string,\n flags?: CollectionFlags,\n ): Promise<void> => {\n if (shouldIgnorePath(path, flags)) return;\n const skillPath = `${path}/SKILL.md`;\n try {\n const fileContent = await readFile(skillPath, 'utf-8');\n const {\n matter: { name, description },\n content,\n } = await parseSkillFile(fileContent);\n if (shouldIgnoreSkill(name, flags)) return;\n if (alreadyExists(name, path, description)) return;\n skills.set(name, {\n type: 'local',\n path,\n name,\n description,\n } satisfies LocalSkill);\n skillContentCache.set(`${name}/SKILL.md`, content);\n } catch (err) {\n log.error(`Failed to load skill at path: ${skillPath}`, err as Error);\n }\n };\n\n const loadGitHubPath = async (\n owner: string,\n repo: string,\n path: string,\n ref?: string,\n flags?: CollectionFlags,\n ): Promise<void> => {\n if (shouldIgnorePath(path, flags)) return;\n const skillPath = `${path}/SKILL.md`;\n if (!octokit) {\n log.error(\n `Octokit instance is required to load GitHub skills: ${owner}/${repo}/${skillPath}`,\n );\n return;\n }\n try {\n const skillFileResponse = await octokit.repos.getContent({\n owner,\n repo,\n path: skillPath,\n ...(ref ? { ref } : {}),\n });\n if (\n Array.isArray(skillFileResponse.data) ||\n skillFileResponse.data.type !== 'file'\n ) {\n log.error(`Expected SKILL.md to be a file`, null, {\n owner,\n repo,\n path: skillPath,\n ref,\n });\n return;\n }\n const fileContent = Buffer.from(\n skillFileResponse.data.content,\n 'base64',\n ).toString('utf-8');\n const {\n matter: { name, description },\n content,\n } = await parseSkillFile(fileContent);\n if (shouldIgnoreSkill(name, flags)) return;\n if (alreadyExists(name, path, description)) return;\n skills.set(name, {\n type: 'github',\n repo: `${owner}/${repo}`,\n path,\n ...(ref ? { ref } : {}),\n name,\n description,\n } satisfies GitHubSkill);\n skillContentCache.set(`${name}/SKILL.md`, content);\n } catch (err) {\n log.error(\n `Failed to load skill at GitHub path: ${owner}/${repo}/${skillPath}${ref ? `@${ref}` : ''}\\n${(err as Error).message}`,\n );\n }\n };\n\n const promises: Promise<void>[] = [];\n await Promise.all(\n Object.entries(skillCfgs).map(async ([name, cfg]) => {\n try {\n switch (cfg.type) {\n case 'local': {\n promises.push(loadLocalPath(cfg.path));\n break;\n }\n case 'local_collection': {\n const dirEntries = await readdir(cfg.path, {\n withFileTypes: true,\n });\n const flags = parseCollectionFlags(cfg);\n for (const entry of dirEntries) {\n if (entry.isFile()) continue;\n if (entry.name.startsWith('.')) continue;\n if (!entry.isDirectory()) {\n log.warn(`Skipping non-directory entry in local_collection`, {\n path: `${cfg.path}/${entry.name}`,\n });\n continue;\n }\n promises.push(loadLocalPath(`${cfg.path}/${entry.name}`, flags));\n }\n break;\n }\n case 'github': {\n const [owner, repo] = cfg.repo.split('/');\n if (!owner || !repo) {\n log.error(\n `Invalid GitHub repo format in skill config: ${cfg.repo}`,\n null,\n { name, repo: cfg.repo },\n );\n break;\n }\n promises.push(\n loadGitHubPath(owner, repo, cfg.path || '.', cfg.ref),\n );\n break;\n }\n case 'github_collection': {\n const [owner, repo] = cfg.repo.split('/');\n if (!owner || !repo) {\n log.error(\n `Invalid GitHub repo format in skill config: ${cfg.repo}`,\n null,\n { name, repo: cfg.repo },\n );\n break;\n }\n if (!octokit) {\n log.error(\n `Octokit instance is required to load GitHub collection skills: ${cfg.repo}`,\n );\n break;\n }\n const rootPath = cfg.path\n ? cfg.path.replace(/(^\\.?\\/+)|(^\\.$)|(\\/\\.$)/g, '')\n : '';\n const dirResponse = await octokit.repos.getContent({\n owner,\n repo,\n path: rootPath,\n ...(cfg.ref ? { ref: cfg.ref } : {}),\n });\n if (!Array.isArray(dirResponse.data)) {\n log.error(\n `Expected github_collection repo path to be a directory`,\n null,\n { name, owner, repo, path: cfg.path || '.', ref: cfg.ref },\n );\n break;\n }\n const flags = parseCollectionFlags(cfg);\n for (const entry of dirResponse.data) {\n if (entry.type === 'file') continue;\n if (entry.name.startsWith('.')) continue;\n if (entry.type !== 'dir') {\n log.warn(`Skipping non-directory entry in github_collection`, {\n path: `${cfg.repo}/${entry.path}`,\n type: entry.type,\n });\n continue;\n }\n promises.push(\n loadGitHubPath(owner, repo, entry.path, cfg.ref, flags),\n );\n }\n break;\n }\n default: {\n // @ts-expect-error exhaustive check\n throw new Error(`Unhandled skill config type: ${cfg.type}`);\n }\n }\n } catch (err) {\n log.error(`Failed to load skill config \"${name}\"`, err as Error);\n }\n }),\n );\n await Promise.all(promises);\n\n // Sort skills by name\n return new Map(\n Array.from(skills.entries()).sort((a, b) => a[0].localeCompare(b[0])),\n );\n};\n\nexport const resolveSkill = async ({\n name,\n octokit,\n flags = {},\n force = false,\n}: {\n name: string;\n octokit?: Octokit | null;\n flags?: SkillsFlags;\n force?: boolean;\n}): Promise<Skill | null> => {\n if (!skillVisible(name, flags)) {\n return null;\n }\n const skills = await loadSkills({ octokit, force });\n return skills.get(name) || null;\n};\n\nexport const skillVisible = (name: string, flags: SkillsFlags): boolean => {\n if (flags.enabledSkills && !flags.enabledSkills.has(name)) {\n return false;\n }\n if (flags.disabledSkills?.has(name)) {\n return false;\n }\n return true;\n};\n\n/** Base class for skills API errors; catch in tool.ts to format recovery messages. */\nexport class SkillsApiError extends Error {}\n\nexport class SkillNotFoundError extends SkillsApiError {\n constructor(public readonly skillName: string) {\n super(`Skill not found: ${skillName}.`);\n }\n}\n\nexport class PathNotFoundError extends SkillsApiError {\n constructor(\n public readonly skill: string,\n public readonly path: string,\n public readonly listing: string,\n ) {\n super(`Path not found: ${path}.`);\n }\n}\n\nexport class InvalidPathError extends SkillsApiError {\n constructor(public readonly path: string) {\n super(`Invalid path: ${path}.`);\n }\n}\n\n/** Comma-separated visible skill names for error/recovery messages. */\nexport const getAvailableSkillNames = async ({\n octokit,\n flags = {},\n}: {\n octokit?: Octokit | null;\n flags?: SkillsFlags;\n}): Promise<string> => {\n try {\n const skills = await loadSkills({ octokit, force: false });\n const names = [...skills.values()]\n .filter((s) => skillVisible(s.name, flags))\n .map((s) => s.name)\n .sort();\n return names.length > 0 ? names.join(', ') : '(none)';\n } catch (err) {\n throw new Error(`getAvailableSkillNames failed: ${(err as Error).message}`);\n }\n};\n\nexport const listSkills = async ({\n octokit,\n flags = {},\n force = false,\n}: {\n octokit?: Octokit | null;\n flags?: SkillsFlags;\n force?: boolean;\n} = {}): Promise<string> => {\n const skills = await loadSkills({ octokit, force });\n return `<available_skills>\n${encode(\n [...skills.values()]\n .filter((s) => skillVisible(s.name, flags))\n .map((s) => ({\n name: s.name,\n description: s.description,\n })),\n { delimiter: '\\t' },\n)}\n</available_skills>`;\n};\n\nexport const viewSkillContent = async ({\n octokit,\n flags = {},\n name,\n path: passedPath,\n}: {\n octokit?: Octokit | null;\n flags?: SkillsFlags;\n name: string;\n path?: string;\n}): Promise<string> => {\n const skill = await resolveSkill({ octokit, flags, name });\n if (!skill) {\n throw new SkillNotFoundError(name);\n }\n\n const targetPath = passedPath || 'SKILL.md';\n const cacheKey = `${name}/${normalizeSkillPath(targetPath)}`;\n const cached = skillContentCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n const content = await getSkillContent({ octokit, skill, path: targetPath });\n skillContentCache.set(cacheKey, content);\n return content;\n};\n\nconst normalizeSkillPath = (path: string): string => {\n const normalizedPath = Path.posix\n .normalize(\n // treat \\ as /\n path.replace(/\\\\/g, '/'),\n )\n // strip leading ./ or /\n .replace(/^(\\.?\\/)+/, '');\n if (\n normalizedPath.split('/').some((s) => s === '..') ||\n normalizedPath.includes('\\0')\n ) {\n throw new InvalidPathError(path);\n }\n return normalizedPath;\n};\n\nconst getSkillContent = async ({\n skill,\n path: targetPath,\n octokit,\n}: {\n skill: Skill;\n path: string;\n octokit?: Octokit | null;\n}): Promise<string> => {\n const normalizedPath = normalizeSkillPath(targetPath);\n switch (skill.type) {\n case 'local': {\n const root = Path.resolve(skill.path);\n const target = Path.resolve(Path.join(root, normalizedPath));\n if (targetPath !== '.' && !target.startsWith(root)) {\n throw new InvalidPathError(targetPath);\n }\n let stats: Stats;\n try {\n stats = await stat(target);\n } catch {\n const entries = await readdir(root, { withFileTypes: true }).catch(\n () => [],\n );\n const listing = entries\n .map((entry) => `${entry.isDirectory() ? '📁' : '📄'} ${entry.name}`)\n .join('\\n');\n throw new PathNotFoundError(\n skill.name,\n targetPath,\n listing || '(empty)',\n );\n }\n if (stats.isDirectory()) {\n const entries = await readdir(target, {\n withFileTypes: true,\n });\n const listing = entries\n .map((entry) => {\n return `${entry.isDirectory() ? '📁' : '📄'} ${entry.name}`;\n })\n .join('\\n');\n return `Directory listing for ${skill.name}/${normalizedPath}:\\n${listing}`;\n } else if (stats.isFile()) {\n return await readFile(target, 'utf-8');\n } else {\n throw new Error(`Unsupported file type at path: ${target}`);\n }\n }\n case 'github': {\n const [owner, repo] = skill.repo.split('/');\n if (!owner || !repo) {\n throw new Error(`Invalid GitHub repo format in skill: ${skill.repo}`);\n }\n const path = `${skill.path || '.'}/${normalizedPath}`\n .replace(/\\/+/g, '/')\n .replace(/(^\\.?\\/+)|(^\\.$)|(\\/\\.$)/g, '');\n if (!octokit) {\n throw new Error(\n `Octokit instance is required to load GitHub skill content: ${owner}/${repo}/${path}`,\n );\n }\n const response = await octokit.repos.getContent({\n owner,\n repo,\n path,\n ...(skill.ref ? { ref: skill.ref } : {}),\n });\n if (Array.isArray(response.data)) {\n // Directory listing\n const listing = response.data\n .map((entry) => {\n return `${entry.type === 'dir' ? '📁' : '📄'} ${entry.name}`;\n })\n .join('\\n');\n return `Directory listing for ${skill.name}/${normalizedPath}:\\n${listing}`;\n }\n if (response.data.type !== 'file') {\n throw new Error(`Unsupported content type: ${response.data.type}`);\n }\n return Buffer.from(response.data.content, 'base64').toString('utf-8');\n }\n default: {\n // @ts-expect-error exhaustive check\n throw new Error(`Unhandled skill type: ${skill.type}`);\n }\n }\n};\n\nexport const skillsDescription = `\n# Skills\n\nThis tool provides access to domain-specific skills - structured knowledge and procedures for specialized tasks.\n\n## How to Use Skills\n\n1. **Discover**: If you have not been provided the list of skills, fetch them by invoking this tool with \\`name: \".\"\\`. Use only skill names that appear in that list.\n2. **Read**: Access a skill by reading its SKILL.md file: \\`name: \"skill-name\", path: \"SKILL.md\"\\`. Use a skill name from the list (step 1); do not guess names from context or topic words.\n3. **Explore**: Navigate within the skill directory to find additional resources, examples, or templates. You can list the contents of the directory by using \\`path: \".\"\\` (relative to the skill root); use only a path that appears in that listing—do not guess or infer path names from skill descriptions or topic words (e.g. \"indexing strategies\" in text is not a path). SKILL.md and other documents may contain relative links to guide you.\n4. **Apply**: Follow the procedures and reference the knowledge in the skill to complete your task\n\n## Skill Structure\n\nEach skill contains:\n- **SKILL.md**: Main documentation (always start here)\n- **REFERENCE.md**: Quick reference card (optional)\n- Additional files: Examples, templates, scripts\n\n## When to Use Skills\n\n- Read relevant skills proactively when you identify a task that matches a skill's domain\n- Skills are meant to augment your knowledge, not replace your reasoning\n- Apply skill guidance while adapting to the specific user request\n- Skills use progressive disclosure - start with high-level guidance and drill down only as needed\n- Skills may also refer to tools or resources external to the skill itself\n- Use other tools to execute any code or scripts provided by the skill\n`.trim();\n\nconst toSet = (flag: ParsedQs[string]): Set<string> | null =>\n flag\n ? Array.isArray(flag)\n ? new Set(flag as string[])\n : typeof flag === 'string'\n ? new Set(flag.split(',').map((s) => s.trim()))\n : null\n : null;\n\nexport const parseSkillsFlags = (\n query: McpFeatureFlags['query'],\n): SkillsFlags => ({\n enabledSkills: toSet(query?.enabled_skills),\n disabledSkills: toSet(query?.disabled_skills),\n});\n\nexport const parseCollectionFlags = (\n cfg: CollectionFlagsCfg,\n): CollectionFlags => ({\n enabledSkills: toSet(cfg.enabled_skills),\n disabledSkills: toSet(cfg.disabled_skills),\n ignoredPaths: toSet(cfg.ignored_paths),\n});\n"]}
@@ -129,3 +129,4 @@ describe('Skills API', () => {
129
129
  });
130
130
  });
131
131
  });
132
+ //# sourceMappingURL=utils.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.spec.js","sourceRoot":"","sources":["../../src/skills/utils.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from 'bun:test';\nimport Path from 'node:path';\nimport {\n getAvailableSkillNames,\n InvalidPathError,\n listSkills,\n PathNotFoundError,\n SkillNotFoundError,\n viewSkillContent,\n} from './utils.js';\n\nprocess.env.SKILLS_FILE = Path.resolve(\n import.meta.dir,\n '__fixtures__',\n 'skills.yaml',\n);\n\ndescribe('Skills API', () => {\n describe('getAvailableSkillNames', () => {\n it('returns a comma-separated list of visible skill names in alphabetical order when skills are loaded', async () => {\n const names = await getAvailableSkillNames({});\n expect(names).toBe(\n 'collection-a, collection-b, first-skill, second-skill',\n );\n });\n\n it('returns \"(none)\" when flags filter out every skill (e.g. enabledSkills does not match any)', async () => {\n const names = await getAvailableSkillNames({\n flags: {\n enabledSkills: new Set(['does-not-exist']),\n disabledSkills: null,\n },\n });\n expect(names).toBe('(none)');\n });\n\n it('throws an error with message prefixed by \"getAvailableSkillNames failed:\" when something in the function fails', async () => {\n await expect(\n getAvailableSkillNames({\n flags: {\n enabledSkills: {\n has: () => {\n throw new Error('enabledSkills filter threw');\n },\n } as unknown as Set<string>,\n disabledSkills: null,\n },\n }),\n ).rejects.toThrow(\n 'getAvailableSkillNames failed: enabledSkills filter threw',\n );\n });\n });\n\n describe('listSkills and viewSkillContent (skills-api-test-plan)', () => {\n it('list all skills: returns a string containing available_skills and all loaded skill names', async () => {\n const result = await listSkills({});\n expect(result).toContain('<available_skills>');\n expect(result).toContain('first-skill');\n expect(result).toContain('second-skill');\n expect(result).toContain('collection-a');\n expect(result).toContain('collection-b');\n const inner = result\n .split('<available_skills>')[1]\n .split('</available_skills>')[0];\n const lines = inner.trim().split('\\n');\n expect(lines).toHaveLength(5);\n });\n\n it('read valid skill: returns the content of the skill SKILL.md when name and path are valid', async () => {\n const result = await viewSkillContent({\n name: 'first-skill',\n path: 'SKILL.md',\n });\n expect(result).toBe('First skill content\\n');\n });\n\n it('skill not found: viewSkillContent throws SkillNotFoundError', async () => {\n try {\n await viewSkillContent({ name: 'nonexistent-skill', path: 'SKILL.md' });\n throw new Error('Expected SkillNotFoundError to be thrown');\n } catch (err) {\n expect(err).toBeInstanceOf(SkillNotFoundError);\n expect((err as SkillNotFoundError).skillName).toBe('nonexistent-skill');\n }\n });\n\n it('skill not found with another name: throws SkillNotFoundError', async () => {\n try {\n await viewSkillContent({\n name: 'another-missing-skill',\n path: 'SKILL.md',\n });\n throw new Error('Expected SkillNotFoundError to be thrown');\n } catch (err) {\n expect(err).toBeInstanceOf(SkillNotFoundError);\n expect((err as SkillNotFoundError).skillName).toBe(\n 'another-missing-skill',\n );\n }\n });\n\n it('path not found inside valid skill: viewSkillContent throws PathNotFoundError', async () => {\n try {\n await viewSkillContent({\n name: 'first-skill',\n path: 'indexing-strategies',\n });\n throw new Error('Expected PathNotFoundError to be thrown');\n } catch (err) {\n expect(err).toBeInstanceOf(PathNotFoundError);\n expect((err as PathNotFoundError).skill).toBe('first-skill');\n expect((err as PathNotFoundError).path).toBe('indexing-strategies');\n expect((err as PathNotFoundError).listing).toContain('SKILL.md');\n }\n });\n\n it('invalid path directory traversal: viewSkillContent throws InvalidPathError', async () => {\n try {\n await viewSkillContent({\n name: 'first-skill',\n path: '../../etc/passwd',\n });\n throw new Error('Expected InvalidPathError to be thrown');\n } catch (err) {\n expect(err).toBeInstanceOf(InvalidPathError);\n expect((err as InvalidPathError).path).toBe('../../etc/passwd');\n }\n });\n\n it('invalid path with null byte: viewSkillContent throws InvalidPathError', async () => {\n await expect(\n viewSkillContent({\n name: 'first-skill',\n path: 'SKILL.md\\x00.txt',\n }),\n ).rejects.toThrow(InvalidPathError);\n });\n });\n\n describe('local_collection', () => {\n it('loads every real skill directory inside the collection', async () => {\n const names = await getAvailableSkillNames({});\n expect(names).toContain('collection-a');\n expect(names).toContain('collection-b');\n });\n\n it('exposes collection skill content via viewSkillContent', async () => {\n const result = await viewSkillContent({\n name: 'collection-a',\n path: 'SKILL.md',\n });\n expect(result).toBe('Collection skill A content\\n');\n });\n\n it('skips dot-prefixed directories (e.g. .github) even when they contain a valid SKILL.md', async () => {\n const names = await getAvailableSkillNames({});\n expect(names).not.toContain('dot-github-trap');\n await expect(\n viewSkillContent({ name: 'dot-github-trap', path: 'SKILL.md' }),\n ).rejects.toBeInstanceOf(SkillNotFoundError);\n });\n });\n});\n"]}
package/dist/stdio.js CHANGED
@@ -32,3 +32,4 @@ export const stdioServerFactory = async ({ name, version, context, apiFactories,
32
32
  process.exit(1);
33
33
  }
34
34
  };
35
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAA4B,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAOjE,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EAErC,EACA,IAAI,EACJ,OAAO,EACP,OAAO,EACP,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,YAAY,GAWb,EAAiB,EAAE;IAClB,IAAI,CAAC;QACH,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACpD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC;YACxC,IAAI;YACJ,OAAO;YACP,OAAO;YACP,YAAY;YACZ,eAAe;YACf,iBAAiB;YACjB,eAAe;YACf,YAAY;SACb,CAAC,CAAC;QAEH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,kBAAkB;QAClB,oBAAoB,CAAC;YACnB,KAAK,IAAmB,EAAE;gBACxB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;YACD,KAAK,IAAmB,EAAE;gBACxB,MAAM,SAAS,EAAE,EAAE,CAAC;YACtB,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC","sourcesContent":["#!/usr/bin/env node\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { type AdditionalSetupArgs, mcpServerFactory } from './mcpServer.js';\nimport { registerExitHandlers } from './registerExitHandlers.js';\nimport type {\n BaseApiFactory,\n BasePromptFactory,\n ResourceFactory,\n} from './types.js';\n\nexport const stdioServerFactory = async <\n Context extends Record<string, unknown>,\n>({\n name,\n version,\n context,\n apiFactories,\n promptFactories,\n resourceFactories,\n additionalSetup,\n cleanupFn,\n instructions,\n}: {\n name: string;\n version?: string;\n context: Context;\n apiFactories?: readonly BaseApiFactory<Context>[];\n promptFactories?: readonly BasePromptFactory<Context>[];\n resourceFactories?: readonly ResourceFactory<Context>[];\n additionalSetup?: (args: AdditionalSetupArgs<Context>) => void;\n cleanupFn?: () => Promise<void>;\n instructions?: string;\n}): Promise<void> => {\n try {\n console.error('Starting default (STDIO) server...');\n const transport = new StdioServerTransport();\n const { server } = await mcpServerFactory({\n name,\n version,\n context,\n apiFactories,\n promptFactories,\n resourceFactories,\n additionalSetup,\n instructions,\n });\n\n await server.connect(transport);\n\n // Cleanup on exit\n registerExitHandlers([\n async (): Promise<void> => {\n await server.close();\n },\n async (): Promise<void> => {\n await cleanupFn?.();\n },\n ]);\n } catch (error) {\n console.error('Server error:', error);\n process.exit(1);\n }\n};\n"]}
package/dist/store.d.ts CHANGED
@@ -9,6 +9,7 @@ export declare class Store<T> {
9
9
  private expirationDateTime?;
10
10
  constructor({ fetch, ttl }: StoreProps<T>);
11
11
  get(): Promise<T>;
12
+ set(value: T): void;
12
13
  }
13
14
  interface ArrayStoreProps<T> {
14
15
  fetch: () => Promise<T[]>;
package/dist/store.js CHANGED
@@ -5,21 +5,25 @@ export class Store {
5
5
  expirationDateTime;
6
6
  constructor({ fetch, ttl }) {
7
7
  this.fetch = fetch;
8
- if (ttl) {
9
- this.ttl = ttl;
10
- this.expirationDateTime = Date.now() + ttl;
11
- }
8
+ this.ttl = ttl;
12
9
  }
13
10
  async get() {
14
11
  if (this.expirationDateTime && Date.now() > this.expirationDateTime) {
15
12
  this.contents = null;
16
- if (this.ttl) {
17
- this.expirationDateTime = Date.now() + this.ttl;
18
- }
13
+ this.expirationDateTime = undefined;
19
14
  }
20
15
  this.contents ??= this.fetch();
16
+ if (this.ttl && !this.expirationDateTime) {
17
+ this.expirationDateTime = Date.now() + this.ttl;
18
+ }
21
19
  return this.contents;
22
20
  }
21
+ set(value) {
22
+ this.contents = Promise.resolve(value);
23
+ if (this.ttl) {
24
+ this.expirationDateTime = Date.now() + this.ttl;
25
+ }
26
+ }
23
27
  }
24
28
  export class ArrayStore extends Store {
25
29
  constructor({ fetch, ttl }) {
@@ -34,3 +38,4 @@ export class ArrayStore extends Store {
34
38
  return items.filter(predicate);
35
39
  }
36
40
  }
41
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,KAAK;IACR,QAAQ,GAAsB,IAAI,CAAC;IACnC,KAAK,CAAyB;IAC9B,GAAG,CAAU;IACb,kBAAkB,CAAU;IAEpC,YAAY,EAAE,KAAK,EAAE,GAAG,EAAiB;QACvC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,GAAG;QACP,IAAI,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACpE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,kBAAkB,GAAG,SAAS,CAAC;QACtC,CAAC;QACD,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QAE/B,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACzC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC;QAClD,CAAC;QAED,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,GAAG,CAAC,KAAQ;QACV,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC;QAClD,CAAC;IACH,CAAC;CACF;AAOD,MAAM,OAAO,UAAc,SAAQ,KAAU;IAC3C,YAAY,EAAE,KAAK,EAAE,GAAG,EAAsB;QAC5C,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,SAA+B;QACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,SAA+B;QAC1C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;CACF","sourcesContent":["interface StoreProps<T> {\n fetch: () => Promise<T>;\n ttl?: number; // amount of time in milliseconds after which cached data will be considered stale\n}\n\nexport class Store<T> {\n private contents: Promise<T> | null = null;\n private fetch: StoreProps<T>['fetch'];\n private ttl?: number;\n private expirationDateTime?: number;\n\n constructor({ fetch, ttl }: StoreProps<T>) {\n this.fetch = fetch;\n this.ttl = ttl;\n }\n\n async get(): Promise<T> {\n if (this.expirationDateTime && Date.now() > this.expirationDateTime) {\n this.contents = null;\n this.expirationDateTime = undefined;\n }\n this.contents ??= this.fetch();\n\n if (this.ttl && !this.expirationDateTime) {\n this.expirationDateTime = Date.now() + this.ttl;\n }\n\n return this.contents;\n }\n\n set(value: T): void {\n this.contents = Promise.resolve(value);\n if (this.ttl) {\n this.expirationDateTime = Date.now() + this.ttl;\n }\n }\n}\n\ninterface ArrayStoreProps<T> {\n fetch: () => Promise<T[]>;\n ttl?: number;\n}\n\nexport class ArrayStore<T> extends Store<T[]> {\n constructor({ fetch, ttl }: ArrayStoreProps<T>) {\n super({ fetch, ttl });\n }\n\n async find(predicate: (item: T) => boolean): Promise<T | null> {\n const items = await this.get();\n return items.find(predicate) ?? null;\n }\n\n async filter(predicate: (item: T) => boolean): Promise<T[]> {\n const items = await this.get();\n return items.filter(predicate);\n }\n}\n"]}
package/dist/testSetup.js CHANGED
@@ -12,3 +12,4 @@ if (!process.env.VERBOSE_TESTS) {
12
12
  console.error = noop;
13
13
  }
14
14
  export {};
15
+ //# sourceMappingURL=testSetup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testSetup.js","sourceRoot":"","sources":["../src/testSetup.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,2EAA2E;AAC3E,8EAA8E;AAC9E,8EAA8E;AAC9E,kBAAkB;AAElB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IACtB,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;IACnB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IACpB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IACpB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;AACvB,CAAC","sourcesContent":["// Test preload (configured via bunfig.toml) that silences console output so\n// successful `bun test` / `bun check` runs stay quiet. Our logger and some\n// dependencies write directly to the console, which would otherwise flood the\n// output with logs. Set VERBOSE_TESTS=1 to keep the original console behavior\n// when debugging.\n\nif (!process.env.VERBOSE_TESTS) {\n const noop = () => {};\n console.log = noop;\n console.info = noop;\n console.debug = noop;\n console.warn = noop;\n console.error = noop;\n}\n"]}
package/dist/tracing.js CHANGED
@@ -72,3 +72,4 @@ export const addAiResultToSpan = (span, aiResult, inputMessages) => {
72
72
  span.setAttribute('gen_ai.usage.output_tokens', aiResult.totalUsage.outputTokens || 0);
73
73
  }
74
74
  };
75
+ //# sourceMappingURL=tracing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.js","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Span, SpanStatusCode, type Tracer } from '@opentelemetry/api';\nimport type { generateText, ModelMessage, ToolResultPart } from 'ai';\nimport { log } from './logger.js';\n\n// The generic parameters of `GenerateTextResult` (runtime context and output)\n// are not exported by `ai`, so derive the broad result type from\n// `generateText` itself, which instantiates them with its defaults.\ntype AnyGenerateTextResult = Awaited<ReturnType<typeof generateText>>;\n\nexport const withSpan = async <T>(\n tracer: Tracer,\n name: string,\n fn: (span: Span) => Promise<T>,\n): Promise<T> => {\n return tracer.startActiveSpan(name, async (span) => {\n try {\n return await fn(span);\n } catch (error) {\n log.error(`Error in span ${name}`, error as Error);\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n });\n throw error;\n } finally {\n span.end();\n }\n });\n};\n\nconst getToolContent = (content: ToolResultPart): unknown => {\n const { output } = content;\n // The `execution-denied` output variant carries no `value` field.\n if (!('value' in output)) {\n return output;\n }\n const { type, value } = output;\n if (type === 'json' && value) {\n if (typeof value === 'object' && 'structuredContent' in value) {\n return value.structuredContent;\n } else if (typeof value === 'object' && 'content' in value) {\n return value.content;\n }\n return value;\n } else if (value) {\n return value;\n }\n return output;\n};\n\nconst annotateModelMessage = (\n m: ModelMessage,\n i: number,\n): Record<string, unknown> => {\n const msg: Record<string, unknown> = {\n ...m,\n 'event.name': `gen_ai.${m.role}.message`,\n 'gen_ai.message.index': Math.max(0, i - 1),\n };\n if (m.role === 'tool' && Array.isArray(m.content)) {\n const [c] = m.content;\n // A tool message's content may also include tool-approval responses,\n // which have no tool result to annotate.\n if (c?.type === 'tool-result') {\n msg.id = c.toolCallId;\n msg.name = c.toolName;\n msg.content = getToolContent(c);\n }\n }\n return msg;\n};\n\nexport const addAiResultToSpan = (\n span: Span,\n aiResult: AnyGenerateTextResult,\n inputMessages: ModelMessage[],\n): void => {\n span.setAttribute('final_result', aiResult.text);\n const messages = [...inputMessages, ...aiResult.response.messages].map(\n annotateModelMessage,\n );\n span.setAttribute('all_messages_events', JSON.stringify(messages));\n // This is required for logfire to parse the events properly\n span.setAttribute(\n 'logfire.json_schema',\n JSON.stringify({\n type: 'object',\n properties: { all_messages_events: { type: 'array' } },\n }),\n );\n if (aiResult.totalUsage) {\n span.setAttribute(\n 'gen_ai.usage.input_tokens',\n aiResult.totalUsage.inputTokens || 0,\n );\n span.setAttribute(\n 'gen_ai.usage.output_tokens',\n aiResult.totalUsage.outputTokens || 0,\n );\n }\n};\n"]}
package/dist/types.js CHANGED
@@ -1 +1,2 @@
1
1
  export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n CompleteResourceTemplateCallback,\n ListResourcesCallback,\n ReadResourceCallback,\n ReadResourceTemplateCallback,\n ResourceMetadata,\n} from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type {\n GetPromptResult,\n ToolAnnotations,\n} from '@modelcontextprotocol/sdk/types.js';\nimport type { Router } from 'express';\nimport type { ZodRawShape, z } from 'zod';\n\n// Compatibility helper: works with both Zod 3 and Zod 4\n// Replaces z.objectOutputType which was removed in Zod 4\ntype ObjectOutput<T extends ZodRawShape> = z.infer<z.ZodObject<T>>;\n\n// ===== Base types (type-erased for heterogeneous collections) =====\n\nexport type BaseToolConfig = {\n title?: string;\n description?: string;\n inputSchema: ZodRawShape;\n outputSchema: ZodRawShape;\n annotations?: ToolAnnotations;\n};\n\nexport interface BaseApiDefinition {\n name: string;\n method?: 'get' | 'post' | 'put' | 'delete';\n route?: string | string[];\n config: BaseToolConfig;\n disabled?: boolean;\n // Method syntax is bivariant, allowing typed extensions to override with narrower types\n fn(args: Record<string, unknown>): Promise<Record<string, unknown>>;\n pickResult?(result: Record<string, unknown>): unknown;\n}\n\nexport type BaseApiFactory<Context extends Record<string, unknown>> = (\n ctx: Context,\n featureFlags: McpFeatureFlags,\n) => BaseApiDefinition | Promise<BaseApiDefinition>;\n\nexport type BasePromptConfig = {\n title?: string;\n description?: string;\n inputSchema: ZodRawShape;\n};\n\nexport interface BasePromptDefinition {\n name: string;\n config: BasePromptConfig;\n disabled?: boolean;\n // Method syntax is bivariant, allowing typed extensions to override with narrower types\n fn(args: Record<string, unknown>): Promise<GetPromptResult>;\n}\n\nexport type BasePromptFactory<Context extends Record<string, unknown>> = (\n ctx: Context,\n featureFlags: McpFeatureFlags,\n) => BasePromptDefinition | Promise<BasePromptDefinition>;\n\n// ===== Typed versions (for implementations) =====\n\nexport type ToolConfig<\n InputArgs extends ZodRawShape,\n OutputArgs extends ZodRawShape,\n> = {\n title?: string;\n description?: string;\n inputSchema: InputArgs;\n outputSchema: OutputArgs;\n annotations?: ToolAnnotations;\n};\n\nexport interface ApiDefinition<\n InputArgs extends ZodRawShape,\n OutputArgs extends ZodRawShape,\n SimplifiedOutputArgs = OutputArgs,\n> extends BaseApiDefinition {\n config: ToolConfig<InputArgs, OutputArgs>;\n fn(args: ObjectOutput<InputArgs>): Promise<ObjectOutput<OutputArgs>>;\n pickResult?(result: ObjectOutput<OutputArgs>): SimplifiedOutputArgs;\n}\n\nexport type ApiFactory<\n Context extends Record<string, unknown>,\n Input extends ZodRawShape,\n Output extends ZodRawShape,\n RestOutput = Output,\n> = (\n ctx: Context,\n featureFlags: McpFeatureFlags,\n) =>\n | ApiDefinition<Input, Output, RestOutput>\n | Promise<ApiDefinition<Input, Output, RestOutput>>;\n\nexport type RouterFactoryResult = [Router, () => void | Promise<void>];\n\nexport type PromptConfig<InputArgs extends ZodRawShape> = {\n title?: string;\n description?: string;\n inputSchema: InputArgs;\n};\n\nexport interface PromptDefinition<InputArgs extends ZodRawShape>\n extends BasePromptDefinition {\n config: PromptConfig<InputArgs>;\n fn(args: ObjectOutput<InputArgs>): Promise<GetPromptResult>;\n}\n\nexport type PromptFactory<\n Context extends Record<string, unknown>,\n Input extends ZodRawShape,\n> = (ctx: Context, featureFlags: McpFeatureFlags) => PromptDefinition<Input>;\n\nexport interface TemplatedResourceDefinition {\n type: 'templated';\n name: string;\n uriTemplate: string;\n list?: ListResourcesCallback;\n complete?: {\n [variable: string]: CompleteResourceTemplateCallback;\n };\n config: ResourceMetadata;\n disabled?: boolean;\n read: ReadResourceTemplateCallback;\n}\n\nexport interface StaticResourceDefinition {\n type: 'static';\n name: string;\n uri: string;\n config: ResourceMetadata;\n disabled?: boolean;\n read: ReadResourceCallback;\n}\n\nexport type ResourceDefinition =\n | TemplatedResourceDefinition\n | StaticResourceDefinition;\n\nexport type ResourceFactory<Context extends Record<string, unknown>> = (\n ctx: Context,\n featureFlags: McpFeatureFlags,\n) => ResourceDefinition | Promise<ResourceDefinition>;\n\nexport interface ParsedQs {\n [key: string]: undefined | string | ParsedQs | (string | ParsedQs)[];\n}\n\nexport interface McpFeatureFlags {\n prompts?: boolean;\n enabledPrompts?: Set<string> | null;\n disabledPrompts?: Set<string> | null;\n resources?: boolean;\n enabledResources?: Set<string> | null;\n disabledResources?: Set<string> | null;\n tools?: boolean;\n enabledTools?: Set<string> | null;\n disabledTools?: Set<string> | null;\n query?: ParsedQs;\n}\n\n// Helper type to flatten intersection types\ntype Flatten<T> = { [K in keyof T]: T[K] } & {};\n\n// Helper type to extract keys where the Zod type is optional\ntype OptionalKeys<T extends Record<string, z.ZodType>> = {\n [K in keyof T]: T[K] extends z.ZodOptional<z.ZodType> ? K : never;\n}[keyof T];\n\n// Helper type to extract keys where the Zod type is required\ntype RequiredKeys<T extends Record<string, z.ZodType>> = {\n [K in keyof T]: T[K] extends z.ZodOptional<z.ZodType> ? never : K;\n}[keyof T];\n\nexport type InferSchema<T extends Record<string, z.ZodType>> = Flatten<\n {\n [K in RequiredKeys<T>]: z.infer<T[K]>;\n } & {\n [K in OptionalKeys<T>]?: z.infer<T[K]>;\n }\n>;\n\nexport interface MigrationsConfig {\n serviceName: string;\n migrationsDirectory?: string;\n schema?: string;\n}\n"]}
@@ -151,3 +151,4 @@ describe('InferSchema', () => {
151
151
  expect(parsedFull.deletedAt).toEqual(now);
152
152
  });
153
153
  });
154
+ //# sourceMappingURL=types.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.spec.js","sourceRoot":"","sources":["../src/types.spec.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, expectTypeOf, it } from 'bun:test';\nimport { z } from 'zod';\nimport type { InferSchema } from './types.js';\n\ndescribe('InferSchema', () => {\n it('should infer required properties correctly', () => {\n const schema = {\n name: z.string(),\n age: z.number(),\n };\n const zodSchema = z.object(schema);\n\n type Result = InferSchema<typeof schema>;\n\n // Type-level assertion (checked by tsc --noEmit)\n expectTypeOf<Result>().toEqualTypeOf<{\n name: string;\n age: number;\n }>();\n\n // Runtime check with zod validation\n const valid: Result = { name: 'John', age: 30 };\n const parsed = zodSchema.parse(valid);\n expect(parsed.name).toBe('John');\n expect(parsed.age).toBe(30);\n });\n\n it('should make optional zod properties optional in the inferred type', () => {\n const schema = {\n name: z.string(),\n nickname: z.string().optional(),\n };\n const zodSchema = z.object(schema);\n\n type Result = InferSchema<typeof schema>;\n\n // Type-level assertion (checked by tsc --noEmit)\n // nickname should be optional (string | undefined with optional key)\n expectTypeOf<Result>().toEqualTypeOf<{\n name: string;\n nickname?: string | undefined;\n }>();\n\n // Runtime checks - should compile without providing nickname\n const withoutNickname: Result = { name: 'John' };\n const parsedWithout = zodSchema.parse(withoutNickname);\n expect(parsedWithout.name).toBe('John');\n expect(parsedWithout.nickname).toBeUndefined();\n\n // Should also compile with nickname provided\n const withNickname: Result = { name: 'John', nickname: 'Johnny' };\n const parsedWith = zodSchema.parse(withNickname);\n expect(parsedWith.nickname).toBe('Johnny');\n });\n\n it('should handle nullable properties', () => {\n const schema = {\n name: z.string(),\n middleName: z.string().nullable(),\n };\n const zodSchema = z.object(schema);\n\n type Result = InferSchema<typeof schema>;\n\n // Type-level assertion (checked by tsc --noEmit)\n // Nullable properties should still be required, but allow null\n expectTypeOf<Result>().toEqualTypeOf<{\n name: string;\n middleName: string | null;\n }>();\n\n // Runtime checks with zod validation\n const withNull: Result = { name: 'John', middleName: null };\n const parsedNull = zodSchema.parse(withNull);\n expect(parsedNull.middleName).toBeNull();\n\n const withValue: Result = { name: 'John', middleName: 'William' };\n const parsedValue = zodSchema.parse(withValue);\n expect(parsedValue.middleName).toBe('William');\n });\n\n it('should handle optional and nullable combined', () => {\n const schema = {\n name: z.string(),\n suffix: z.string().nullable().optional(),\n };\n const zodSchema = z.object(schema);\n\n type Result = InferSchema<typeof schema>;\n\n // Type-level assertion (checked by tsc --noEmit)\n // Should be optional and nullable\n expectTypeOf<Result>().toEqualTypeOf<{\n name: string;\n suffix?: string | null | undefined;\n }>();\n\n // Runtime checks with zod validation\n const withoutSuffix: Result = { name: 'John' };\n const parsedWithout = zodSchema.parse(withoutSuffix);\n expect(parsedWithout.suffix).toBeUndefined();\n\n const withNull: Result = { name: 'John', suffix: null };\n const parsedNull = zodSchema.parse(withNull);\n expect(parsedNull.suffix).toBeNull();\n\n const withValue: Result = { name: 'John', suffix: 'Jr.' };\n const parsedValue = zodSchema.parse(withValue);\n expect(parsedValue.suffix).toBe('Jr.');\n });\n\n it('should handle complex nested schemas', () => {\n const schema = {\n user: z.object({\n name: z.string(),\n email: z.string().optional(),\n }),\n metadata: z\n .object({\n createdAt: z.date(),\n })\n .optional(),\n };\n const zodSchema = z.object(schema);\n\n type Result = InferSchema<typeof schema>;\n\n // Type-level assertion (checked by tsc --noEmit)\n // metadata should be optional\n expectTypeOf<Result>().toEqualTypeOf<{\n user: {\n name: string;\n email?: string | undefined;\n };\n metadata?:\n | {\n createdAt: Date;\n }\n | undefined;\n }>();\n\n // Runtime checks with zod validation\n const withoutMetadata: Result = {\n user: { name: 'John' },\n };\n const parsedWithout = zodSchema.parse(withoutMetadata);\n expect(parsedWithout.user.name).toBe('John');\n expect(parsedWithout.metadata).toBeUndefined();\n\n const now = new Date();\n const withMetadata: Result = {\n user: { name: 'John', email: 'john@example.com' },\n metadata: { createdAt: now },\n };\n const parsedWith = zodSchema.parse(withMetadata);\n expect(parsedWith.metadata?.createdAt).toEqual(now);\n });\n\n it('should handle arrays with optional elements', () => {\n const schema = {\n items: z.array(z.string()),\n tags: z.array(z.string()).optional(),\n };\n const zodSchema = z.object(schema);\n\n type Result = InferSchema<typeof schema>;\n\n // Type-level assertion (checked by tsc --noEmit)\n // tags should be optional\n expectTypeOf<Result>().toEqualTypeOf<{\n items: string[];\n tags?: string[] | undefined;\n }>();\n\n // Runtime checks with zod validation\n const withoutTags: Result = { items: ['a', 'b'] };\n const parsedWithout = zodSchema.parse(withoutTags);\n expect(parsedWithout.items).toEqual(['a', 'b']);\n expect(parsedWithout.tags).toBeUndefined();\n\n const withTags: Result = { items: ['a'], tags: ['tag1', 'tag2'] };\n const parsedWith = zodSchema.parse(withTags);\n expect(parsedWith.tags).toEqual(['tag1', 'tag2']);\n });\n\n it('should correctly type a mixed schema', () => {\n const schema = {\n id: z.string(),\n description: z.string().optional(),\n count: z.number(),\n deletedAt: z.date().nullable().optional(),\n };\n const zodSchema = z.object(schema);\n\n type Result = InferSchema<typeof schema>;\n\n // Type-level assertion (checked by tsc --noEmit)\n expectTypeOf<Result>().toEqualTypeOf<{\n id: string;\n description?: string | undefined;\n count: number;\n deletedAt?: Date | null | undefined;\n }>();\n\n // Runtime checks - minimal valid object (only required fields)\n const minimal: Result = {\n id: '123',\n count: 0,\n };\n const parsedMinimal = zodSchema.parse(minimal);\n expect(parsedMinimal.id).toBe('123');\n expect(parsedMinimal.count).toBe(0);\n\n // Full object\n const now = new Date();\n const full: Result = {\n id: '456',\n description: 'A test',\n count: 5,\n deletedAt: now,\n };\n const parsedFull = zodSchema.parse(full);\n expect(parsedFull.description).toBe('A test');\n expect(parsedFull.deletedAt).toEqual(now);\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tigerdata/mcp-boilerplate",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "MCP boilerplate code for Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "author": "TigerData",