tracelattice 1.3.3 → 1.3.4

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 (83) hide show
  1. package/dist/ServerConfig.d.ts +14 -0
  2. package/dist/ServerConfig.d.ts.map +1 -1
  3. package/dist/ServerConfig.js +12 -1
  4. package/dist/ServerConfig.js.map +1 -1
  5. package/dist/__tests__/core/HistoryManager.ownership.test.d.ts +2 -0
  6. package/dist/__tests__/core/HistoryManager.ownership.test.d.ts.map +1 -0
  7. package/dist/__tests__/core/SessionLock.test.d.ts +6 -0
  8. package/dist/__tests__/core/SessionLock.test.d.ts.map +1 -0
  9. package/dist/__tests__/core/SessionManager.test.d.ts +8 -0
  10. package/dist/__tests__/core/SessionManager.test.d.ts.map +1 -0
  11. package/dist/__tests__/core/ThoughtProcessor.toolAllowlist.test.d.ts +2 -0
  12. package/dist/__tests__/core/ThoughtProcessor.toolAllowlist.test.d.ts.map +1 -0
  13. package/dist/__tests__/helpers/factories.d.ts +7 -0
  14. package/dist/__tests__/helpers/factories.d.ts.map +1 -1
  15. package/dist/__tests__/sanitize.enforceJsonShape.test.d.ts +2 -0
  16. package/dist/__tests__/sanitize.enforceJsonShape.test.d.ts.map +1 -0
  17. package/dist/__tests__/transport-owner-context.test.d.ts +8 -0
  18. package/dist/__tests__/transport-owner-context.test.d.ts.map +1 -0
  19. package/dist/cli.js +176 -57
  20. package/dist/config/ConfigLoader.d.ts +7 -0
  21. package/dist/config/ConfigLoader.d.ts.map +1 -1
  22. package/dist/config/ConfigLoader.js +6 -1
  23. package/dist/config/ConfigLoader.js.map +1 -1
  24. package/dist/context/RequestContext.d.ts +26 -0
  25. package/dist/context/RequestContext.d.ts.map +1 -1
  26. package/dist/context/RequestContext.js +7 -1
  27. package/dist/context/RequestContext.js.map +1 -1
  28. package/dist/contracts/features.d.ts +2 -2
  29. package/dist/contracts/features.js.map +1 -1
  30. package/dist/contracts/interfaces.d.ts +42 -0
  31. package/dist/contracts/interfaces.d.ts.map +1 -1
  32. package/dist/core/HistoryManager.d.ts +13 -1
  33. package/dist/core/HistoryManager.d.ts.map +1 -1
  34. package/dist/core/HistoryManager.js +25 -14
  35. package/dist/core/HistoryManager.js.map +1 -1
  36. package/dist/core/InputNormalizer.d.ts.map +1 -1
  37. package/dist/core/InputNormalizer.js +5 -2
  38. package/dist/core/InputNormalizer.js.map +1 -1
  39. package/dist/core/SessionLock.d.ts +56 -0
  40. package/dist/core/SessionLock.d.ts.map +1 -0
  41. package/dist/core/SessionLock.js +43 -0
  42. package/dist/core/SessionLock.js.map +1 -0
  43. package/dist/core/SessionManager.d.ts +18 -3
  44. package/dist/core/SessionManager.d.ts.map +1 -1
  45. package/dist/core/SessionManager.js +34 -1
  46. package/dist/core/SessionManager.js.map +1 -1
  47. package/dist/core/ThoughtProcessor.d.ts +21 -2
  48. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  49. package/dist/core/ThoughtProcessor.js +33 -13
  50. package/dist/core/ThoughtProcessor.js.map +1 -1
  51. package/dist/di/ServiceRegistry.d.ts +3 -3
  52. package/dist/di/ServiceRegistry.d.ts.map +1 -1
  53. package/dist/errors.d.ts +48 -0
  54. package/dist/errors.d.ts.map +1 -1
  55. package/dist/errors.js +38 -2
  56. package/dist/errors.js.map +1 -1
  57. package/dist/lib.d.ts.map +1 -1
  58. package/dist/lib.js +9 -3
  59. package/dist/lib.js.map +1 -1
  60. package/dist/registry/ToolRegistry.d.ts +1 -0
  61. package/dist/registry/ToolRegistry.d.ts.map +1 -1
  62. package/dist/registry/ToolRegistry.js +3 -0
  63. package/dist/registry/ToolRegistry.js.map +1 -1
  64. package/dist/sanitize.d.ts +70 -0
  65. package/dist/sanitize.d.ts.map +1 -1
  66. package/dist/sanitize.js +77 -1
  67. package/dist/sanitize.js.map +1 -1
  68. package/dist/schema.d.ts +35 -35
  69. package/dist/schema.d.ts.map +1 -1
  70. package/dist/schema.js +15 -5
  71. package/dist/schema.js.map +1 -1
  72. package/dist/transport/HttpTransport.d.ts.map +1 -1
  73. package/dist/transport/HttpTransport.js +9 -3
  74. package/dist/transport/HttpTransport.js.map +1 -1
  75. package/dist/transport/SseTransport.d.ts.map +1 -1
  76. package/dist/transport/SseTransport.js +10 -3
  77. package/dist/transport/SseTransport.js.map +1 -1
  78. package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
  79. package/dist/transport/StreamableHttpTransport.js +8 -3
  80. package/dist/transport/StreamableHttpTransport.js.map +1 -1
  81. package/dist/types/tool.d.ts +1 -1
  82. package/dist/types/tool.d.ts.map +1 -1
  83. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sources":["../src/schema.ts"],"sourcesContent":["/**\n * Valibot validation schemas for the sequential thinking MCP tool.\n *\n * This module defines the validation schemas used for the sequential thinking tool,\n * including schemas for tool recommendations, skill recommendations, step recommendations,\n * and the main sequential thinking input. All schemas use Valibot for runtime validation\n * and provide detailed descriptions for MCP protocol compatibility.\n *\n * @remarks\n * **Schema Overview:**\n * - `ToolRecommendationSchema` - Validates tool recommendation objects with confidence scores\n * - `SkillRecommendationSchema` - Validates skill recommendation objects\n * - `StepRecommendationSchema` - Validates step coordination structures\n * - `SequentialThinkingSchema` - Main schema for thought input validation\n * - Reasoning enhancement fields: thought_type, quality_score, confidence, hypothesis_id, etc.\n *\n * @example\n * ```typescript\n * import { SequentialThinkingSchema } from './schema.js';\n * import { safeParse } from 'valibot';\n *\n * const result = safeParse(SequentialThinkingSchema, inputData);\n * if (result.success) {\n * const thought = result.output;\n * // Process the valid thought\n * } else {\n * console.error('Validation failed:', result.issues);\n * }\n * ```\n * @module schema\n */\n\nimport * as v from 'valibot';\nimport type { Tool } from './types/tool.js';\nimport type { Edge, EdgeKind } from './core/graph/Edge.js';\n/**\n * Detailed description for the sequential thinking tool.\n *\n * This description is shown to LLMs when they consider using this tool.\n * It explains when to use the tool, its features, parameters, and best practices.\n */\nconst TOOL_DESCRIPTION = `A detailed tool for dynamic and reflective problem-solving through thoughts.\nThis tool helps analyze problems through a flexible thinking process that can adapt and evolve.\nEach thought can build on, question, or revise previous insights as understanding deepens.\n\nIMPORTANT: This server facilitates sequential thinking with MCP tool coordination and skill recommendations. The LLM analyzes available tools and skills to make intelligent recommendations, which are then tracked and organized by this server.\n\nWhen to use this tool:\n- Breaking down complex problems into steps\n- Planning and design with room for revision\n- Analysis that might need course correction\n- Problems where the full scope might not be clear initially\n- Problems that require a multi-step solution\n- Tasks that need to maintain context over multiple steps\n- Situations where irrelevant information needs to be filtered out\n- When you need guidance on which tools to use and in what order\n- When you need guidance on which skills to invoke for specific workflows\n\nKey features:\n- You can adjust total_thoughts up or down as you progress\n- You can question or revise previous thoughts\n- You can add more thoughts even after reaching what seemed like the end\n- You can express uncertainty and explore alternative approaches\n- Not every thought needs to build linearly - you can branch or backtrack\n- Generates a solution hypothesis\n- Verifies the hypothesis based on the Chain of Thought steps\n- Recommends appropriate tools for each step\n- Recommends appropriate skills alongside tools\n- Provides rationale for tool recommendations\n- Suggests tool execution order and parameters\n- Tracks previous recommendations and remaining steps\n\nParameters explained:\n- available_mcp_tools: (Optional) Array of MCP tool names that are available for use (e.g., [\"mcp-omnisearch\", \"mcp-turso-cloud\"])\n- available_skills: (Optional) Array of skill names that are available for use (e.g., [\"commit\", \"review-pr\", \"pdf\"])\n- thought: Your current thinking step, which can include:\n* Regular analytical steps\n* Revisions of previous thoughts\n* Questions about previous decisions\n* Realizations about needing more analysis\n* Changes in approach\n* Hypothesis generation\n* Hypothesis verification\n* Tool recommendations and rationale\n- next_thought_needed: True if you need more thinking, even if at what seemed like the end\n- thought_number: Current number in sequence (can go beyond initial total if needed)\n- total_thoughts: Current estimate of thoughts needed (can be adjusted up/down)\n- is_revision: A boolean indicating if this thought revises previous thinking\n- revises_thought: If is_revision is true, which thought number is being reconsidered\n- branch_from_thought: If branching, which thought number is the branching point\n- branch_id: Identifier for the current branch (if any)\n- needs_more_thoughts: If reaching end but realizing more thoughts needed\n- current_step: Current step recommendation, including:\n* step_description: What needs to be done\n* recommended_tools: (CRITICAL: PLURAL - \"recommended_tools\" with an 's') Tools recommended for this step - MUST be an array.\n* recommended_skills: (CRITICAL: PLURAL - \"recommended_skills\" with an 's') Skills recommended for this step (optional) - MUST be an array.\n* expected_outcome: What to expect from this step\n* next_step_conditions: Conditions to consider for the next step\n- previous_steps: Steps already recommended (each step MUST use \"recommended_tools\" PLURAL)\n- remaining_steps: High-level descriptions of upcoming steps\n\nReasoning Enhancement Parameters:\n- thought_type: Thought purpose: 'regular' (default), 'hypothesis', 'verification', 'critique', 'synthesis', 'meta', 'tool_call' (requires toolInterleave flag), 'tool_observation' (requires toolInterleave flag), 'assumption' (requires newThoughtTypes flag), 'decomposition' (requires newThoughtTypes flag), 'backtrack' (requires newThoughtTypes flag; logically retracts the thought referenced by backtrack_target - the target remains in history but is excluded from quality calculations)\n- quality_score: Self-assessed quality of this thought (0-1)\n- confidence: Confidence in this thought's correctness (0-1)\n- hypothesis_id: Links hypothesis to verification (alphanumeric, hyphens, underscores)\n- verification_target: For 'verification'/'critique' types, the thought_number being evaluated\n- synthesis_sources: For 'synthesis' type, the thought_numbers being combined\n- merge_from_thoughts: Thought numbers from other branches merged (graph reasoning)\n- merge_branch_ids: Branch IDs merged into current context\n- meta_observation: Observation about reasoning process (with thought_type 'meta')\n- reasoning_depth: How deep to reason: 'shallow' (quick), 'moderate' (default), 'deep' (thorough)\n- session_id: (Optional) Unique identifier to scope thought history, branches, and statistics to an isolated session. When provided, all state is scoped to this session ID. When omitted, uses shared global state (backward compatible). Format: alphanumeric, hyphens, underscores, 1-100 chars.\n- reset_state: (Optional) When true, clears all state for the target session (or global state if no session_id) before processing the current thought. Use this to start a fresh reasoning chain without accumulated state from previous chains.\n\nResponse Enrichment:\n- When reasoning fields are set, response includes confidence_signals (depth, revision/branch count, type distribution, avg confidence, structural_quality, quality_components) and reasoning_stats (hypothesis tracking)\n- confidence_signals.structural_quality: Composite 0-1 score — weighted geometric mean of type_diversity (0.3), verification_coverage (0.3), depth_efficiency (0.2), confidence_stability (0.2). Weights: type_diversity=0.3, verification_coverage=0.3, depth_efficiency=0.2, confidence_stability=0.2 (weighted geometric mean). All components floored at 0.01 to prevent collapse.\n- confidence_signals.quality_components: Individual metrics — type_diversity (Shannon entropy/log₂(6)), verification_coverage (verified/total hypotheses, 1.0 if none), depth_efficiency (max(chain_depth, branch_count+1)/total, branching rewarded), confidence_stability (1 - stddev(confidence), default 0.5, null when fewer than 2 confidence values)\n- reasoning_hints: (Conditional) Array of actionable hint strings from cross-thought pattern analysis. Only warning-severity patterns produce hints. Max 3 hints per response, with 3-thought cooldown per pattern per session. Hints are prioritized: confidence_drift > unverified_hypothesis > no_alternatives_explored > consecutive_without_verification, so the most actionable patterns fill the cap first. Present only when warnings are detected.\n- Detected patterns (internal, not in response): consecutive_without_verification (3+ regular thoughts without verification), unverified_hypothesis (hypothesis without verification within 3 thoughts after it), no_alternatives_explored (5+ thoughts with no critique/branches), monotonic_type (5+ consecutive same type), confidence_drift (3+ consecutive decreasing confidence), healthy_verification (hypothesis verified within 3 thoughts — info only)\nYou should:\n1. Start with an initial estimate of needed thoughts, but be ready to adjust\n2. Feel free to question or revise previous thoughts\n3. Don't hesitate to add more thoughts if needed, even at the \"end\"\n4. Express uncertainty when present\n5. Mark thoughts that revise previous thinking or branch into new paths\n6. Ignore information that is irrelevant to the current step\n7. Generate a solution hypothesis when appropriate\n8. Verify the hypothesis based on the Chain of Thought steps\n9. Consider available tools that could help with the current step\n10. Provide clear rationale for tool recommendations\n11. Suggest specific tool parameters when appropriate\n12. Consider alternative tools for each step\n13. Track progress through the recommended steps\n14. Consider available skills that provide workflows for complex tasks\n15. Coordinate skill invocation with tool recommendations (skills may call tools)\n16. Provide a single, ideally correct answer as the final output\n17. Only set next_thought_needed to false when truly done and a satisfactory answer is reached\n18. Classify your reasoning steps using thought_type for better analytics and self-awareness\n19. Use hypothesis → verification chains to test solutions before committing\n20. Self-assess quality and confidence to track reasoning reliability\n21. Use merge_from_thoughts to combine insights from multiple reasoning branches\n22. Use session_id to isolate independent reasoning chains from each other\n23. Use reset_state: true when starting a completely new analysis to avoid statistical contamination from previous chains`;\n\n/**\n * Valibot schema for validating tool recommendation objects.\n *\n * Validates that a tool recommendation has:\n * - A tool name (string)\n * - A confidence score between 0 and 1\n * - A rationale explaining the recommendation\n * - A priority number for ordering\n * - Optional suggested input parameters\n * - Optional alternative tools\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { ToolRecommendationSchema } from './schema.js';\n *\n * const result = safeParse(ToolRecommendationSchema, {\n * tool_name: 'mcp__tavily-mcp__tavily-search',\n * confidence: 0.9,\n * rationale: 'Best for web search',\n * priority: 1\n * });\n * ```\n */\nexport const ToolRecommendationSchema = v.object({\n\ttool_name: v.pipe(v.string(), v.description('Name of the tool being recommended')),\n\tconfidence: v.pipe(\n\t\tv.number(),\n\t\tv.minValue(0),\n\t\tv.maxValue(1),\n\t\tv.description('0-1 indicating confidence in recommendation')\n\t),\n\trationale: v.pipe(v.string(), v.description('Why this tool is recommended')),\n\tpriority: v.optional(\n\t\tv.pipe(v.number(), v.description('Order in the recommendation sequence (default: 999)'))\n\t),\n\tsuggested_inputs: v.optional(\n\t\tv.pipe(v.record(v.string(), v.unknown()), v.description('Optional suggested parameters'))\n\t),\n\talternatives: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Alternative tools that could be used'))\n\t),\n});\n\n/**\n * Valibot schema for validating skill recommendation objects.\n *\n * Validates that a skill recommendation has:\n * - A skill name (string)\n * - A confidence score between 0 and 1\n * - A rationale explaining the recommendation\n * - A priority number for ordering\n * - Optional alternative skills\n * - Optional allowed tools list\n * - Optional user invocable flag\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { SkillRecommendationSchema } from './schema.js';\n *\n * const result = safeParse(SkillRecommendationSchema, {\n * skill_name: 'commit',\n * confidence: 0.95,\n * rationale: 'Handles git commit workflow',\n * priority: 1,\n * user_invocable: true\n * });\n * ```\n */\nexport const SkillRecommendationSchema = v.object({\n\tskill_name: v.pipe(v.string(), v.description('Name of the skill being recommended')),\n\tconfidence: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('0-1 indicating confidence in recommendation (default: 0.5)')\n\t\t)\n\t),\n\trationale: v.optional(\n\t\tv.pipe(v.string(), v.description('Why this skill is recommended (default: empty string)'))\n\t),\n\tpriority: v.optional(\n\t\tv.pipe(v.number(), v.description('Order in the recommendation sequence (default: 999)'))\n\t),\n\talternatives: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Alternative skills that could be used'))\n\t),\n\tallowed_tools: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.string()),\n\t\t\tv.description('Tools this skill is allowed to use (from skill frontmatter)')\n\t\t)\n\t),\n\tuser_invocable: v.optional(\n\t\tv.pipe(v.boolean(), v.description('Whether this skill can be user-invoked'))\n\t),\n});\n\n/**\n * Valibot schema for validating step recommendation objects.\n *\n * Validates that a step recommendation has:\n * - A step description\n * - An array of recommended tools\n * - An optional array of recommended skills\n * - An expected outcome\n * - Optional conditions for the next step\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { StepRecommendationSchema } from './schema.js';\n *\n * const result = safeParse(StepRecommendationSchema, {\n * step_description: 'Search for TypeScript files',\n * recommended_tools: [{ ... }],\n * expected_outcome: 'List of all TypeScript files'\n * });\n * ```\n */\nexport const StepRecommendationSchema = v.object({\n\tstep_description: v.pipe(v.string(), v.description('What needs to be done')),\n\trecommended_tools: v.pipe(\n\t\tv.array(ToolRecommendationSchema),\n\t\tv.description('Tools recommended for this step')\n\t),\n\trecommended_skills: v.optional(\n\t\tv.pipe(v.array(SkillRecommendationSchema), v.description('Skills recommended for this step'))\n\t),\n\texpected_outcome: v.pipe(v.string(), v.description('What to expect from this step')),\n\tnext_step_conditions: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Conditions to consider for the next step'))\n\t),\n});\n\n/**\n * Valibot schema for validating partial tool recommendation objects.\n *\n * This is a lenient version of ToolRecommendationSchema used for previous_steps,\n * where LLMs naturally provide partial/skeletal data. Only tool_name and rationale\n * are required, while confidence and priority are optional with default values.\n *\n * Validates that a partial tool recommendation has:\n * - A tool name (required)\n * - A rationale explaining the recommendation (required)\n * - An optional confidence score (defaults to 0.5)\n * - An optional priority number (defaults to 999)\n * - Optional suggested input parameters\n * - Optional alternative tools\n *\n * @remarks\n * **Design Rationale:**\n * LLMs tend to provide complete data for current_step but only partial data\n * for previous_steps (historical context). This schema accommodates that natural\n * LLM behavior while maintaining data integrity through sensible defaults.\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { PartialToolRecommendationSchema } from './schema.js';\n *\n * // Minimal valid input (LLM often generates this for previous_steps)\n * const result = safeParse(PartialToolRecommendationSchema, {\n * tool_name: 'Read',\n * rationale: 'Read the file'\n * });\n * // confidence and priority will be filled in by the normalizer\n * ```\n */\nexport const PartialToolRecommendationSchema = v.object({\n\ttool_name: v.pipe(v.string(), v.description('Name of the tool being recommended')),\n\trationale: v.optional(\n\t\tv.pipe(v.string(), v.description('Why this tool is recommended (default: empty string)'))\n\t),\n\tconfidence: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('0-1 indicating confidence in recommendation (default: 0.5)')\n\t\t)\n\t),\n\tpriority: v.optional(\n\t\tv.pipe(v.number(), v.description('Order in the recommendation sequence (default: 999)'))\n\t),\n\tsuggested_inputs: v.optional(\n\t\tv.pipe(v.record(v.string(), v.unknown()), v.description('Optional suggested parameters'))\n\t),\n\talternatives: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Alternative tools that could be used'))\n\t),\n});\n\n/**\n * Valibot schema for validating partial step recommendation objects.\n *\n * This is a lenient version of StepRecommendationSchema used for previous_steps,\n * where LLMs naturally provide partial/skeletal data. Only step_description is\n * strictly required, while expected_outcome and tool recommendation fields are\n * optional with default values.\n *\n * Validates that a partial step recommendation has:\n * - A step description (required)\n * - An array of recommended tools (with optional confidence/priority)\n * - An optional array of recommended skills\n * - An optional expected outcome (defaults to empty string)\n * - Optional conditions for the next step\n *\n * @remarks\n * **Design Rationale:**\n * LLMs provide complete, detailed data for current_step but only brief summaries\n * for previous_steps. This schema allows the natural LLM behavior while the\n * InputNormalizer fills in sensible defaults for missing fields.\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { PartialStepRecommendationSchema } from './schema.js';\n *\n * // Minimal valid input (LLM often generates this for previous_steps)\n * const result = safeParse(PartialStepRecommendationSchema, {\n * step_description: 'Read the file',\n * recommended_tools: [{\n * tool_name: 'Read',\n * rationale: 'Read the file'\n * }]\n * });\n * // confidence, priority, and expected_outcome will be filled in by normalizer\n * ```\n */\nexport const PartialStepRecommendationSchema = v.object({\n\tstep_description: v.pipe(v.string(), v.description('What needs to be done')),\n\trecommended_tools: v.pipe(\n\t\tv.array(PartialToolRecommendationSchema),\n\t\tv.description('Tools recommended for this step')\n\t),\n\trecommended_skills: v.optional(\n\t\tv.pipe(v.array(SkillRecommendationSchema), v.description('Skills recommended for this step'))\n\t),\n\texpected_outcome: v.optional(\n\t\tv.pipe(v.string(), v.description('What to expect from this step (default: empty string)'))\n\t),\n\tnext_step_conditions: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Conditions to consider for the next step'))\n\t),\n});\n\n/**\n * Main Valibot schema for validating sequential thinking tool input.\n *\n * This is the primary schema used for the sequential thinking MCP tool.\n * It validates all thought data including:\n * - Optional available tools and skills arrays\n * - The thought content (required)\n * - Thought numbering (thought_number, total_thoughts)\n * - Revision and branching metadata\n * - Current, previous, and remaining step recommendations\n *\n * @remarks\n * **Validation Rules:**\n * - `thought_number` must be >= 1\n * - `total_thoughts` must be >= 1\n * - `branch_id` must be 1-50 characters, alphanumeric/hyphens/underscores only\n * - `confidence` values must be between 0 and 1\n * - `thought_type` must be one of: regular, hypothesis, verification, critique, synthesis, meta\n * - `quality_score` and `confidence` must be between 0 and 1\n * - `hypothesis_id` must be 1-50 characters, alphanumeric/hyphens/underscores only\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { SequentialThinkingSchema } from './schema.js';\n *\n * const result = safeParse(SequentialThinkingSchema, {\n * thought: 'I need to analyze the problem',\n * thought_number: 1,\n * total_thoughts: 5,\n * next_thought_needed: true,\n * available_mcp_tools: ['Read', 'Write', 'Grep']\n * });\n *\n * if (result.success) {\n * console.log('Valid thought:', result.output);\n * } else {\n * console.error('Validation errors:', result.issues);\n * }\n * ```\n */\nexport const SequentialThinkingSchema = v.object({\n\tavailable_mcp_tools: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.string()),\n\t\t\tv.description(\n\t\t\t\t'Array of MCP tool names available for use (e.g., [\"mcp-omnisearch\", \"mcp-turso-cloud\"])'\n\t\t\t)\n\t\t)\n\t),\n\tavailable_skills: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.string()),\n\t\t\tv.description('Array of skill names available for use (e.g., [\"commit\", \"review-pr\", \"pdf\"])')\n\t\t)\n\t),\n\tthought: v.pipe(v.string(), v.description('Your current thinking step')),\n\tid: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(30),\n\t\t\tv.description('Unique identifier for this thought. Auto-generated if not provided.')\n\t\t)\n\t),\n\tnext_thought_needed: v.optional(\n\t\tv.pipe(\n\t\t\tv.boolean(),\n\t\t\tv.description('Whether another thought step is needed (defaults to true if not provided)')\n\t\t)\n\t),\n\tthought_number: v.pipe(v.number(), v.minValue(1), v.description('Current thought number')),\n\ttotal_thoughts: v.pipe(\n\t\tv.number(),\n\t\tv.minValue(1),\n\t\tv.description('Estimated total thoughts needed')\n\t),\n\tis_revision: v.optional(\n\t\tv.pipe(v.boolean(), v.description('Whether this revises previous thinking'))\n\t),\n\trevises_thought: v.optional(\n\t\tv.pipe(v.number(), v.minValue(1), v.description('Which thought is being reconsidered'))\n\t),\n\tbranch_from_thought: v.optional(\n\t\tv.pipe(v.number(), v.minValue(1), v.description('Branching point thought number'))\n\t),\n\tbranch_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'Branch ID must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(50),\n\t\t\tv.description('Branch identifier (alphanumeric, hyphens, underscores only, max 50 chars)')\n\t\t)\n\t),\n\tneeds_more_thoughts: v.optional(\n\t\tv.pipe(v.boolean(), v.description('If more thoughts are needed'))\n\t),\n\tcurrent_step: v.optional(\n\t\tv.pipe(StepRecommendationSchema, v.description('Current step recommendation'))\n\t),\n\tprevious_steps: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(PartialStepRecommendationSchema),\n\t\t\tv.description(\n\t\t\t\t'Steps already recommended (lenient schema - allows partial data with defaults)'\n\t\t\t)\n\t\t)\n\t),\n\tremaining_steps: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('High-level descriptions of upcoming steps'))\n\t),\n\tthought_type: v.optional(\n\t\tv.pipe(\n\t\t\tv.picklist(['regular', 'hypothesis', 'verification', 'critique', 'synthesis', 'meta', 'tool_call', 'tool_observation', 'assumption', 'decomposition', 'backtrack']),\n\t\t\tv.description(\n\t\t\t\t'Classified purpose: regular (default), hypothesis, verification, critique, synthesis, meta, tool_call (requires toolInterleave), tool_observation (requires toolInterleave), assumption (requires newThoughtTypes), decomposition (requires newThoughtTypes), backtrack (requires newThoughtTypes)'\n\t\t\t)\n\t\t)\n\t),\n\tquality_score: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('Self-assessed quality score (0-1)')\n\t\t)\n\t),\n\tconfidence: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('Explicit confidence in correctness (0-1)')\n\t\t)\n\t),\n\thypothesis_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'Hypothesis ID must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(50),\n\t\t\tv.description('Identifier linking hypothesis to verification thoughts')\n\t\t)\n\t),\n\tverification_target: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(1),\n\t\t\tv.description('Thought number being verified or critiqued')\n\t\t)\n\t),\n\tsynthesis_sources: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.pipe(v.number(), v.minValue(1))),\n\t\t\tv.description('Thought numbers being synthesized')\n\t\t)\n\t),\n\tmerge_from_thoughts: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.pipe(v.number(), v.minValue(1))),\n\t\t\tv.description('Thought numbers from other branches being merged (DAG)')\n\t\t)\n\t),\n\tmerge_branch_ids: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.pipe(v.string(), v.regex(/^[a-zA-Z0-9_-]+$/), v.maxLength(50))),\n\t\t\tv.description('Branch IDs being merged into current context')\n\t\t)\n\t),\n\tmeta_observation: v.optional(\n\t\tv.pipe(v.string(), v.description('Metacognitive observation about reasoning process'))\n\t),\n\treasoning_depth: v.optional(\n\t\tv.pipe(\n\t\t\tv.picklist(['shallow', 'moderate', 'deep']),\n\t\t\tv.description('Effort signal: how deep reasoning should go')\n\t\t)\n\t),\n\tsession_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'Session ID must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(100),\n\t\t\tv.description(\n\t\t\t\t'Optional session identifier for state isolation. When provided, thought history, branches, and statistics are scoped to this session. Omitting preserves global behavior.'\n\t\t\t)\n\t\t)\n\t),\n\treset_state: v.optional(\n\t\tv.pipe(\n\t\t\tv.boolean(),\n\t\t\tv.description(\n\t\t\t\t'When true, clears all state for the target session before processing this thought. The thought is then processed as the first in a fresh session.'\n\t\t\t)\n\t\t)\n\t),\n\ttool_name: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Name of the tool being invoked (for tool_call thoughts)'))),\n\ttool_arguments: v.optional(v.pipe(v.record(v.string(), v.unknown()), v.description('Arguments passed to the tool (for tool_call thoughts)'))),\n\ttool_result: v.optional(v.pipe(v.unknown(), v.description('Result returned by the tool (for tool_observation thoughts)'))),\n\tcontinuation_token: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Token for resuming long-running tool invocations'))),\n\tdecomposition_children: v.optional(v.pipe(v.array(v.string()), v.description('Child thought IDs produced by decomposition'))),\n\tbacktrack_target: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.description('Thought number to backtrack to. When the parent thought has thought_type=backtrack, this thought is logically retracted: it remains in history but is excluded from quality signals and reasoning stats.'))),\n\tregister_branch_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'register_branch_id must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(50),\n\t\t\tv.description(\n\t\t\t\t'Pre-declares a branch ID for this session before any thoughts reference it. Useful so that subsequent thoughts using merge_branch_ids can target a branch that has not yet received any thoughts.'\n\t\t\t)\n\t\t)\n\t),\n});\n\n/**\n * The sequential thinking tool definition for MCP registration.\n *\n * This object defines the tool that is registered with the MCP server.\n * The inputSchema is left empty as the schema is handled by tmcp\n * when registering the tool using the Valibot adapter.\n *\n * @example\n * ```typescript\n * import { SEQUENTIAL_THINKING_TOOL } from './schema.js';\n * import { McpServer } from 'tmcp';\n *\n * const server = new McpServer({ name: 'my-server', version: '1.0.0' });\n * server.tool({\n * name: SEQUENTIAL_THINKING_TOOL.name,\n * description: SEQUENTIAL_THINKING_TOOL.description,\n * schema: SequentialThinkingSchema\n * }, handler);\n * ```\n */\nexport const SEQUENTIAL_THINKING_TOOL: Tool = {\n\tname: 'sequentialthinking_tools',\n\tdescription: TOOL_DESCRIPTION,\n\tinputSchema: {}, // Schema is handled by tmcp when registering the tool\n};\n\n/**\n * Valibot schema for validating JSON-RPC 2.0 request messages.\n *\n * Validates that a JSON-RPC request has:\n * - A jsonrpc version (must be \"2.0\")\n * - A method name (string)\n * - Optional params (object or array)\n * - Optional id (string, number, or null for notifications)\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { JsonRpcRequestSchema } from './schema.js';\n *\n * const result = safeParse(JsonRpcRequestSchema, {\n * jsonrpc: '2.0',\n * method: 'tools/list',\n * id: 1\n * });\n * ```\n */\nexport const JsonRpcRequestSchema = v.object({\n\tjsonrpc: v.pipe(\n\t\tv.string(),\n\t\tv.literal('2.0'),\n\t\tv.description('JSON-RPC protocol version (must be \"2.0\")')\n\t),\n\tmethod: v.pipe(v.string(), v.minLength(1), v.description('Method name to invoke')),\n\tparams: v.optional(\n\t\tv.pipe(\n\t\t\tv.union([v.object({}), v.array(v.unknown())]),\n\t\t\tv.description('Method parameters (object or array)')\n\t\t)\n\t),\n\tid: v.optional(\n\t\tv.pipe(\n\t\t\tv.union([v.string(), v.number(), v.null()]),\n\t\t\tv.description('Request ID (omit for notifications)')\n\t\t)\n\t),\n});\n\n/**\n * Schema for {@link EdgeKind} — the semantic relationship between two thoughts.\n */\nexport const EdgeKindSchema = v.union([\n\tv.literal('sequence'),\n\tv.literal('branch'),\n\tv.literal('merge'),\n\tv.literal('verifies'),\n\tv.literal('critiques'),\n\tv.literal('derives_from'),\n\tv.literal('tool_invocation'),\n\tv.literal('revises'),\n]) satisfies v.GenericSchema<EdgeKind>;\n\n/**\n * Schema for {@link Edge} — a directed edge in the thought DAG.\n */\nexport const EdgeSchema = v.object({\n\tid: v.pipe(v.string(), v.minLength(1), v.maxLength(30)),\n\tfrom: v.pipe(v.string(), v.minLength(1), v.maxLength(30)),\n\tto: v.pipe(v.string(), v.minLength(1), v.maxLength(30)),\n\tkind: EdgeKindSchema,\n\tsessionId: v.pipe(v.string(), v.minLength(1)),\n\tcreatedAt: v.number(),\n\tmetadata: v.optional(v.record(v.string(), v.unknown())),\n}) satisfies v.GenericSchema<Omit<Edge, 'id' | 'from' | 'to' | 'sessionId'> & { id: string; from: string; to: string; sessionId: string }>;\n"],"names":["TOOL_DESCRIPTION","ToolRecommendationSchema","v","SkillRecommendationSchema","StepRecommendationSchema","PartialToolRecommendationSchema","PartialStepRecommendationSchema","SequentialThinkingSchema","SEQUENTIAL_THINKING_TOOL","JsonRpcRequestSchema","EdgeKindSchema","EdgeSchema"],"mappings":";AAyCA,MAAMA,mBAAmB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yHAuG+F,CAAC;AA0BnH,MAAMC,2BAA2BC,0BAAAA,MAAQ,CAAC;IAChD,WAAWA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAC5C,YAAYA,0BAAAA,IAAM,CACjBA,0BAAAA,MAAQ,IACRA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,WAAa,CAAC;IAEf,WAAWA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAC5C,UAAUA,0BAAAA,QAAU,CACnBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAElC,kBAAkBA,0BAAAA,QAAU,CAC3BA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,OAAS,KAAKA,0BAAAA,WAAa,CAAC;IAEzD,cAAcA,0BAAAA,QAAU,CACvBA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAAKA,0BAAAA,WAAa,CAAC;AAE5C;AA4BO,MAAMC,4BAA4BD,0BAAAA,MAAQ,CAAC;IACjD,YAAYA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAC7C,YAAYA,0BAAAA,QAAU,CACrBA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,WAAa,CAAC;IAGhB,WAAWA,0BAAAA,QAAU,CACpBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAElC,UAAUA,0BAAAA,QAAU,CACnBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAElC,cAAcA,0BAAAA,QAAU,CACvBA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAAKA,0BAAAA,WAAa,CAAC;IAE3C,eAAeA,0BAAAA,QAAU,CACxBA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAChBA,0BAAAA,WAAa,CAAC;IAGhB,gBAAgBA,0BAAAA,QAAU,CACzBA,0BAAAA,IAAM,CAACA,0BAAAA,OAAS,IAAIA,0BAAAA,WAAa,CAAC;AAEpC;AAwBO,MAAME,2BAA2BF,0BAAAA,MAAQ,CAAC;IAChD,kBAAkBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IACnD,mBAAmBA,0BAAAA,IAAM,CACxBA,0BAAAA,KAAO,CAACD,2BACRC,0BAAAA,WAAa,CAAC;IAEf,oBAAoBA,0BAAAA,QAAU,CAC7BA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACC,4BAA4BD,0BAAAA,WAAa,CAAC;IAE1D,kBAAkBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IACnD,sBAAsBA,0BAAAA,QAAU,CAC/BA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAAKA,0BAAAA,WAAa,CAAC;AAE5C;AAoCO,MAAMG,kCAAkCH,0BAAAA,MAAQ,CAAC;IACvD,WAAWA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAC5C,WAAWA,0BAAAA,QAAU,CACpBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAElC,YAAYA,0BAAAA,QAAU,CACrBA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,WAAa,CAAC;IAGhB,UAAUA,0BAAAA,QAAU,CACnBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAElC,kBAAkBA,0BAAAA,QAAU,CAC3BA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,OAAS,KAAKA,0BAAAA,WAAa,CAAC;IAEzD,cAAcA,0BAAAA,QAAU,CACvBA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAAKA,0BAAAA,WAAa,CAAC;AAE5C;AAuCO,MAAMI,kCAAkCJ,0BAAAA,MAAQ,CAAC;IACvD,kBAAkBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IACnD,mBAAmBA,0BAAAA,IAAM,CACxBA,0BAAAA,KAAO,CAACG,kCACRH,0BAAAA,WAAa,CAAC;IAEf,oBAAoBA,0BAAAA,QAAU,CAC7BA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACC,4BAA4BD,0BAAAA,WAAa,CAAC;IAE1D,kBAAkBA,0BAAAA,QAAU,CAC3BA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAElC,sBAAsBA,0BAAAA,QAAU,CAC/BA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAAKA,0BAAAA,WAAa,CAAC;AAE5C;AA2CO,MAAMK,2BAA2BL,0BAAAA,MAAQ,CAAC;IAChD,qBAAqBA,0BAAAA,QAAU,CAC9BA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAChBA,0BAAAA,WAAa,CACZ;IAIH,kBAAkBA,0BAAAA,QAAU,CAC3BA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAChBA,0BAAAA,WAAa,CAAC;IAGhB,SAASA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAC1C,IAAIA,0BAAAA,QAAU,CACbA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,SAAW,CAAC,IACZA,0BAAAA,SAAW,CAAC,KACZA,0BAAAA,WAAa,CAAC;IAGhB,qBAAqBA,0BAAAA,QAAU,CAC9BA,0BAAAA,IAAM,CACLA,0BAAAA,OAAS,IACTA,0BAAAA,WAAa,CAAC;IAGhB,gBAAgBA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,QAAU,CAAC,IAAIA,0BAAAA,WAAa,CAAC;IAChE,gBAAgBA,0BAAAA,IAAM,CACrBA,0BAAAA,MAAQ,IACRA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,WAAa,CAAC;IAEf,aAAaA,0BAAAA,QAAU,CACtBA,0BAAAA,IAAM,CAACA,0BAAAA,OAAS,IAAIA,0BAAAA,WAAa,CAAC;IAEnC,iBAAiBA,0BAAAA,QAAU,CAC1BA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,QAAU,CAAC,IAAIA,0BAAAA,WAAa,CAAC;IAEjD,qBAAqBA,0BAAAA,QAAU,CAC9BA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,QAAU,CAAC,IAAIA,0BAAAA,WAAa,CAAC;IAEjD,WAAWA,0BAAAA,QAAU,CACpBA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,KAAO,CACN,oBACA,2EAEDA,0BAAAA,SAAW,CAAC,IACZA,0BAAAA,SAAW,CAAC,KACZA,0BAAAA,WAAa,CAAC;IAGhB,qBAAqBA,0BAAAA,QAAU,CAC9BA,0BAAAA,IAAM,CAACA,0BAAAA,OAAS,IAAIA,0BAAAA,WAAa,CAAC;IAEnC,cAAcA,0BAAAA,QAAU,CACvBA,0BAAAA,IAAM,CAACE,0BAA0BF,0BAAAA,WAAa,CAAC;IAEhD,gBAAgBA,0BAAAA,QAAU,CACzBA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAACI,kCACRJ,0BAAAA,WAAa,CACZ;IAIH,iBAAiBA,0BAAAA,QAAU,CAC1BA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAAKA,0BAAAA,WAAa,CAAC;IAE3C,cAAcA,0BAAAA,QAAU,CACvBA,0BAAAA,IAAM,CACLA,0BAAAA,QAAU,CAAC;QAAC;QAAW;QAAc;QAAgB;QAAY;QAAa;QAAQ;QAAa;QAAoB;QAAc;QAAiB;KAAY,GAClKA,0BAAAA,WAAa,CACZ;IAIH,eAAeA,0BAAAA,QAAU,CACxBA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,WAAa,CAAC;IAGhB,YAAYA,0BAAAA,QAAU,CACrBA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,WAAa,CAAC;IAGhB,eAAeA,0BAAAA,QAAU,CACxBA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,KAAO,CACN,oBACA,+EAEDA,0BAAAA,SAAW,CAAC,IACZA,0BAAAA,SAAW,CAAC,KACZA,0BAAAA,WAAa,CAAC;IAGhB,qBAAqBA,0BAAAA,QAAU,CAC9BA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,QAAU,CAAC,IACXA,0BAAAA,WAAa,CAAC;IAGhB,mBAAmBA,0BAAAA,QAAU,CAC5BA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,QAAU,CAAC,MACtCA,0BAAAA,WAAa,CAAC;IAGhB,qBAAqBA,0BAAAA,QAAU,CAC9BA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,QAAU,CAAC,MACtCA,0BAAAA,WAAa,CAAC;IAGhB,kBAAkBA,0BAAAA,QAAU,CAC3BA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,KAAO,CAAC,qBAAqBA,0BAAAA,SAAW,CAAC,OACpEA,0BAAAA,WAAa,CAAC;IAGhB,kBAAkBA,0BAAAA,QAAU,CAC3BA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,WAAa,CAAC;IAElC,iBAAiBA,0BAAAA,QAAU,CAC1BA,0BAAAA,IAAM,CACLA,0BAAAA,QAAU,CAAC;QAAC;QAAW;QAAY;KAAO,GAC1CA,0BAAAA,WAAa,CAAC;IAGhB,YAAYA,0BAAAA,QAAU,CACrBA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,KAAO,CACN,oBACA,4EAEDA,0BAAAA,SAAW,CAAC,IACZA,0BAAAA,SAAW,CAAC,MACZA,0BAAAA,WAAa,CACZ;IAIH,aAAaA,0BAAAA,QAAU,CACtBA,0BAAAA,IAAM,CACLA,0BAAAA,OAAS,IACTA,0BAAAA,WAAa,CACZ;IAIH,WAAWA,0BAAAA,QAAU,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,SAAW,CAAC,IAAIA,0BAAAA,WAAa,CAAC;IACvE,gBAAgBA,0BAAAA,QAAU,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,OAAS,KAAKA,0BAAAA,WAAa,CAAC;IACnF,aAAaA,0BAAAA,QAAU,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,OAAS,IAAIA,0BAAAA,WAAa,CAAC;IAC1D,oBAAoBA,0BAAAA,QAAU,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,SAAW,CAAC,IAAIA,0BAAAA,WAAa,CAAC;IAChF,wBAAwBA,0BAAAA,QAAU,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,KAAO,CAACA,0BAAAA,MAAQ,KAAKA,0BAAAA,WAAa,CAAC;IAC7E,kBAAkBA,0BAAAA,QAAU,CAACA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,OAAS,IAAIA,0BAAAA,QAAU,CAAC,IAAIA,0BAAAA,WAAa,CAAC;IAC1F,oBAAoBA,0BAAAA,QAAU,CAC7BA,0BAAAA,IAAM,CACLA,0BAAAA,MAAQ,IACRA,0BAAAA,KAAO,CACN,oBACA,oFAEDA,0BAAAA,SAAW,CAAC,IACZA,0BAAAA,SAAW,CAAC,KACZA,0BAAAA,WAAa,CACZ;AAIJ;AAsBO,MAAMM,2BAAiC;IAC7C,MAAM;IACN,aAAaR;IACb,aAAa,CAAC;AACf;AAuBO,MAAMS,uBAAuBP,0BAAAA,MAAQ,CAAC;IAC5C,SAASA,0BAAAA,IAAM,CACdA,0BAAAA,MAAQ,IACRA,0BAAAA,OAAS,CAAC,QACVA,0BAAAA,WAAa,CAAC;IAEf,QAAQA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,SAAW,CAAC,IAAIA,0BAAAA,WAAa,CAAC;IACzD,QAAQA,0BAAAA,QAAU,CACjBA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAAC;QAACA,0BAAAA,MAAQ,CAAC,CAAC;QAAIA,0BAAAA,KAAO,CAACA,0BAAAA,OAAS;KAAI,GAC5CA,0BAAAA,WAAa,CAAC;IAGhB,IAAIA,0BAAAA,QAAU,CACbA,0BAAAA,IAAM,CACLA,0BAAAA,KAAO,CAAC;QAACA,0BAAAA,MAAQ;QAAIA,0BAAAA,MAAQ;QAAIA,yBAAAA,CAAAA,OAAM;KAAG,GAC1CA,0BAAAA,WAAa,CAAC;AAGjB;AAKO,MAAMQ,iBAAiBR,0BAAAA,KAAO,CAAC;IACrCA,0BAAAA,OAAS,CAAC;IACVA,0BAAAA,OAAS,CAAC;IACVA,0BAAAA,OAAS,CAAC;IACVA,0BAAAA,OAAS,CAAC;IACVA,0BAAAA,OAAS,CAAC;IACVA,0BAAAA,OAAS,CAAC;IACVA,0BAAAA,OAAS,CAAC;IACVA,0BAAAA,OAAS,CAAC;CACV;AAKM,MAAMS,aAAaT,0BAAAA,MAAQ,CAAC;IAClC,IAAIA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,SAAW,CAAC,IAAIA,0BAAAA,SAAW,CAAC;IACnD,MAAMA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,SAAW,CAAC,IAAIA,0BAAAA,SAAW,CAAC;IACrD,IAAIA,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,SAAW,CAAC,IAAIA,0BAAAA,SAAW,CAAC;IACnD,MAAMQ;IACN,WAAWR,0BAAAA,IAAM,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,SAAW,CAAC;IAC1C,WAAWA,0BAAAA,MAAQ;IACnB,UAAUA,0BAAAA,QAAU,CAACA,0BAAAA,MAAQ,CAACA,0BAAAA,MAAQ,IAAIA,0BAAAA,OAAS;AACpD"}
1
+ {"version":3,"file":"schema.js","sources":["../src/schema.ts"],"sourcesContent":["/**\n * Valibot validation schemas for the sequential thinking MCP tool.\n *\n * This module defines the validation schemas used for the sequential thinking tool,\n * including schemas for tool recommendations, skill recommendations, step recommendations,\n * and the main sequential thinking input. All schemas use Valibot for runtime validation\n * and provide detailed descriptions for MCP protocol compatibility.\n *\n * @remarks\n * **Schema Overview:**\n * - `ToolRecommendationSchema` - Validates tool recommendation objects with confidence scores\n * - `SkillRecommendationSchema` - Validates skill recommendation objects\n * - `StepRecommendationSchema` - Validates step coordination structures\n * - `SequentialThinkingSchema` - Main schema for thought input validation\n * - Reasoning enhancement fields: thought_type, quality_score, confidence, hypothesis_id, etc.\n *\n * @example\n * ```typescript\n * import { SequentialThinkingSchema } from './schema.js';\n * import { safeParse } from 'valibot';\n *\n * const result = safeParse(SequentialThinkingSchema, inputData);\n * if (result.success) {\n * const thought = result.output;\n * // Process the valid thought\n * } else {\n * console.error('Validation failed:', result.issues);\n * }\n * ```\n * @module schema\n */\n\nimport * as v from 'valibot';\nimport type { Tool } from './types/tool.js';\nimport type { Edge, EdgeKind } from './core/graph/Edge.js';\n/**\n * Detailed description for the sequential thinking tool.\n *\n * This description is shown to LLMs when they consider using this tool.\n * It explains when to use the tool, its features, parameters, and best practices.\n */\nconst TOOL_DESCRIPTION = `A detailed tool for dynamic and reflective problem-solving through thoughts.\nThis tool helps analyze problems through a flexible thinking process that can adapt and evolve.\nEach thought can build on, question, or revise previous insights as understanding deepens.\n\nIMPORTANT: This server facilitates sequential thinking with MCP tool coordination and skill recommendations. The LLM analyzes available tools and skills to make intelligent recommendations, which are then tracked and organized by this server.\n\nWhen to use this tool:\n- Breaking down complex problems into steps\n- Planning and design with room for revision\n- Analysis that might need course correction\n- Problems where the full scope might not be clear initially\n- Problems that require a multi-step solution\n- Tasks that need to maintain context over multiple steps\n- Situations where irrelevant information needs to be filtered out\n- When you need guidance on which tools to use and in what order\n- When you need guidance on which skills to invoke for specific workflows\n\nKey features:\n- You can adjust total_thoughts up or down as you progress\n- You can question or revise previous thoughts\n- You can add more thoughts even after reaching what seemed like the end\n- You can express uncertainty and explore alternative approaches\n- Not every thought needs to build linearly - you can branch or backtrack\n- Generates a solution hypothesis\n- Verifies the hypothesis based on the Chain of Thought steps\n- Recommends appropriate tools for each step\n- Recommends appropriate skills alongside tools\n- Provides rationale for tool recommendations\n- Suggests tool execution order and parameters\n- Tracks previous recommendations and remaining steps\n\nParameters explained:\n- available_mcp_tools: (Optional) Array of MCP tool names that are available for use (e.g., [\"mcp-omnisearch\", \"mcp-turso-cloud\"])\n- available_skills: (Optional) Array of skill names that are available for use (e.g., [\"commit\", \"review-pr\", \"pdf\"])\n- thought: Your current thinking step, which can include:\n* Regular analytical steps\n* Revisions of previous thoughts\n* Questions about previous decisions\n* Realizations about needing more analysis\n* Changes in approach\n* Hypothesis generation\n* Hypothesis verification\n* Tool recommendations and rationale\n- next_thought_needed: True if you need more thinking, even if at what seemed like the end\n- thought_number: Current number in sequence (can go beyond initial total if needed)\n- total_thoughts: Current estimate of thoughts needed (can be adjusted up/down)\n- is_revision: A boolean indicating if this thought revises previous thinking\n- revises_thought: If is_revision is true, which thought number is being reconsidered\n- branch_from_thought: If branching, which thought number is the branching point\n- branch_id: Identifier for the current branch (if any)\n- needs_more_thoughts: If reaching end but realizing more thoughts needed\n- current_step: Current step recommendation, including:\n* step_description: What needs to be done\n* recommended_tools: (CRITICAL: PLURAL - \"recommended_tools\" with an 's') Tools recommended for this step - MUST be an array.\n* recommended_skills: (CRITICAL: PLURAL - \"recommended_skills\" with an 's') Skills recommended for this step (optional) - MUST be an array.\n* expected_outcome: What to expect from this step\n* next_step_conditions: Conditions to consider for the next step\n- previous_steps: Steps already recommended (each step MUST use \"recommended_tools\" PLURAL)\n- remaining_steps: High-level descriptions of upcoming steps\n\nReasoning Enhancement Parameters:\n- thought_type: Thought purpose: 'regular' (default), 'hypothesis', 'verification', 'critique', 'synthesis', 'meta', 'tool_call' (requires toolInterleave flag), 'tool_observation' (requires toolInterleave flag), 'assumption' (requires newThoughtTypes flag), 'decomposition' (requires newThoughtTypes flag), 'backtrack' (requires newThoughtTypes flag; logically retracts the thought referenced by backtrack_target - the target remains in history but is excluded from quality calculations)\n- quality_score: Self-assessed quality of this thought (0-1)\n- confidence: Confidence in this thought's correctness (0-1)\n- hypothesis_id: Links hypothesis to verification (alphanumeric, hyphens, underscores)\n- verification_target: For 'verification'/'critique' types, the thought_number being evaluated\n- synthesis_sources: For 'synthesis' type, the thought_numbers being combined\n- merge_from_thoughts: Thought numbers from other branches merged (graph reasoning)\n- merge_branch_ids: Branch IDs merged into current context\n- meta_observation: Observation about reasoning process (with thought_type 'meta')\n- reasoning_depth: How deep to reason: 'shallow' (quick), 'moderate' (default), 'deep' (thorough)\n- session_id: (Optional) Unique identifier to scope thought history, branches, and statistics to an isolated session. When provided, all state is scoped to this session ID. When omitted, uses shared global state (backward compatible). Format: alphanumeric, hyphens, underscores, 1-100 chars.\n- reset_state: (Optional) When true, clears all state for the target session (or global state if no session_id) before processing the current thought. Use this to start a fresh reasoning chain without accumulated state from previous chains.\n\nResponse Enrichment:\n- When reasoning fields are set, response includes confidence_signals (depth, revision/branch count, type distribution, avg confidence, structural_quality, quality_components) and reasoning_stats (hypothesis tracking)\n- confidence_signals.structural_quality: Composite 0-1 score — weighted geometric mean of type_diversity (0.3), verification_coverage (0.3), depth_efficiency (0.2), confidence_stability (0.2). Weights: type_diversity=0.3, verification_coverage=0.3, depth_efficiency=0.2, confidence_stability=0.2 (weighted geometric mean). All components floored at 0.01 to prevent collapse.\n- confidence_signals.quality_components: Individual metrics — type_diversity (Shannon entropy/log₂(6)), verification_coverage (verified/total hypotheses, 1.0 if none), depth_efficiency (max(chain_depth, branch_count+1)/total, branching rewarded), confidence_stability (1 - stddev(confidence), default 0.5, null when fewer than 2 confidence values)\n- reasoning_hints: (Conditional) Array of actionable hint strings from cross-thought pattern analysis. Only warning-severity patterns produce hints. Max 3 hints per response, with 3-thought cooldown per pattern per session. Hints are prioritized: confidence_drift > unverified_hypothesis > no_alternatives_explored > consecutive_without_verification, so the most actionable patterns fill the cap first. Present only when warnings are detected.\n- Detected patterns (internal, not in response): consecutive_without_verification (3+ regular thoughts without verification), unverified_hypothesis (hypothesis without verification within 3 thoughts after it), no_alternatives_explored (5+ thoughts with no critique/branches), monotonic_type (5+ consecutive same type), confidence_drift (3+ consecutive decreasing confidence), healthy_verification (hypothesis verified within 3 thoughts — info only)\nYou should:\n1. Start with an initial estimate of needed thoughts, but be ready to adjust\n2. Feel free to question or revise previous thoughts\n3. Don't hesitate to add more thoughts if needed, even at the \"end\"\n4. Express uncertainty when present\n5. Mark thoughts that revise previous thinking or branch into new paths\n6. Ignore information that is irrelevant to the current step\n7. Generate a solution hypothesis when appropriate\n8. Verify the hypothesis based on the Chain of Thought steps\n9. Consider available tools that could help with the current step\n10. Provide clear rationale for tool recommendations\n11. Suggest specific tool parameters when appropriate\n12. Consider alternative tools for each step\n13. Track progress through the recommended steps\n14. Consider available skills that provide workflows for complex tasks\n15. Coordinate skill invocation with tool recommendations (skills may call tools)\n16. Provide a single, ideally correct answer as the final output\n17. Only set next_thought_needed to false when truly done and a satisfactory answer is reached\n18. Classify your reasoning steps using thought_type for better analytics and self-awareness\n19. Use hypothesis → verification chains to test solutions before committing\n20. Self-assess quality and confidence to track reasoning reliability\n21. Use merge_from_thoughts to combine insights from multiple reasoning branches\n22. Use session_id to isolate independent reasoning chains from each other\n23. Use reset_state: true when starting a completely new analysis to avoid statistical contamination from previous chains`;\n\n/**\n * Valibot schema for validating tool recommendation objects.\n *\n * Validates that a tool recommendation has:\n * - A tool name (string)\n * - A confidence score between 0 and 1\n * - A rationale explaining the recommendation\n * - A priority number for ordering\n * - Optional suggested input parameters\n * - Optional alternative tools\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { ToolRecommendationSchema } from './schema.js';\n *\n * const result = safeParse(ToolRecommendationSchema, {\n * tool_name: 'mcp__tavily-mcp__tavily-search',\n * confidence: 0.9,\n * rationale: 'Best for web search',\n * priority: 1\n * });\n * ```\n */\nexport const ToolRecommendationSchema = v.object({\n\ttool_name: v.pipe(v.string(), v.description('Name of the tool being recommended')),\n\tconfidence: v.pipe(\n\t\tv.number(),\n\t\tv.minValue(0),\n\t\tv.maxValue(1),\n\t\tv.description('0-1 indicating confidence in recommendation')\n\t),\n\trationale: v.pipe(v.string(), v.maxLength(2000), v.description('Why this tool is recommended')),\n\tpriority: v.optional(\n\t\tv.pipe(v.number(), v.description('Order in the recommendation sequence (default: 999)'))\n\t),\n\tsuggested_inputs: v.optional(\n\t\tv.pipe(\n\t\t\tv.record(v.string(), v.union([v.string(), v.number(), v.boolean(), v.null()])),\n\t\t\tv.description('Optional suggested parameters (flat key-value pairs only)')\n\t\t)\n\t),\n\talternatives: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Alternative tools that could be used'))\n\t),\n});\n\n/**\n * Valibot schema for validating skill recommendation objects.\n *\n * Validates that a skill recommendation has:\n * - A skill name (string)\n * - A confidence score between 0 and 1\n * - A rationale explaining the recommendation\n * - A priority number for ordering\n * - Optional alternative skills\n * - Optional allowed tools list\n * - Optional user invocable flag\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { SkillRecommendationSchema } from './schema.js';\n *\n * const result = safeParse(SkillRecommendationSchema, {\n * skill_name: 'commit',\n * confidence: 0.95,\n * rationale: 'Handles git commit workflow',\n * priority: 1,\n * user_invocable: true\n * });\n * ```\n */\nexport const SkillRecommendationSchema = v.object({\n\tskill_name: v.pipe(v.string(), v.description('Name of the skill being recommended')),\n\tconfidence: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('0-1 indicating confidence in recommendation (default: 0.5)')\n\t\t)\n\t),\n\trationale: v.optional(\n\t\tv.pipe(v.string(), v.maxLength(2000), v.description('Why this skill is recommended (default: empty string)'))\n\t),\n\tpriority: v.optional(\n\t\tv.pipe(v.number(), v.description('Order in the recommendation sequence (default: 999)'))\n\t),\n\talternatives: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Alternative skills that could be used'))\n\t),\n\tallowed_tools: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.string()),\n\t\t\tv.description('Tools this skill is allowed to use (from skill frontmatter)')\n\t\t)\n\t),\n\tuser_invocable: v.optional(\n\t\tv.pipe(v.boolean(), v.description('Whether this skill can be user-invoked'))\n\t),\n});\n\n/**\n * Valibot schema for validating step recommendation objects.\n *\n * Validates that a step recommendation has:\n * - A step description\n * - An array of recommended tools\n * - An optional array of recommended skills\n * - An expected outcome\n * - Optional conditions for the next step\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { StepRecommendationSchema } from './schema.js';\n *\n * const result = safeParse(StepRecommendationSchema, {\n * step_description: 'Search for TypeScript files',\n * recommended_tools: [{ ... }],\n * expected_outcome: 'List of all TypeScript files'\n * });\n * ```\n */\nexport const StepRecommendationSchema = v.object({\n\tstep_description: v.pipe(v.string(), v.description('What needs to be done')),\n\trecommended_tools: v.pipe(\n\t\tv.array(ToolRecommendationSchema),\n\t\tv.description('Tools recommended for this step')\n\t),\n\trecommended_skills: v.optional(\n\t\tv.pipe(v.array(SkillRecommendationSchema), v.description('Skills recommended for this step'))\n\t),\n\texpected_outcome: v.pipe(v.string(), v.description('What to expect from this step')),\n\tnext_step_conditions: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Conditions to consider for the next step'))\n\t),\n});\n\n/**\n * Valibot schema for validating partial tool recommendation objects.\n *\n * This is a lenient version of ToolRecommendationSchema used for previous_steps,\n * where LLMs naturally provide partial/skeletal data. Only tool_name and rationale\n * are required, while confidence and priority are optional with default values.\n *\n * Validates that a partial tool recommendation has:\n * - A tool name (required)\n * - A rationale explaining the recommendation (required)\n * - An optional confidence score (defaults to 0.5)\n * - An optional priority number (defaults to 999)\n * - Optional suggested input parameters\n * - Optional alternative tools\n *\n * @remarks\n * **Design Rationale:**\n * LLMs tend to provide complete data for current_step but only partial data\n * for previous_steps (historical context). This schema accommodates that natural\n * LLM behavior while maintaining data integrity through sensible defaults.\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { PartialToolRecommendationSchema } from './schema.js';\n *\n * // Minimal valid input (LLM often generates this for previous_steps)\n * const result = safeParse(PartialToolRecommendationSchema, {\n * tool_name: 'Read',\n * rationale: 'Read the file'\n * });\n * // confidence and priority will be filled in by the normalizer\n * ```\n */\nexport const PartialToolRecommendationSchema = v.object({\n\ttool_name: v.pipe(v.string(), v.description('Name of the tool being recommended')),\n\trationale: v.optional(\n\t\tv.pipe(v.string(), v.maxLength(2000), v.description('Why this tool is recommended (default: empty string)'))\n\t),\n\tconfidence: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('0-1 indicating confidence in recommendation (default: 0.5)')\n\t\t)\n\t),\n\tpriority: v.optional(\n\t\tv.pipe(v.number(), v.description('Order in the recommendation sequence (default: 999)'))\n\t),\n\tsuggested_inputs: v.optional(\n\t\tv.pipe(\n\t\t\tv.record(v.string(), v.union([v.string(), v.number(), v.boolean(), v.null()])),\n\t\t\tv.description('Optional suggested parameters (flat key-value pairs only)')\n\t\t)\n\t),\n\talternatives: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Alternative tools that could be used'))\n\t),\n});\n\n/**\n * Valibot schema for validating partial step recommendation objects.\n *\n * This is a lenient version of StepRecommendationSchema used for previous_steps,\n * where LLMs naturally provide partial/skeletal data. Only step_description is\n * strictly required, while expected_outcome and tool recommendation fields are\n * optional with default values.\n *\n * Validates that a partial step recommendation has:\n * - A step description (required)\n * - An array of recommended tools (with optional confidence/priority)\n * - An optional array of recommended skills\n * - An optional expected outcome (defaults to empty string)\n * - Optional conditions for the next step\n *\n * @remarks\n * **Design Rationale:**\n * LLMs provide complete, detailed data for current_step but only brief summaries\n * for previous_steps. This schema allows the natural LLM behavior while the\n * InputNormalizer fills in sensible defaults for missing fields.\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { PartialStepRecommendationSchema } from './schema.js';\n *\n * // Minimal valid input (LLM often generates this for previous_steps)\n * const result = safeParse(PartialStepRecommendationSchema, {\n * step_description: 'Read the file',\n * recommended_tools: [{\n * tool_name: 'Read',\n * rationale: 'Read the file'\n * }]\n * });\n * // confidence, priority, and expected_outcome will be filled in by normalizer\n * ```\n */\nexport const PartialStepRecommendationSchema = v.object({\n\tstep_description: v.pipe(v.string(), v.description('What needs to be done')),\n\trecommended_tools: v.pipe(\n\t\tv.array(PartialToolRecommendationSchema),\n\t\tv.description('Tools recommended for this step')\n\t),\n\trecommended_skills: v.optional(\n\t\tv.pipe(v.array(SkillRecommendationSchema), v.description('Skills recommended for this step'))\n\t),\n\texpected_outcome: v.optional(\n\t\tv.pipe(v.string(), v.description('What to expect from this step (default: empty string)'))\n\t),\n\tnext_step_conditions: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('Conditions to consider for the next step'))\n\t),\n});\n\n/**\n * Main Valibot schema for validating sequential thinking tool input.\n *\n * This is the primary schema used for the sequential thinking MCP tool.\n * It validates all thought data including:\n * - Optional available tools and skills arrays\n * - The thought content (required)\n * - Thought numbering (thought_number, total_thoughts)\n * - Revision and branching metadata\n * - Current, previous, and remaining step recommendations\n *\n * @remarks\n * **Validation Rules:**\n * - `thought_number` must be >= 1\n * - `total_thoughts` must be >= 1\n * - `branch_id` must be 1-50 characters, alphanumeric/hyphens/underscores only\n * - `confidence` values must be between 0 and 1\n * - `thought_type` must be one of: regular, hypothesis, verification, critique, synthesis, meta\n * - `quality_score` and `confidence` must be between 0 and 1\n * - `hypothesis_id` must be 1-50 characters, alphanumeric/hyphens/underscores only\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { SequentialThinkingSchema } from './schema.js';\n *\n * const result = safeParse(SequentialThinkingSchema, {\n * thought: 'I need to analyze the problem',\n * thought_number: 1,\n * total_thoughts: 5,\n * next_thought_needed: true,\n * available_mcp_tools: ['Read', 'Write', 'Grep']\n * });\n *\n * if (result.success) {\n * console.log('Valid thought:', result.output);\n * } else {\n * console.error('Validation errors:', result.issues);\n * }\n * ```\n */\nexport const SequentialThinkingSchema = v.object({\n\tavailable_mcp_tools: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.string()),\n\t\t\tv.description(\n\t\t\t\t'Array of MCP tool names available for use (e.g., [\"mcp-omnisearch\", \"mcp-turso-cloud\"])'\n\t\t\t)\n\t\t)\n\t),\n\tavailable_skills: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.string()),\n\t\t\tv.description('Array of skill names available for use (e.g., [\"commit\", \"review-pr\", \"pdf\"])')\n\t\t)\n\t),\n\tthought: v.pipe(v.string(), v.description('Your current thinking step')),\n\tid: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(30),\n\t\t\tv.description('Unique identifier for this thought. Auto-generated if not provided.')\n\t\t)\n\t),\n\tnext_thought_needed: v.optional(\n\t\tv.pipe(\n\t\t\tv.boolean(),\n\t\t\tv.description('Whether another thought step is needed (defaults to true if not provided)')\n\t\t)\n\t),\n\tthought_number: v.pipe(v.number(), v.minValue(1), v.description('Current thought number')),\n\ttotal_thoughts: v.pipe(\n\t\tv.number(),\n\t\tv.minValue(1),\n\t\tv.description('Estimated total thoughts needed')\n\t),\n\tis_revision: v.optional(\n\t\tv.pipe(v.boolean(), v.description('Whether this revises previous thinking'))\n\t),\n\trevises_thought: v.optional(\n\t\tv.pipe(v.number(), v.minValue(1), v.description('Which thought is being reconsidered'))\n\t),\n\tbranch_from_thought: v.optional(\n\t\tv.pipe(v.number(), v.minValue(1), v.description('Branching point thought number'))\n\t),\n\tbranch_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'Branch ID must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(50),\n\t\t\tv.description('Branch identifier (alphanumeric, hyphens, underscores only, max 50 chars)')\n\t\t)\n\t),\n\tneeds_more_thoughts: v.optional(\n\t\tv.pipe(v.boolean(), v.description('If more thoughts are needed'))\n\t),\n\tcurrent_step: v.optional(\n\t\tv.pipe(StepRecommendationSchema, v.description('Current step recommendation'))\n\t),\n\tprevious_steps: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(PartialStepRecommendationSchema),\n\t\t\tv.description(\n\t\t\t\t'Steps already recommended (lenient schema - allows partial data with defaults)'\n\t\t\t)\n\t\t)\n\t),\n\tremaining_steps: v.optional(\n\t\tv.pipe(v.array(v.string()), v.description('High-level descriptions of upcoming steps'))\n\t),\n\tthought_type: v.optional(\n\t\tv.pipe(\n\t\t\tv.picklist(['regular', 'hypothesis', 'verification', 'critique', 'synthesis', 'meta', 'tool_call', 'tool_observation', 'assumption', 'decomposition', 'backtrack']),\n\t\t\tv.description(\n\t\t\t\t'Classified purpose: regular (default), hypothesis, verification, critique, synthesis, meta, tool_call (requires toolInterleave), tool_observation (requires toolInterleave), assumption (requires newThoughtTypes), decomposition (requires newThoughtTypes), backtrack (requires newThoughtTypes)'\n\t\t\t)\n\t\t)\n\t),\n\tquality_score: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('Self-assessed quality score (0-1)')\n\t\t)\n\t),\n\tconfidence: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(0),\n\t\t\tv.maxValue(1),\n\t\t\tv.description('Explicit confidence in correctness (0-1)')\n\t\t)\n\t),\n\thypothesis_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'Hypothesis ID must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(50),\n\t\t\tv.description('Identifier linking hypothesis to verification thoughts')\n\t\t)\n\t),\n\tverification_target: v.optional(\n\t\tv.pipe(\n\t\t\tv.number(),\n\t\t\tv.minValue(1),\n\t\t\tv.description('Thought number being verified or critiqued')\n\t\t)\n\t),\n\tsynthesis_sources: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.pipe(v.number(), v.minValue(1))),\n\t\t\tv.description('Thought numbers being synthesized')\n\t\t)\n\t),\n\tmerge_from_thoughts: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.pipe(v.number(), v.minValue(1))),\n\t\t\tv.description('Thought numbers from other branches being merged (DAG)')\n\t\t)\n\t),\n\tmerge_branch_ids: v.optional(\n\t\tv.pipe(\n\t\t\tv.array(v.pipe(v.string(), v.regex(/^[a-zA-Z0-9_-]+$/), v.maxLength(50))),\n\t\t\tv.description('Branch IDs being merged into current context')\n\t\t)\n\t),\n\tmeta_observation: v.optional(\n\t\tv.pipe(v.string(), v.description('Metacognitive observation about reasoning process'))\n\t),\n\treasoning_depth: v.optional(\n\t\tv.pipe(\n\t\t\tv.picklist(['shallow', 'moderate', 'deep']),\n\t\t\tv.description('Effort signal: how deep reasoning should go')\n\t\t)\n\t),\n\tsession_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'Session ID must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(100),\n\t\t\tv.description(\n\t\t\t\t'Optional session identifier for state isolation. When provided, thought history, branches, and statistics are scoped to this session. Omitting preserves global behavior.'\n\t\t\t)\n\t\t)\n\t),\n\treset_state: v.optional(\n\t\tv.pipe(\n\t\t\tv.boolean(),\n\t\t\tv.description(\n\t\t\t\t'When true, clears all state for the target session before processing this thought. The thought is then processed as the first in a fresh session.'\n\t\t\t)\n\t\t)\n\t),\n\ttool_name: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Name of the tool being invoked (for tool_call thoughts)'))),\n\ttool_arguments: v.optional(v.pipe(v.record(v.string(), v.unknown()), v.description('Arguments passed to the tool (for tool_call thoughts)'))),\n\ttool_result: v.optional(v.pipe(v.unknown(), v.description('Result returned by the tool (for tool_observation thoughts)'))),\n\tcontinuation_token: v.optional(v.pipe(v.string(), v.minLength(1), v.description('Token for resuming long-running tool invocations'))),\n\tdecomposition_children: v.optional(v.pipe(v.array(v.string()), v.description('Child thought IDs produced by decomposition'))),\n\tbacktrack_target: v.optional(v.pipe(v.number(), v.integer(), v.minValue(1), v.description('Thought number to backtrack to. When the parent thought has thought_type=backtrack, this thought is logically retracted: it remains in history but is excluded from quality signals and reasoning stats.'))),\n\tregister_branch_id: v.optional(\n\t\tv.pipe(\n\t\t\tv.string(),\n\t\t\tv.regex(\n\t\t\t\t/^[a-zA-Z0-9_-]+$/,\n\t\t\t\t'register_branch_id must contain only letters, numbers, hyphens, and underscores'\n\t\t\t),\n\t\t\tv.minLength(1),\n\t\t\tv.maxLength(50),\n\t\t\tv.description(\n\t\t\t\t'Pre-declares a branch ID for this session before any thoughts reference it. Useful so that subsequent thoughts using merge_branch_ids can target a branch that has not yet received any thoughts.'\n\t\t\t)\n\t\t)\n\t),\n});\n\n/**\n * The sequential thinking tool definition for MCP registration.\n *\n * This object defines the tool that is registered with the MCP server.\n * The inputSchema is left empty as the schema is handled by tmcp\n * when registering the tool using the Valibot adapter.\n *\n * @example\n * ```typescript\n * import { SEQUENTIAL_THINKING_TOOL } from './schema.js';\n * import { McpServer } from 'tmcp';\n *\n * const server = new McpServer({ name: 'my-server', version: '1.0.0' });\n * server.tool({\n * name: SEQUENTIAL_THINKING_TOOL.name,\n * description: SEQUENTIAL_THINKING_TOOL.description,\n * schema: SequentialThinkingSchema\n * }, handler);\n * ```\n */\nexport const SEQUENTIAL_THINKING_TOOL: Tool = {\n\tname: 'sequentialthinking_tools',\n\tdescription: TOOL_DESCRIPTION,\n\tinputSchema: {}, // Schema is handled by tmcp when registering the tool\n};\n\n/**\n * Valibot schema for validating JSON-RPC 2.0 request messages.\n *\n * Validates that a JSON-RPC request has:\n * - A jsonrpc version (must be \"2.0\")\n * - A method name (string)\n * - Optional params (object or array)\n * - Optional id (string, number, or null for notifications)\n *\n * @example\n * ```typescript\n * import { safeParse } from 'valibot';\n * import { JsonRpcRequestSchema } from './schema.js';\n *\n * const result = safeParse(JsonRpcRequestSchema, {\n * jsonrpc: '2.0',\n * method: 'tools/list',\n * id: 1\n * });\n * ```\n */\nexport const JsonRpcRequestSchema = v.object({\n\tjsonrpc: v.pipe(\n\t\tv.string(),\n\t\tv.literal('2.0'),\n\t\tv.description('JSON-RPC protocol version (must be \"2.0\")')\n\t),\n\tmethod: v.pipe(v.string(), v.minLength(1), v.description('Method name to invoke')),\n\tparams: v.optional(\n\t\tv.pipe(\n\t\t\tv.union([v.object({}), v.array(v.unknown())]),\n\t\t\tv.description('Method parameters (object or array)')\n\t\t)\n\t),\n\tid: v.optional(\n\t\tv.pipe(\n\t\t\tv.union([v.string(), v.number(), v.null()]),\n\t\t\tv.description('Request ID (omit for notifications)')\n\t\t)\n\t),\n});\n\n/**\n * Schema for {@link EdgeKind} — the semantic relationship between two thoughts.\n */\nexport const EdgeKindSchema = v.union([\n\tv.literal('sequence'),\n\tv.literal('branch'),\n\tv.literal('merge'),\n\tv.literal('verifies'),\n\tv.literal('critiques'),\n\tv.literal('derives_from'),\n\tv.literal('tool_invocation'),\n\tv.literal('revises'),\n]) satisfies v.GenericSchema<EdgeKind>;\n\n/**\n * Schema for {@link Edge} — a directed edge in the thought DAG.\n */\nexport const EdgeSchema = v.object({\n\tid: v.pipe(v.string(), v.minLength(1), v.maxLength(30)),\n\tfrom: v.pipe(v.string(), v.minLength(1), v.maxLength(30)),\n\tto: v.pipe(v.string(), v.minLength(1), v.maxLength(30)),\n\tkind: EdgeKindSchema,\n\tsessionId: v.pipe(v.string(), v.minLength(1)),\n\tcreatedAt: v.number(),\n\tmetadata: v.optional(v.record(v.string(), v.unknown())),\n}) satisfies v.GenericSchema<Omit<Edge, 'id' | 'from' | 'to' | 'sessionId'> & { id: string; from: string; to: string; sessionId: string }>;\n"],"names":["TOOL_DESCRIPTION","ToolRecommendationSchema","v","SkillRecommendationSchema","StepRecommendationSchema","PartialToolRecommendationSchema","PartialStepRecommendationSchema","SequentialThinkingSchema","SEQUENTIAL_THINKING_TOOL","JsonRpcRequestSchema","EdgeKindSchema","EdgeSchema"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/HttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAQ3E,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC7D;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,aAAc,SAAQ,aAAc,YAAW,UAAU;IACrE,IAAI,IAAI,IAAI,aAAa,CAAmB;IAC5C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;gBAEpC,OAAO,GAAE,oBAAyB;IAY9C;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;OAKG;YACW,cAAc;IAiE5B;;;;;OAKG;YACW,kBAAkB;IAqFhC;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAW3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAErF"}
1
+ {"version":3,"file":"HttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/HttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAS3E,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC7D;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,aAAc,SAAQ,aAAc,YAAW,UAAU;IACrE,IAAI,IAAI,IAAI,aAAa,CAAmB;IAC5C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;gBAEpC,OAAO,GAAE,oBAAyB;IAY9C;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD;;OAEG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;OAKG;YACW,cAAc;IAiE5B;;;;;OAKG;YACW,kBAAkB;IAyFhC;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAW3B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAErF"}
@@ -1,9 +1,11 @@
1
1
  import { createServer } from "node:http";
2
+ import { randomUUID } from "node:crypto";
2
3
  import { safeParse } from "valibot";
3
4
  import { getErrorMessage } from "../errors.js";
4
5
  import { JsonRpcRequestSchema } from "../schema.js";
5
6
  import { BaseTransport } from "./BaseTransport.js";
6
7
  import { readRequestBody, sendCorsPreflight, sendJsonRpcError, sendJsonRpcResponse } from "./HttpHelpers.js";
8
+ import { runWithContext } from "../context/RequestContext.js";
7
9
  class HttpTransport extends BaseTransport {
8
10
  get kind() {
9
11
  return 'http';
@@ -140,9 +142,13 @@ class HttpTransport extends BaseTransport {
140
142
  sendJsonRpcError(res, 200, -32603, 'Server not ready', jsonRpcRequest?.id ?? null);
141
143
  return;
142
144
  }
143
- const response = await this._mcpServer.receive(jsonRpcRequest, {
144
- sessionInfo: {}
145
- });
145
+ const owner = randomUUID();
146
+ const response = await runWithContext({
147
+ requestId: randomUUID(),
148
+ owner
149
+ }, ()=>this._mcpServer.receive(jsonRpcRequest, {
150
+ sessionInfo: {}
151
+ }));
146
152
  clearTimeout(timeout);
147
153
  this._activeRequests--;
148
154
  if (response) sendJsonRpcResponse(res, response);
@@ -1 +1 @@
1
- {"version":3,"file":"transport/HttpTransport.js","sources":["../../src/transport/HttpTransport.ts"],"sourcesContent":["/**\n * HTTP Transport implementation.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({\n * port: 3000,\n * host: 'localhost'\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from 'node:http';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport { getErrorMessage } from '../errors.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport type { ITransport, TransportKind } from '../contracts/transport.js';\nimport {\n\treadRequestBody,\n\tsendCorsPreflight,\n\tsendJsonRpcError,\n\tsendJsonRpcResponse,\n} from './HttpHelpers.js';\n\nexport interface HttpTransportOptions extends TransportOptions {\n\t/**\n\t * Path for messages endpoint\n\t * @default '/messages'\n\t */\n\tpath?: string;\n\tmetrics?: IMetrics;\n\tmetricsProvider?: () => string;\n\n\t/**\n\t * Enable request body size limit\n\t * @default true\n\t */\n\tenableBodySizeLimit?: boolean;\n\n\t/**\n\t * Maximum request body size in bytes\n\t * @default 10485760 (10MB)\n\t */\n\tmaxBodySize?: number;\n\n\t/**\n\t * Request timeout in milliseconds\n\t * @default 30000 (30 seconds)\n\t */\n\trequestTimeout?: number;\n}\n\n/**\n * HTTP Transport for MCP server.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @remarks\n * **Security Features:**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n * - Request body size limits (configurable, default 10MB)\n * - Request timeout (configurable, default 30s)\n *\n * **Rate Limiting:**\n * - Tracks requests per IP address within a time window\n * - Returns 429 Too Many Requests when limit exceeded\n * - Can be disabled via `enableRateLimit: false`\n *\n * **HTTP Status Code Mapping:**\n * - 200: Success (JSON-RPC response)\n * - 204: CORS Preflight (empty body)\n * - 400: Bad Request\n * - 403: Forbidden (invalid CORS)\n * - 404: Not Found\n * - 413: Payload Too Large\n * - 429: Too Many Requests\n * - 500: Internal Server Error\n * - 503: Server Not Ready\n */\nexport class HttpTransport extends BaseTransport implements ITransport {\n\tget kind(): TransportKind { return 'http'; }\n\tprivate _server: ReturnType<typeof createServer>;\n\tprivate _mcpServer: McpServer | null = null;\n\tprivate _requestTimeout: number;\n\tprivate _bodySizeLimitEnabled: boolean;\n\tprivate _maxBodySize: number;\n\tprivate _requestCount: number = 0;\n\tprivate _activeRequests: number = 0;\n\tprivate _path: string;\n\tprivate _metrics?: IMetrics;\n\tprivate _metricsProvider: (() => string) | null;\n\n\tconstructor(options: HttpTransportOptions = {}) {\n\t\tsuper(options);\n\n\t\tthis._requestTimeout = options.requestTimeout ?? 30000;\n\t\tthis._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;\n\t\tthis._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;\n\t\tthis._path = options.path ?? '/messages';\n\t\tthis._metrics = options.metrics;\n\t\tthis._metricsProvider = options.metricsProvider ?? null;\n\t\tthis._server = createServer((req, res) => this._handleRequest(req, res));\n\t}\n\n\t/**\n\t * Get number of active HTTP connections.\n\t */\n\tget clientCount(): number {\n\t\treturn this._activeRequests;\n\t}\n\n\t/**\n\t * Connects MCP server to this transport.\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server.listen(this._port, this._host, () => {\n\t\t\t\tthis.log('info', `HTTP transport listening on http://${this._host}:${this._port}`);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Track an error in metrics.\n\t */\n\tprivate _trackError(errorType: string): void {\n\t\tthis._metrics?.counter(\n\t\t\t'http_request_errors_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', error_type: errorType },\n\t\t\t'Total HTTP request errors'\n\t\t);\n\t}\n\n\t/**\n\t * Route and handle incoming HTTP requests.\n\t *\n\t * Performs security checks (host, shutdown, rate limit, CORS) then\n\t * dispatches to the appropriate endpoint handler.\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tconst requestPath = req.url || '/';\n\t\tconst requestMethod = req.method || 'GET';\n\t\tthis._metrics?.counter('http_requests_total', 1, {}, 'Total HTTP transport requests');\n\t\tthis._metrics?.counter(\n\t\t\t'http_transport_requests_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', method: requestMethod, path: requestPath },\n\t\t\t'Total HTTP requests by transport'\n\t\t);\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('http_request_duration_seconds', durationSeconds, {});\n\t\t\tthis._metrics?.histogram('http_transport_request_duration_seconds', durationSeconds, {\n\t\t\t\ttransport: 'http',\n\t\t\t\tpath: requestPath,\n\t\t\t});\n\t\t});\n\n\t\t// Security middleware chain\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isShuttingDown) {\n\t\t\tthis._trackError('shutting_down');\n\t\t\tsendJsonRpcError(res, 503, -32603, 'Server is shutting down');\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tthis._trackError('rate_limit');\n\t\t\tres.setHeader('Retry-After', '60');\n\t\t\tsendJsonRpcError(res, 429, -32000, 'Too many requests');\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid origin');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setCorsHeaders(res);\n\n\t\t// Static endpoints\n\t\tif (req.method === 'GET' && req.url === '/metrics')\n\t\t\treturn this.handleMetricsEndpoint(res, this._metricsProvider);\n\t\tif (req.method === 'OPTIONS') return sendCorsPreflight(res);\n\t\tif (req.method === 'GET' && req.url === '/health')\n\t\t\treturn this.handleHealthEndpoint(res, { requests: this._requestCount });\n\t\tif (req.method === 'GET' && req.url === '/ready') return this.handleReadinessEndpoint(res);\n\n\t\t// MCP endpoint\n\t\tif (req.method === 'POST' && req.url === this._path) return this._handlePostRequest(req, res);\n\n\t\t// 404\n\t\tthis._trackError('not_found');\n\t\tsendJsonRpcError(res, 404, -32601, 'Not Found');\n\t}\n\n\t/**\n\t * Handle POST to the MCP messages endpoint.\n\t *\n\t * Reads the request body, validates JSON-RPC format, and delegates\n\t * processing to the MCP server.\n\t */\n\tprivate async _handlePostRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tthis._requestCount++;\n\t\tthis._activeRequests++;\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tthis._activeRequests--;\n\t\t\tthis._trackError('timeout');\n\t\t\tsendJsonRpcError(res, 500, -32603, 'Request timeout');\n\t\t}, this._requestTimeout);\n\n\t\ttry {\n\t\t\tconst maxBodySize = this._bodySizeLimitEnabled ? this._maxBodySize : 0;\n\t\t\tconst body = await readRequestBody(req, maxBodySize);\n\n\t\t\tif (body === null) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('payload_too_large');\n\t\t\t\tsendJsonRpcError(res, 413, -32000, 'Request body too large');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet jsonRpcRequest;\n\t\t\ttry {\n\t\t\t\tjsonRpcRequest = JSON.parse(body);\n\t\t\t} catch {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('parse_error');\n\t\t\t\tsendJsonRpcError(res, 200, -32700, 'Parse error');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, jsonRpcRequest);\n\t\t\tif (!parseResult.success) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('validation');\n\t\t\t\tsendJsonRpcError(\n\t\t\t\t\tres,\n\t\t\t\t\t200,\n\t\t\t\t\t-32600,\n\t\t\t\t\t'Invalid Request',\n\t\t\t\t\tjsonRpcRequest?.id ?? null,\n\t\t\t\t\tparseResult.issues\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!this._mcpServer) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('server_not_ready');\n\t\t\t\tsendJsonRpcError(res, 200, -32603, 'Server not ready', jsonRpcRequest?.id ?? null);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst response = await this._mcpServer.receive(jsonRpcRequest, {\n\t\t\t\tsessionInfo: {},\n\t\t\t});\n\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\n\t\t\tif (response) {\n\t\t\t\tsendJsonRpcResponse(res, response);\n\t\t\t} else {\n\t\t\t\tres.writeHead(204);\n\t\t\t\tres.end();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\t\t\tthis._trackError('internal_error');\n\t\t\tsendJsonRpcError(\n\t\t\t\tres,\n\t\t\t\t200,\n\t\t\t\t-32603,\n\t\t\t\t'Internal error',\n\t\t\t\tnull,\n\t\t\t\tgetErrorMessage(error)\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Returns number of requests handled.\n\t */\n\tget requestCount(): number {\n\t\treturn this._requestCount;\n\t}\n\n\t/**\n\t * Stops transport server.\n\t */\n\tasync stop(): Promise<void> {\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server.close(() => {\n\t\t\t\tthis.log('info', 'HTTP transport stopped');\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Create an HTTP transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured HTTP transport\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({ port: 3000 });\n * await transport.connect(server);\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions = {}): HttpTransport {\n\treturn new HttpTransport(options);\n}\n"],"names":["HttpTransport","BaseTransport","options","createServer","req","res","mcpServer","Promise","resolve","errorType","startTime","Date","requestPath","requestMethod","durationSeconds","sendJsonRpcError","clientIp","sendCorsPreflight","timeout","setTimeout","maxBodySize","body","readRequestBody","clearTimeout","jsonRpcRequest","JSON","parseResult","safeParse","JsonRpcRequestSchema","response","sendJsonRpcResponse","error","getErrorMessage","createHttpTransport"],"mappings":"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"}
1
+ {"version":3,"file":"transport/HttpTransport.js","sources":["../../src/transport/HttpTransport.ts"],"sourcesContent":["/**\n * HTTP Transport implementation.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({\n * port: 3000,\n * host: 'localhost'\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport { getErrorMessage } from '../errors.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport type { ITransport, TransportKind } from '../contracts/transport.js';\nimport {\n\treadRequestBody,\n\tsendCorsPreflight,\n\tsendJsonRpcError,\n\tsendJsonRpcResponse,\n} from './HttpHelpers.js';\nimport { runWithContext } from '../context/RequestContext.js';\n\nexport interface HttpTransportOptions extends TransportOptions {\n\t/**\n\t * Path for messages endpoint\n\t * @default '/messages'\n\t */\n\tpath?: string;\n\tmetrics?: IMetrics;\n\tmetricsProvider?: () => string;\n\n\t/**\n\t * Enable request body size limit\n\t * @default true\n\t */\n\tenableBodySizeLimit?: boolean;\n\n\t/**\n\t * Maximum request body size in bytes\n\t * @default 10485760 (10MB)\n\t */\n\tmaxBodySize?: number;\n\n\t/**\n\t * Request timeout in milliseconds\n\t * @default 30000 (30 seconds)\n\t */\n\trequestTimeout?: number;\n}\n\n/**\n * HTTP Transport for MCP server.\n *\n * This transport provides a stateless, REST-like API interface for MCP tool invocations\n * using standard HTTP request-response patterns.\n *\n * @remarks\n * **Security Features:**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n * - Request body size limits (configurable, default 10MB)\n * - Request timeout (configurable, default 30s)\n *\n * **Rate Limiting:**\n * - Tracks requests per IP address within a time window\n * - Returns 429 Too Many Requests when limit exceeded\n * - Can be disabled via `enableRateLimit: false`\n *\n * **HTTP Status Code Mapping:**\n * - 200: Success (JSON-RPC response)\n * - 204: CORS Preflight (empty body)\n * - 400: Bad Request\n * - 403: Forbidden (invalid CORS)\n * - 404: Not Found\n * - 413: Payload Too Large\n * - 429: Too Many Requests\n * - 500: Internal Server Error\n * - 503: Server Not Ready\n */\nexport class HttpTransport extends BaseTransport implements ITransport {\n\tget kind(): TransportKind { return 'http'; }\n\tprivate _server: ReturnType<typeof createServer>;\n\tprivate _mcpServer: McpServer | null = null;\n\tprivate _requestTimeout: number;\n\tprivate _bodySizeLimitEnabled: boolean;\n\tprivate _maxBodySize: number;\n\tprivate _requestCount: number = 0;\n\tprivate _activeRequests: number = 0;\n\tprivate _path: string;\n\tprivate _metrics?: IMetrics;\n\tprivate _metricsProvider: (() => string) | null;\n\n\tconstructor(options: HttpTransportOptions = {}) {\n\t\tsuper(options);\n\n\t\tthis._requestTimeout = options.requestTimeout ?? 30000;\n\t\tthis._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;\n\t\tthis._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;\n\t\tthis._path = options.path ?? '/messages';\n\t\tthis._metrics = options.metrics;\n\t\tthis._metricsProvider = options.metricsProvider ?? null;\n\t\tthis._server = createServer((req, res) => this._handleRequest(req, res));\n\t}\n\n\t/**\n\t * Get number of active HTTP connections.\n\t */\n\tget clientCount(): number {\n\t\treturn this._activeRequests;\n\t}\n\n\t/**\n\t * Connects MCP server to this transport.\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server.listen(this._port, this._host, () => {\n\t\t\t\tthis.log('info', `HTTP transport listening on http://${this._host}:${this._port}`);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Track an error in metrics.\n\t */\n\tprivate _trackError(errorType: string): void {\n\t\tthis._metrics?.counter(\n\t\t\t'http_request_errors_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', error_type: errorType },\n\t\t\t'Total HTTP request errors'\n\t\t);\n\t}\n\n\t/**\n\t * Route and handle incoming HTTP requests.\n\t *\n\t * Performs security checks (host, shutdown, rate limit, CORS) then\n\t * dispatches to the appropriate endpoint handler.\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tconst requestPath = req.url || '/';\n\t\tconst requestMethod = req.method || 'GET';\n\t\tthis._metrics?.counter('http_requests_total', 1, {}, 'Total HTTP transport requests');\n\t\tthis._metrics?.counter(\n\t\t\t'http_transport_requests_total',\n\t\t\t1,\n\t\t\t{ transport: 'http', method: requestMethod, path: requestPath },\n\t\t\t'Total HTTP requests by transport'\n\t\t);\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('http_request_duration_seconds', durationSeconds, {});\n\t\t\tthis._metrics?.histogram('http_transport_request_duration_seconds', durationSeconds, {\n\t\t\t\ttransport: 'http',\n\t\t\t\tpath: requestPath,\n\t\t\t});\n\t\t});\n\n\t\t// Security middleware chain\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isShuttingDown) {\n\t\t\tthis._trackError('shutting_down');\n\t\t\tsendJsonRpcError(res, 503, -32603, 'Server is shutting down');\n\t\t\treturn;\n\t\t}\n\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tthis._trackError('rate_limit');\n\t\t\tres.setHeader('Retry-After', '60');\n\t\t\tsendJsonRpcError(res, 429, -32000, 'Too many requests');\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._trackError('forbidden');\n\t\t\tsendJsonRpcError(res, 403, -32000, 'Forbidden - invalid origin');\n\t\t\treturn;\n\t\t}\n\n\t\tthis.setCorsHeaders(res);\n\n\t\t// Static endpoints\n\t\tif (req.method === 'GET' && req.url === '/metrics')\n\t\t\treturn this.handleMetricsEndpoint(res, this._metricsProvider);\n\t\tif (req.method === 'OPTIONS') return sendCorsPreflight(res);\n\t\tif (req.method === 'GET' && req.url === '/health')\n\t\t\treturn this.handleHealthEndpoint(res, { requests: this._requestCount });\n\t\tif (req.method === 'GET' && req.url === '/ready') return this.handleReadinessEndpoint(res);\n\n\t\t// MCP endpoint\n\t\tif (req.method === 'POST' && req.url === this._path) return this._handlePostRequest(req, res);\n\n\t\t// 404\n\t\tthis._trackError('not_found');\n\t\tsendJsonRpcError(res, 404, -32601, 'Not Found');\n\t}\n\n\t/**\n\t * Handle POST to the MCP messages endpoint.\n\t *\n\t * Reads the request body, validates JSON-RPC format, and delegates\n\t * processing to the MCP server.\n\t */\n\tprivate async _handlePostRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tthis._requestCount++;\n\t\tthis._activeRequests++;\n\n\t\tconst timeout = setTimeout(() => {\n\t\t\tthis._activeRequests--;\n\t\t\tthis._trackError('timeout');\n\t\t\tsendJsonRpcError(res, 500, -32603, 'Request timeout');\n\t\t}, this._requestTimeout);\n\n\t\ttry {\n\t\t\tconst maxBodySize = this._bodySizeLimitEnabled ? this._maxBodySize : 0;\n\t\t\tconst body = await readRequestBody(req, maxBodySize);\n\n\t\t\tif (body === null) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('payload_too_large');\n\t\t\t\tsendJsonRpcError(res, 413, -32000, 'Request body too large');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet jsonRpcRequest;\n\t\t\ttry {\n\t\t\t\tjsonRpcRequest = JSON.parse(body);\n\t\t\t} catch {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('parse_error');\n\t\t\t\tsendJsonRpcError(res, 200, -32700, 'Parse error');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, jsonRpcRequest);\n\t\t\tif (!parseResult.success) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('validation');\n\t\t\t\tsendJsonRpcError(\n\t\t\t\t\tres,\n\t\t\t\t\t200,\n\t\t\t\t\t-32600,\n\t\t\t\t\t'Invalid Request',\n\t\t\t\t\tjsonRpcRequest?.id ?? null,\n\t\t\t\t\tparseResult.issues\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!this._mcpServer) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tthis._activeRequests--;\n\t\t\t\tthis._trackError('server_not_ready');\n\t\t\t\tsendJsonRpcError(res, 200, -32603, 'Server not ready', jsonRpcRequest?.id ?? null);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst owner = randomUUID();\n\t\t\tconst response = await runWithContext(\n\t\t\t\t{ requestId: randomUUID(), owner },\n\t\t\t\t() => this._mcpServer!.receive(jsonRpcRequest, {\n\t\t\t\t\tsessionInfo: {},\n\t\t\t\t})\n\t\t\t);\n\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\n\t\t\tif (response) {\n\t\t\t\tsendJsonRpcResponse(res, response);\n\t\t\t} else {\n\t\t\t\tres.writeHead(204);\n\t\t\t\tres.end();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tclearTimeout(timeout);\n\t\t\tthis._activeRequests--;\n\t\t\tthis._trackError('internal_error');\n\t\t\tsendJsonRpcError(\n\t\t\t\tres,\n\t\t\t\t200,\n\t\t\t\t-32603,\n\t\t\t\t'Internal error',\n\t\t\t\tnull,\n\t\t\t\tgetErrorMessage(error)\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Returns number of requests handled.\n\t */\n\tget requestCount(): number {\n\t\treturn this._requestCount;\n\t}\n\n\t/**\n\t * Stops transport server.\n\t */\n\tasync stop(): Promise<void> {\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server.close(() => {\n\t\t\t\tthis.log('info', 'HTTP transport stopped');\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Create an HTTP transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured HTTP transport\n *\n * @example\n * ```typescript\n * const transport = new HttpTransport({ port: 3000 });\n * await transport.connect(server);\n * ```\n */\nexport function createHttpTransport(options: HttpTransportOptions = {}): HttpTransport {\n\treturn new HttpTransport(options);\n}\n"],"names":["HttpTransport","BaseTransport","options","createServer","req","res","mcpServer","Promise","resolve","errorType","startTime","Date","requestPath","requestMethod","durationSeconds","sendJsonRpcError","clientIp","sendCorsPreflight","timeout","setTimeout","maxBodySize","body","readRequestBody","clearTimeout","jsonRpcRequest","JSON","parseResult","safeParse","JsonRpcRequestSchema","owner","randomUUID","response","runWithContext","sendJsonRpcResponse","error","getErrorMessage","createHttpTransport"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SseTransport.d.ts","sourceRoot":"","sources":["../../src/transport/SseTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC3E;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAa,SAAQ,aAAc,YAAW,UAAU;IACpE,IAAI,IAAI,IAAI,aAAa,CAAkB;IAC3C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,eAAe,CAAC,CAAiB;gBAE7B,OAAO,GAAE,mBAAwB;IAU7C;;;;OAIG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlD,OAAO,CAAC,UAAU,CAA0B;IAE5C;;OAEG;YACW,cAAc;IA2F5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;OAEG;YACW,qBAAqB;IAYnC;;OAEG;YACW,oBAAoB;IA6DlC;;OAEG;YACW,cAAc;IAyD5B;;OAEG;IACH,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,8BAA8B;IAStC,OAAO,CAAC,kBAAkB;IAyB1B;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAM7C;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,cAAc,GAAG,SAAS,CAE/C;IAED;;;;;OAKG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA6B5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAElF"}
1
+ {"version":3,"file":"SseTransport.d.ts","sourceRoot":"","sources":["../../src/transport/SseTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE3E;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAa,SAAQ,aAAc,YAAW,UAAU;IACpE,IAAI,IAAI,IAAI,aAAa,CAAkB;IAC3C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,eAAe,CAAC,CAAiB;gBAE7B,OAAO,GAAE,mBAAwB;IAU7C;;;;OAIG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlD,OAAO,CAAC,UAAU,CAA0B;IAE5C;;OAEG;YACW,cAAc;IA2F5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAc1B;;OAEG;YACW,qBAAqB;IAYnC;;OAEG;YACW,oBAAoB;IA6DlC;;OAEG;YACW,cAAc;IA8D5B;;OAEG;IACH,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,8BAA8B;IAStC,OAAO,CAAC,kBAAkB;IAyB1B;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAM7C;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,cAAc,GAAG,SAAS,CAE/C;IAED;;;;;OAKG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA6B5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAElF"}
@@ -1,8 +1,10 @@
1
1
  import { createServer } from "node:http";
2
+ import { randomUUID } from "node:crypto";
2
3
  import { URL } from "node:url";
3
4
  import { safeParse } from "valibot";
4
5
  import { JsonRpcRequestSchema } from "../schema.js";
5
6
  import { BaseTransport } from "./BaseTransport.js";
7
+ import { runWithContext } from "../context/RequestContext.js";
6
8
  class SseTransport extends BaseTransport {
7
9
  get kind() {
8
10
  return 'sse';
@@ -227,9 +229,14 @@ class SseTransport extends BaseTransport {
227
229
  return;
228
230
  }
229
231
  if (this._mcpServer) {
230
- const response = await this._mcpServer.receive(jsonRpcRequest, {
231
- sessionInfo: {}
232
- });
232
+ const sessionId = this._clientSessionMap.get(res);
233
+ const owner = sessionId ?? `sse-${randomUUID()}`;
234
+ const response = await runWithContext({
235
+ requestId: randomUUID(),
236
+ owner
237
+ }, ()=>this._mcpServer.receive(jsonRpcRequest, {
238
+ sessionInfo: {}
239
+ }));
233
240
  res.writeHead(200, {
234
241
  'Content-Type': 'application/json'
235
242
  });
@@ -1 +1 @@
1
- {"version":3,"file":"transport/SseTransport.js","sources":["../../src/transport/SseTransport.ts"],"sourcesContent":["/**\n * SSE (Server-Sent Events) Transport implementation.\n *\n * This transport allows multiple concurrent connections over HTTP using Server-Sent Events,\n * enabling multi-user scenarios and horizontal scaling.\n *\n * When a ConnectionPool is provided, each SSE client gets an isolated session with its own\n * thought history. Without a pool, all clients share a single server instance (backward compatible).\n *\n * @example\n * ```typescript\n * const transport = new SseTransport({\n * port: 3000,\n * host: 'localhost'\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { URL } from 'node:url';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport type { ConnectionPool } from '../pool/ConnectionPool.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport type { ITransport, TransportKind } from '../contracts/transport.js';\n/**\n * SSE-specific transport options extending base TransportOptions.\n */\nexport interface SseTransportOptions extends TransportOptions {\n\tpath?: string;\n\tmetrics?: IMetrics;\n\t/**\n\t * Optional connection pool for per-session state isolation.\n\t * When provided, each SSE client gets an isolated thought history.\n\t * When omitted, all clients share a single server instance (backward compatible).\n\t */\n\tconnectionPool?: ConnectionPool;\n}\n\n/**\n * SSE Transport for MCP server over HTTP.\n *\n * This transport uses Server-Sent Events (SSE) to communicate with clients,\n * allowing multiple concurrent connections and web-based clients.\n *\n * @remarks\n * **Security Features:**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n *\n * **Rate Limiting:**\n * - Tracks requests per IP address within a time window\n * - Returns 429 Too Many Requests when limit exceeded\n * - Can be disabled via `enableRateLimit: false`\n */\nexport class SseTransport extends BaseTransport implements ITransport {\n\tget kind(): TransportKind { return 'sse'; }\n\tprivate _server: ReturnType<typeof createServer>;\n\tprivate _path: string;\n\tprivate _clients: Set<ServerResponse> = new Set();\n\tprivate _clientSessionMap: Map<ServerResponse, string> = new Map();\n\tprivate _messageQueue: Map<string, unknown[]> = new Map();\n\tprivate _metrics?: IMetrics;\n\tprivate _connectionPool?: ConnectionPool;\n\n\tconstructor(options: SseTransportOptions = {}) {\n\t\tsuper(options);\n\t\tthis._path = options.path ?? '/sse';\n\t\tthis._metrics = options.metrics;\n\t\tthis._connectionPool = options.connectionPool;\n\t\tthis._updateActiveConnectionsMetric();\n\n\t\tthis._server = createServer((req, res) => this._handleRequest(req, res));\n\t}\n\n\t/**\n\t * Connect MCP server to this transport.\n\t *\n\t * @param mcpServer - The MCP server instance\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server.listen(this._port, this._host, () => {\n\t\t\t\tthis.log('info', `SSE transport listening on http://${this._host}:${this._port}`);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _mcpServer: McpServer | null = null;\n\n\t/**\n\t * Handle incoming HTTP requests\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tconst requestPath = req.url || '/';\n\t\tconst requestMethod = req.method || 'GET';\n\t\tthis._metrics?.counter('http_requests_total', 1, { transport: 'sse', method: requestMethod, path: requestPath }, 'Total HTTP requests');\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('http_request_duration_seconds', durationSeconds, { transport: 'sse', path: requestPath });\n\t\t});\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'forbidden' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(403, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Forbidden - invalid host header' }));\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(req.url || '', `http://${req.headers.host}`);\n\n\t\t// Check rate limit first\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'rate_limit' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(429, {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t'Retry-After': '60',\n\t\t\t});\n\t\t\tres.end(JSON.stringify({ error: 'Too many requests' }));\n\t\t\treturn;\n\t\t}\n\n\t\t// Validate CORS origin\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'forbidden' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(403, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Forbidden - invalid origin' }));\n\t\t\treturn;\n\t\t}\n\n\t\t// Set CORS headers\n\t\tthis.setCorsHeaders(res);\n\n\t\t// Sanitize query parameters\n\t\tconst sanitizedParams = this.sanitizeQueryParams(url);\n\n\t\t// Validate session ID if present\n\t\tif (sanitizedParams.session || sanitizedParams.sessionId) {\n\t\t\tconst sessionId = (sanitizedParams.session ?? sanitizedParams.sessionId)!;\n\t\t\tif (!this.validateSessionId(sessionId)) {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'validation' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(JSON.stringify({ error: 'Invalid session ID format' }));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// Handle CORS preflight\n\t\tif (this._enableCors && req.method === 'OPTIONS') {\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle SSE endpoint\n\t\tif (url.pathname === this._path && req.method === 'GET') {\n\t\t\tawait this._handleSseConnection(req, res, sanitizedParams);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle message endpoint (for receiving messages from clients)\n\t\tif (url.pathname === `${this._path}/message` && req.method === 'POST') {\n\t\t\tawait this._handleMessage(req, res, sanitizedParams);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle health check (liveness)\n\t\tif (url.pathname === '/health') {\n\t\t\tthis._handleHealthCheck(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle readiness check\n\t\tif (url.pathname === '/ready') {\n\t\t\tawait this._handleReadinessCheck(res);\n\t\t\treturn;\n\t\t}\n\n\n\t\t// 404 for unknown paths\n\t\tres.writeHead(404, { 'Content-Type': 'text/plain' });\n\t\tres.end('Not Found');\n\t}\n\n\t/**\n\t * Handle health check (liveness) endpoint\n\t */\n\tprivate _handleHealthCheck(res: ServerResponse): void {\n\t\tconst healthData: Record<string, unknown> = { status: 'healthy', clients: this._clients.size };\n\t\tif (this._connectionPool) {\n\t\t\tconst poolStats = this._connectionPool.getStats();\n\t\t\thealthData.pool = poolStats;\n\t\t}\n\t\tif (this._healthChecker) {\n\t\t\tconst liveness = this._healthChecker.checkLiveness();\n\t\t\thealthData.liveness = liveness;\n\t\t}\n\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify(healthData));\n\t}\n\n\t/**\n\t * Handle readiness check endpoint\n\t */\n\tprivate async _handleReadinessCheck(res: ServerResponse): Promise<void> {\n\t\tif (this._healthChecker) {\n\t\t\tconst readiness = await this._healthChecker.checkReadiness();\n\t\t\tconst statusCode = readiness.status === 'ok' ? 200 : 503;\n\t\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify(readiness));\n\t\t} else {\n\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ status: 'ok', timestamp: new Date().toISOString(), components: {} }));\n\t\t}\n\t}\n\n\t/**\n\t * Handle new SSE connection\n\t */\n\tprivate async _handleSseConnection(\n\t\treq: IncomingMessage,\n\t\tres: ServerResponse,\n\t\tparams: Record<string, string>\n\t): Promise<void> {\n\t\t// Set SSE headers\n\t\tres.writeHead(200, {\n\t\t\t'Content-Type': 'text/event-stream',\n\t\t\t'Cache-Control': 'no-cache',\n\t\t\tConnection: 'keep-alive',\n\t\t});\n\n\t\t// Resolve session ID when pool is active\n\t\tlet sessionId: string | undefined;\n\t\tif (this._connectionPool) {\n\t\t\tconst requestedSession = params.session ?? params.sessionId;\n\t\t\tif (requestedSession && this._connectionPool.getSessionInfo(requestedSession)) {\n\t\t\t\tsessionId = requestedSession;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tsessionId = await this._connectionPool.createSession();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tres.write(`event: error\\n`);\n\t\t\t\t\tres.write(`data: ${JSON.stringify({ error: error instanceof Error ? error.message : 'Failed to create session' })}\\n\\n`);\n\t\t\t\t\tres.end();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._clientSessionMap.set(res, sessionId);\n\t\t\tthis._updatePoolMetrics();\n\t\t}\n\n\t\t// Send initial connection event\n\t\tconst connectedPayload: Record<string, unknown> = { timestamp: Date.now() };\n\t\tif (sessionId) {\n\t\t\tconnectedPayload.sessionId = sessionId;\n\t\t}\n\t\tthis._sendSseEvent(res, 'connected', connectedPayload);\n\n\t\t// Add to clients\n\t\tthis._clients.add(res);\n\t\tthis._updateActiveConnectionsMetric();\n\n\t\t// Handle client disconnect\n\t\treq.on('close', () => {\n\t\t\tthis._clients.delete(res);\n\t\t\tthis._clientSessionMap.delete(res);\n\t\t\tthis._updateActiveConnectionsMetric();\n\t\t});\n\n\t\t// Send any queued messages\n\t\tconst clientId = this._generateClientId();\n\t\tconst queued = this._messageQueue.get(clientId);\n\t\tif (queued) {\n\t\t\tfor (const message of queued) {\n\t\t\t\tthis._sendSseEvent(res, 'message', message);\n\t\t\t}\n\t\t\tthis._messageQueue.delete(clientId);\n\t\t}\n\t}\n\n\t/**\n\t * Handle incoming message from client\n\t */\n\tprivate async _handleMessage(\n\t\treq: IncomingMessage,\n\t\tres: ServerResponse,\n\t\t_params: Record<string, string>\n\t): Promise<void> {\n\t\tlet body = '';\n\n\t\tfor await (const chunk of req) {\n\t\t\tbody += chunk.toString();\n\t\t}\n\n\t\ttry {\n\t\t\tconst jsonRpcRequest = JSON.parse(body);\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, jsonRpcRequest);\n\t\t\tif (!parseResult.success) {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'validation' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\t\tid: jsonRpcRequest?.id ?? null,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: -32600,\n\t\t\t\t\t\t\tmessage: 'Invalid Request',\n\t\t\t\t\t\t\tdata: parseResult.issues,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Process message through MCP server\n\t\t\tif (this._mcpServer) {\n\t\t\t\tconst response = await this._mcpServer.receive(jsonRpcRequest, {\n\t\t\t\t\tsessionInfo: {},\n\t\t\t\t});\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t});\n\n\t\t\t\tif (response) {\n\t\t\t\t\tres.end(JSON.stringify(response));\n\t\t\t\t} else {\n\t\t\t\t\tres.end(JSON.stringify({ jsonrpc: '2.0', id: jsonRpcRequest?.id ?? null, result: null }));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'server_not_ready' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(503, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(JSON.stringify({ error: 'Server not ready' }));\n\t\t\t}\n\t\t} catch {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'parse_error' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Invalid JSON' }));\n\t\t}\n\t}\n\n\t/**\n\t * Send an SSE event to a specific client\n\t */\n\tprivate _sendSseEvent(res: ServerResponse, event: string, data: unknown): void {\n\t\ttry {\n\t\t\tres.write(`event: ${event}\\n`);\n\t\t\tres.write(`data: ${JSON.stringify(data)}\\n\\n`);\n\t\t} catch {\n\t\t\t// Client disconnected\n\t\t\tthis._clients.delete(res);\n\t\t\tthis._updateActiveConnectionsMetric();\n\t\t}\n\t}\n\n\tprivate _updateActiveConnectionsMetric(): void {\n\t\tthis._metrics?.gauge(\n\t\t\t'sse_active_connections',\n\t\t\tthis._clients.size,\n\t\t\t{},\n\t\t\t'Current active SSE connections'\n\t\t);\n\t}\n\n\tprivate _updatePoolMetrics(): void {\n\t\tif (!this._connectionPool || !this._metrics) {\n\t\t\treturn;\n\t\t}\n\t\tconst stats = this._connectionPool.getStats();\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_active_sessions',\n\t\t\tstats.activeSessions,\n\t\t\t{},\n\t\t\t'Active sessions in connection pool'\n\t\t);\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_total_sessions',\n\t\t\tstats.totalSessions,\n\t\t\t{},\n\t\t\t'Total sessions in connection pool'\n\t\t);\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_max_sessions',\n\t\t\tstats.maxSessions,\n\t\t\t{},\n\t\t\t'Maximum sessions in connection pool'\n\t\t);\n\t}\n\n\t/**\n\t * Broadcast a message to all connected clients\n\t */\n\tbroadcast(event: string, data: unknown): void {\n\t\tfor (const client of this._clients) {\n\t\t\tthis._sendSseEvent(client, event, data);\n\t\t}\n\t}\n\n\t/**\n\t * Generate a unique client ID\n\t */\n\tprivate _generateClientId(): string {\n\t\treturn `client_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n\t}\n\n\t/**\n\t * Get number of connected clients\n\t */\n\tget clientCount(): number {\n\t\treturn this._clients.size;\n\t}\n\n\t/**\n\t * Get the connection pool, if one was configured.\n\t */\n\tget connectionPool(): ConnectionPool | undefined {\n\t\treturn this._connectionPool;\n\t}\n\n\t/**\n\t * Stop the transport server with graceful shutdown.\n\t *\n\t * @param timeout - Maximum time to wait for requests to drain (not used for SSE)\n\t * @returns Promise that resolves when shutdown is complete\n\t */\n\tasync stop(_timeout?: number): Promise<void> {\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\t// Terminate connection pool if present\n\t\tif (this._connectionPool) {\n\t\t\tawait this._connectionPool.terminate();\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\t// Close all client connections\n\t\t\tfor (const client of this._clients) {\n\t\t\t\ttry {\n\t\t\t\t\tclient.end();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._clients.clear();\n\t\t\tthis._clientSessionMap.clear();\n\t\t\tthis._updateActiveConnectionsMetric();\n\n\t\t\t// Close server\n\t\t\tthis._server.close(() => {\n\t\t\t\tthis.log('info', 'SSE transport stopped');\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Create an SSE transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured SSE transport\n *\n * @example\n * ```typescript\n * const transport = createSseTransport({ port: 3000 });\n * await transport.connect(mcpServer);\n * ```\n */\nexport function createSseTransport(options: SseTransportOptions = {}): SseTransport {\n\treturn new SseTransport(options);\n}\n"],"names":["SseTransport","BaseTransport","Set","Map","options","createServer","req","res","mcpServer","Promise","resolve","startTime","Date","requestPath","requestMethod","durationSeconds","JSON","url","URL","clientIp","sanitizedParams","sessionId","healthData","poolStats","liveness","readiness","statusCode","params","requestedSession","error","Error","connectedPayload","clientId","queued","message","_params","body","chunk","jsonRpcRequest","parseResult","safeParse","JsonRpcRequestSchema","response","event","data","stats","client","Math","_timeout","createSseTransport"],"mappings":";;;;;AA4DO,MAAMA,qBAAqBC;IACjC,IAAI,OAAsB;QAAE,OAAO;IAAO;IAClC,QAAyC;IACzC,MAAc;IACd,WAAgC,IAAIC,MAAM;IAC1C,oBAAiD,IAAIC,MAAM;IAC3D,gBAAwC,IAAIA,MAAM;IAClD,SAAoB;IACpB,gBAAiC;IAEzC,YAAYC,UAA+B,CAAC,CAAC,CAAE;QAC9C,KAAK,CAACA;QACN,IAAI,CAAC,KAAK,GAAGA,QAAQ,IAAI,IAAI;QAC7B,IAAI,CAAC,QAAQ,GAAGA,QAAQ,OAAO;QAC/B,IAAI,CAAC,eAAe,GAAGA,QAAQ,cAAc;QAC7C,IAAI,CAAC,8BAA8B;QAEnC,IAAI,CAAC,OAAO,GAAGC,aAAa,CAACC,KAAKC,MAAQ,IAAI,CAAC,cAAc,CAACD,KAAKC;IACpE;IAOA,MAAM,QAAQC,SAAoB,EAAiB;QAClD,IAAI,CAAC,UAAU,GAAGA;QAElB,OAAO,IAAIC,QAAQ,CAACC;YACnB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE;gBAC3C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,kCAAkC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE;gBAChFA;YACD;QACD;IACD;IAEQ,aAA+B,KAAK;IAK5C,MAAc,eAAeJ,GAAoB,EAAEC,GAAmB,EAAiB;QACtF,MAAMI,YAAYC,KAAK,GAAG;QAC1B,MAAMC,cAAcP,IAAI,GAAG,IAAI;QAC/B,MAAMQ,gBAAgBR,IAAI,MAAM,IAAI;QACpC,IAAI,CAAC,QAAQ,EAAE,QAAQ,uBAAuB,GAAG;YAAE,WAAW;YAAO,QAAQQ;YAAe,MAAMD;QAAY,GAAG;QACjHN,IAAI,IAAI,CAAC,UAAU;YAClB,MAAMQ,kBAAmBH,AAAAA,CAAAA,KAAK,GAAG,KAAKD,SAAQ,IAAK;YACnD,IAAI,CAAC,QAAQ,EAAE,UAAU,iCAAiCI,iBAAiB;gBAAE,WAAW;gBAAO,MAAMF;YAAY;QAClH;QACA,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACP,MAAM;YAClC,IAAI,CAAC,QAAQ,EAAE,QAAQ,6BAA6B,GAAG;gBAAE,WAAW;gBAAO,YAAY;YAAY,GAAG;YACtGC,IAAI,SAAS,CAAC,KAAK;gBAAE,gBAAgB;YAAmB;YACxDA,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;gBAAE,OAAO;YAAkC;YAClE;QACD;QAEA,MAAMC,MAAM,IAAIC,IAAIZ,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,EAAEA,IAAI,OAAO,CAAC,IAAI,EAAE;QAG/D,MAAMa,WAAW,IAAI,CAAC,WAAW,CAACb;QAClC,IAAI,IAAI,CAAC,cAAc,CAACa,WAAW;YAClC,IAAI,CAAC,QAAQ,EAAE,QAAQ,6BAA6B,GAAG;gBAAE,WAAW;gBAAO,YAAY;YAAa,GAAG;YACvGZ,IAAI,SAAS,CAAC,KAAK;gBAClB,gBAAgB;gBAChB,eAAe;YAChB;YACAA,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;gBAAE,OAAO;YAAoB;YACpD;QACD;QAGA,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACV,MAAM;YAClC,IAAI,CAAC,QAAQ,EAAE,QAAQ,6BAA6B,GAAG;gBAAE,WAAW;gBAAO,YAAY;YAAY,GAAG;YACtGC,IAAI,SAAS,CAAC,KAAK;gBAAE,gBAAgB;YAAmB;YACxDA,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;gBAAE,OAAO;YAA6B;YAC7D;QACD;QAGA,IAAI,CAAC,cAAc,CAACT;QAGpB,MAAMa,kBAAkB,IAAI,CAAC,mBAAmB,CAACH;QAGjD,IAAIG,gBAAgB,OAAO,IAAIA,gBAAgB,SAAS,EAAE;YACzD,MAAMC,YAAaD,gBAAgB,OAAO,IAAIA,gBAAgB,SAAS;YACvE,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAACC,YAAY;gBACvC,IAAI,CAAC,QAAQ,EAAE,QAAQ,6BAA6B,GAAG;oBAAE,WAAW;oBAAO,YAAY;gBAAa,GAAG;gBACvGd,IAAI,SAAS,CAAC,KAAK;oBAAE,gBAAgB;gBAAmB;gBACxDA,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;oBAAE,OAAO;gBAA4B;gBAC5D;YACD;QACD;QAEA,IAAI,IAAI,CAAC,WAAW,IAAIV,AAAe,cAAfA,IAAI,MAAM,EAAgB;YACjDC,IAAI,SAAS,CAAC;YACdA,IAAI,GAAG;YACP;QACD;QAGA,IAAIU,IAAI,QAAQ,KAAK,IAAI,CAAC,KAAK,IAAIX,AAAe,UAAfA,IAAI,MAAM,EAAY,YACxD,MAAM,IAAI,CAAC,oBAAoB,CAACA,KAAKC,KAAKa;QAK3C,IAAIH,IAAI,QAAQ,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAIX,AAAe,WAAfA,IAAI,MAAM,EAAa,YACtE,MAAM,IAAI,CAAC,cAAc,CAACA,KAAKC,KAAKa;QAKrC,IAAIH,AAAiB,cAAjBA,IAAI,QAAQ,EAAgB,YAC/B,IAAI,CAAC,kBAAkB,CAACV;QAKzB,IAAIU,AAAiB,aAAjBA,IAAI,QAAQ,EAAe,YAC9B,MAAM,IAAI,CAAC,qBAAqB,CAACV;QAMlCA,IAAI,SAAS,CAAC,KAAK;YAAE,gBAAgB;QAAa;QAClDA,IAAI,GAAG,CAAC;IACT;IAKQ,mBAAmBA,GAAmB,EAAQ;QACrD,MAAMe,aAAsC;YAAE,QAAQ;YAAW,SAAS,IAAI,CAAC,QAAQ,CAAC,IAAI;QAAC;QAC7F,IAAI,IAAI,CAAC,eAAe,EAAE;YACzB,MAAMC,YAAY,IAAI,CAAC,eAAe,CAAC,QAAQ;YAC/CD,WAAW,IAAI,GAAGC;QACnB;QACA,IAAI,IAAI,CAAC,cAAc,EAAE;YACxB,MAAMC,WAAW,IAAI,CAAC,cAAc,CAAC,aAAa;YAClDF,WAAW,QAAQ,GAAGE;QACvB;QACAjB,IAAI,SAAS,CAAC,KAAK;YAAE,gBAAgB;QAAmB;QACxDA,IAAI,GAAG,CAACS,KAAK,SAAS,CAACM;IACxB;IAKA,MAAc,sBAAsBf,GAAmB,EAAiB;QACvE,IAAI,IAAI,CAAC,cAAc,EAAE;YACxB,MAAMkB,YAAY,MAAM,IAAI,CAAC,cAAc,CAAC,cAAc;YAC1D,MAAMC,aAAaD,AAAqB,SAArBA,UAAU,MAAM,GAAY,MAAM;YACrDlB,IAAI,SAAS,CAACmB,YAAY;gBAAE,gBAAgB;YAAmB;YAC/DnB,IAAI,GAAG,CAACS,KAAK,SAAS,CAACS;QACxB,OAAO;YACNlB,IAAI,SAAS,CAAC,KAAK;gBAAE,gBAAgB;YAAmB;YACxDA,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;gBAAE,QAAQ;gBAAM,WAAW,IAAIJ,OAAO,WAAW;gBAAI,YAAY,CAAC;YAAE;QAC5F;IACD;IAKA,MAAc,qBACbN,GAAoB,EACpBC,GAAmB,EACnBoB,MAA8B,EACd;QAEhBpB,IAAI,SAAS,CAAC,KAAK;YAClB,gBAAgB;YAChB,iBAAiB;YACjB,YAAY;QACb;QAGA,IAAIc;QACJ,IAAI,IAAI,CAAC,eAAe,EAAE;YACzB,MAAMO,mBAAmBD,OAAO,OAAO,IAAIA,OAAO,SAAS;YAC3D,IAAIC,oBAAoB,IAAI,CAAC,eAAe,CAAC,cAAc,CAACA,mBAC3DP,YAAYO;iBAEZ,IAAI;gBACHP,YAAY,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa;YACrD,EAAE,OAAOQ,OAAO;gBACftB,IAAI,KAAK,CAAC,CAAC,cAAc,CAAC;gBAC1BA,IAAI,KAAK,CAAC,CAAC,MAAM,EAAES,KAAK,SAAS,CAAC;oBAAE,OAAOa,iBAAiBC,QAAQD,MAAM,OAAO,GAAG;gBAA2B,GAAG,IAAI,CAAC;gBACvHtB,IAAI,GAAG;gBACP;YACD;YAED,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAACA,KAAKc;YAChC,IAAI,CAAC,kBAAkB;QACxB;QAGA,MAAMU,mBAA4C;YAAE,WAAWnB,KAAK,GAAG;QAAG;QAC1E,IAAIS,WACHU,iBAAiB,SAAS,GAAGV;QAE9B,IAAI,CAAC,aAAa,CAACd,KAAK,aAAawB;QAGrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAACxB;QAClB,IAAI,CAAC,8BAA8B;QAGnCD,IAAI,EAAE,CAAC,SAAS;YACf,IAAI,CAAC,QAAQ,CAAC,MAAM,CAACC;YACrB,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAACA;YAC9B,IAAI,CAAC,8BAA8B;QACpC;QAGA,MAAMyB,WAAW,IAAI,CAAC,iBAAiB;QACvC,MAAMC,SAAS,IAAI,CAAC,aAAa,CAAC,GAAG,CAACD;QACtC,IAAIC,QAAQ;YACX,KAAK,MAAMC,WAAWD,OACrB,IAAI,CAAC,aAAa,CAAC1B,KAAK,WAAW2B;YAEpC,IAAI,CAAC,aAAa,CAAC,MAAM,CAACF;QAC3B;IACD;IAKA,MAAc,eACb1B,GAAoB,EACpBC,GAAmB,EACnB4B,OAA+B,EACf;QAChB,IAAIC,OAAO;QAEX,WAAW,MAAMC,SAAS/B,IACzB8B,QAAQC,MAAM,QAAQ;QAGvB,IAAI;YACH,MAAMC,iBAAiBtB,KAAK,KAAK,CAACoB;YAClC,MAAMG,cAAcC,UAAUC,sBAAsBH;YACpD,IAAI,CAACC,YAAY,OAAO,EAAE;gBACzB,IAAI,CAAC,QAAQ,EAAE,QAAQ,6BAA6B,GAAG;oBAAE,WAAW;oBAAO,YAAY;gBAAa,GAAG;gBACvGhC,IAAI,SAAS,CAAC,KAAK;oBAAE,gBAAgB;gBAAmB;gBACxDA,IAAI,GAAG,CACNS,KAAK,SAAS,CAAC;oBACd,SAAS;oBACT,IAAIsB,gBAAgB,MAAM;oBAC1B,OAAO;wBACN,MAAM;wBACN,SAAS;wBACT,MAAMC,YAAY,MAAM;oBACzB;gBACD;gBAED;YACD;YAGA,IAAI,IAAI,CAAC,UAAU,EAAE;gBACpB,MAAMG,WAAW,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAACJ,gBAAgB;oBAC9D,aAAa,CAAC;gBACf;gBACA/B,IAAI,SAAS,CAAC,KAAK;oBAClB,gBAAgB;gBACjB;gBAEA,IAAImC,UACHnC,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC0B;qBAEvBnC,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;oBAAE,SAAS;oBAAO,IAAIsB,gBAAgB,MAAM;oBAAM,QAAQ;gBAAK;YAExF,OAAO;gBACN,IAAI,CAAC,QAAQ,EAAE,QAAQ,6BAA6B,GAAG;oBAAE,WAAW;oBAAO,YAAY;gBAAmB,GAAG;gBAC7G/B,IAAI,SAAS,CAAC,KAAK;oBAAE,gBAAgB;gBAAmB;gBACxDA,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;oBAAE,OAAO;gBAAmB;YACpD;QACD,EAAE,OAAM;YACP,IAAI,CAAC,QAAQ,EAAE,QAAQ,6BAA6B,GAAG;gBAAE,WAAW;gBAAO,YAAY;YAAc,GAAG;YACxGT,IAAI,SAAS,CAAC,KAAK;gBAAE,gBAAgB;YAAmB;YACxDA,IAAI,GAAG,CAACS,KAAK,SAAS,CAAC;gBAAE,OAAO;YAAe;QAChD;IACD;IAKQ,cAAcT,GAAmB,EAAEoC,KAAa,EAAEC,IAAa,EAAQ;QAC9E,IAAI;YACHrC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAEoC,MAAM,EAAE,CAAC;YAC7BpC,IAAI,KAAK,CAAC,CAAC,MAAM,EAAES,KAAK,SAAS,CAAC4B,MAAM,IAAI,CAAC;QAC9C,EAAE,OAAM;YAEP,IAAI,CAAC,QAAQ,CAAC,MAAM,CAACrC;YACrB,IAAI,CAAC,8BAA8B;QACpC;IACD;IAEQ,iCAAuC;QAC9C,IAAI,CAAC,QAAQ,EAAE,MACd,0BACA,IAAI,CAAC,QAAQ,CAAC,IAAI,EAClB,CAAC,GACD;IAEF;IAEQ,qBAA2B;QAClC,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,CAAC,IAAI,CAAC,QAAQ,EAC1C;QAED,MAAMsC,QAAQ,IAAI,CAAC,eAAe,CAAC,QAAQ;QAC3C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAClB,4BACAA,MAAM,cAAc,EACpB,CAAC,GACD;QAED,IAAI,CAAC,QAAQ,CAAC,KAAK,CAClB,2BACAA,MAAM,aAAa,EACnB,CAAC,GACD;QAED,IAAI,CAAC,QAAQ,CAAC,KAAK,CAClB,yBACAA,MAAM,WAAW,EACjB,CAAC,GACD;IAEF;IAKA,UAAUF,KAAa,EAAEC,IAAa,EAAQ;QAC7C,KAAK,MAAME,UAAU,IAAI,CAAC,QAAQ,CACjC,IAAI,CAAC,aAAa,CAACA,QAAQH,OAAOC;IAEpC;IAKQ,oBAA4B;QACnC,OAAO,CAAC,OAAO,EAAEhC,KAAK,GAAG,GAAG,CAAC,EAAEmC,KAAK,MAAM,GAAG,QAAQ,CAAC,IAAI,SAAS,CAAC,GAAG,KAAK;IAC7E;IAKA,IAAI,cAAsB;QACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI;IAC1B;IAKA,IAAI,iBAA6C;QAChD,OAAO,IAAI,CAAC,eAAe;IAC5B;IAQA,MAAM,KAAKC,QAAiB,EAAiB;QAC5C,IAAI,CAAC,eAAe,GAAG;QACvB,IAAI,CAAC,qBAAqB;QAG1B,IAAI,IAAI,CAAC,eAAe,EACvB,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS;QAGrC,OAAO,IAAIvC,QAAQ,CAACC;YAEnB,KAAK,MAAMoC,UAAU,IAAI,CAAC,QAAQ,CACjC,IAAI;gBACHA,OAAO,GAAG;YACX,EAAE,OAAM,CAER;YAED,IAAI,CAAC,QAAQ,CAAC,KAAK;YACnB,IAAI,CAAC,iBAAiB,CAAC,KAAK;YAC5B,IAAI,CAAC,8BAA8B;YAGnC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;gBAClB,IAAI,CAAC,GAAG,CAAC,QAAQ;gBACjBpC;YACD;QACD;IACD;AACD;AAcO,SAASuC,mBAAmB7C,UAA+B,CAAC,CAAC;IACnE,OAAO,IAAIJ,aAAaI;AACzB"}
1
+ {"version":3,"file":"transport/SseTransport.js","sources":["../../src/transport/SseTransport.ts"],"sourcesContent":["/**\n * SSE (Server-Sent Events) Transport implementation.\n *\n * This transport allows multiple concurrent connections over HTTP using Server-Sent Events,\n * enabling multi-user scenarios and horizontal scaling.\n *\n * When a ConnectionPool is provided, each SSE client gets an isolated session with its own\n * thought history. Without a pool, all clients share a single server instance (backward compatible).\n *\n * @example\n * ```typescript\n * const transport = new SseTransport({\n * port: 3000,\n * host: 'localhost'\n * });\n * await transport.connect(server);\n * ```\n */\n\nimport { createServer, IncomingMessage, ServerResponse } from 'node:http';\nimport { randomUUID } from 'node:crypto';\nimport { URL } from 'node:url';\nimport type { McpServer } from 'tmcp';\nimport { safeParse } from 'valibot';\nimport type { IMetrics } from '../contracts/interfaces.js';\nimport type { ConnectionPool } from '../pool/ConnectionPool.js';\nimport { JsonRpcRequestSchema } from '../schema.js';\nimport { BaseTransport, type TransportOptions } from './BaseTransport.js';\nimport type { ITransport, TransportKind } from '../contracts/transport.js';\nimport { runWithContext } from '../context/RequestContext.js';\n/**\n * SSE-specific transport options extending base TransportOptions.\n */\nexport interface SseTransportOptions extends TransportOptions {\n\tpath?: string;\n\tmetrics?: IMetrics;\n\t/**\n\t * Optional connection pool for per-session state isolation.\n\t * When provided, each SSE client gets an isolated thought history.\n\t * When omitted, all clients share a single server instance (backward compatible).\n\t */\n\tconnectionPool?: ConnectionPool;\n}\n\n/**\n * SSE Transport for MCP server over HTTP.\n *\n * This transport uses Server-Sent Events (SSE) to communicate with clients,\n * allowing multiple concurrent connections and web-based clients.\n *\n * @remarks\n * **Security Features:**\n * - Session ID validation (alphanumeric, max 64 chars)\n * - Query parameter sanitization (whitelist allowed keys)\n * - Rate limiting per IP (configurable, default 100 req/min)\n * - CORS origin validation\n *\n * **Rate Limiting:**\n * - Tracks requests per IP address within a time window\n * - Returns 429 Too Many Requests when limit exceeded\n * - Can be disabled via `enableRateLimit: false`\n */\nexport class SseTransport extends BaseTransport implements ITransport {\n\tget kind(): TransportKind { return 'sse'; }\n\tprivate _server: ReturnType<typeof createServer>;\n\tprivate _path: string;\n\tprivate _clients: Set<ServerResponse> = new Set();\n\tprivate _clientSessionMap: Map<ServerResponse, string> = new Map();\n\tprivate _messageQueue: Map<string, unknown[]> = new Map();\n\tprivate _metrics?: IMetrics;\n\tprivate _connectionPool?: ConnectionPool;\n\n\tconstructor(options: SseTransportOptions = {}) {\n\t\tsuper(options);\n\t\tthis._path = options.path ?? '/sse';\n\t\tthis._metrics = options.metrics;\n\t\tthis._connectionPool = options.connectionPool;\n\t\tthis._updateActiveConnectionsMetric();\n\n\t\tthis._server = createServer((req, res) => this._handleRequest(req, res));\n\t}\n\n\t/**\n\t * Connect MCP server to this transport.\n\t *\n\t * @param mcpServer - The MCP server instance\n\t */\n\tasync connect(mcpServer: McpServer): Promise<void> {\n\t\tthis._mcpServer = mcpServer;\n\n\t\treturn new Promise((resolve) => {\n\t\t\tthis._server.listen(this._port, this._host, () => {\n\t\t\t\tthis.log('info', `SSE transport listening on http://${this._host}:${this._port}`);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _mcpServer: McpServer | null = null;\n\n\t/**\n\t * Handle incoming HTTP requests\n\t */\n\tprivate async _handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n\t\tconst startTime = Date.now();\n\t\tconst requestPath = req.url || '/';\n\t\tconst requestMethod = req.method || 'GET';\n\t\tthis._metrics?.counter('http_requests_total', 1, { transport: 'sse', method: requestMethod, path: requestPath }, 'Total HTTP requests');\n\t\tres.once('finish', () => {\n\t\t\tconst durationSeconds = (Date.now() - startTime) / 1000;\n\t\t\tthis._metrics?.histogram('http_request_duration_seconds', durationSeconds, { transport: 'sse', path: requestPath });\n\t\t});\n\t\tif (!this.validateHostHeader(req)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'forbidden' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(403, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Forbidden - invalid host header' }));\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(req.url || '', `http://${req.headers.host}`);\n\n\t\t// Check rate limit first\n\t\tconst clientIp = this.getClientIp(req);\n\t\tif (this.checkRateLimit(clientIp)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'rate_limit' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(429, {\n\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t'Retry-After': '60',\n\t\t\t});\n\t\t\tres.end(JSON.stringify({ error: 'Too many requests' }));\n\t\t\treturn;\n\t\t}\n\n\t\t// Validate CORS origin\n\t\tif (!this.validateCorsOrigin(req)) {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'forbidden' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(403, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Forbidden - invalid origin' }));\n\t\t\treturn;\n\t\t}\n\n\t\t// Set CORS headers\n\t\tthis.setCorsHeaders(res);\n\n\t\t// Sanitize query parameters\n\t\tconst sanitizedParams = this.sanitizeQueryParams(url);\n\n\t\t// Validate session ID if present\n\t\tif (sanitizedParams.session || sanitizedParams.sessionId) {\n\t\t\tconst sessionId = (sanitizedParams.session ?? sanitizedParams.sessionId)!;\n\t\t\tif (!this.validateSessionId(sessionId)) {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'validation' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(JSON.stringify({ error: 'Invalid session ID format' }));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// Handle CORS preflight\n\t\tif (this._enableCors && req.method === 'OPTIONS') {\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle SSE endpoint\n\t\tif (url.pathname === this._path && req.method === 'GET') {\n\t\t\tawait this._handleSseConnection(req, res, sanitizedParams);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle message endpoint (for receiving messages from clients)\n\t\tif (url.pathname === `${this._path}/message` && req.method === 'POST') {\n\t\t\tawait this._handleMessage(req, res, sanitizedParams);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle health check (liveness)\n\t\tif (url.pathname === '/health') {\n\t\t\tthis._handleHealthCheck(res);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle readiness check\n\t\tif (url.pathname === '/ready') {\n\t\t\tawait this._handleReadinessCheck(res);\n\t\t\treturn;\n\t\t}\n\n\n\t\t// 404 for unknown paths\n\t\tres.writeHead(404, { 'Content-Type': 'text/plain' });\n\t\tres.end('Not Found');\n\t}\n\n\t/**\n\t * Handle health check (liveness) endpoint\n\t */\n\tprivate _handleHealthCheck(res: ServerResponse): void {\n\t\tconst healthData: Record<string, unknown> = { status: 'healthy', clients: this._clients.size };\n\t\tif (this._connectionPool) {\n\t\t\tconst poolStats = this._connectionPool.getStats();\n\t\t\thealthData.pool = poolStats;\n\t\t}\n\t\tif (this._healthChecker) {\n\t\t\tconst liveness = this._healthChecker.checkLiveness();\n\t\t\thealthData.liveness = liveness;\n\t\t}\n\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\tres.end(JSON.stringify(healthData));\n\t}\n\n\t/**\n\t * Handle readiness check endpoint\n\t */\n\tprivate async _handleReadinessCheck(res: ServerResponse): Promise<void> {\n\t\tif (this._healthChecker) {\n\t\t\tconst readiness = await this._healthChecker.checkReadiness();\n\t\t\tconst statusCode = readiness.status === 'ok' ? 200 : 503;\n\t\t\tres.writeHead(statusCode, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify(readiness));\n\t\t} else {\n\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ status: 'ok', timestamp: new Date().toISOString(), components: {} }));\n\t\t}\n\t}\n\n\t/**\n\t * Handle new SSE connection\n\t */\n\tprivate async _handleSseConnection(\n\t\treq: IncomingMessage,\n\t\tres: ServerResponse,\n\t\tparams: Record<string, string>\n\t): Promise<void> {\n\t\t// Set SSE headers\n\t\tres.writeHead(200, {\n\t\t\t'Content-Type': 'text/event-stream',\n\t\t\t'Cache-Control': 'no-cache',\n\t\t\tConnection: 'keep-alive',\n\t\t});\n\n\t\t// Resolve session ID when pool is active\n\t\tlet sessionId: string | undefined;\n\t\tif (this._connectionPool) {\n\t\t\tconst requestedSession = params.session ?? params.sessionId;\n\t\t\tif (requestedSession && this._connectionPool.getSessionInfo(requestedSession)) {\n\t\t\t\tsessionId = requestedSession;\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tsessionId = await this._connectionPool.createSession();\n\t\t\t\t} catch (error) {\n\t\t\t\t\tres.write(`event: error\\n`);\n\t\t\t\t\tres.write(`data: ${JSON.stringify({ error: error instanceof Error ? error.message : 'Failed to create session' })}\\n\\n`);\n\t\t\t\t\tres.end();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._clientSessionMap.set(res, sessionId);\n\t\t\tthis._updatePoolMetrics();\n\t\t}\n\n\t\t// Send initial connection event\n\t\tconst connectedPayload: Record<string, unknown> = { timestamp: Date.now() };\n\t\tif (sessionId) {\n\t\t\tconnectedPayload.sessionId = sessionId;\n\t\t}\n\t\tthis._sendSseEvent(res, 'connected', connectedPayload);\n\n\t\t// Add to clients\n\t\tthis._clients.add(res);\n\t\tthis._updateActiveConnectionsMetric();\n\n\t\t// Handle client disconnect\n\t\treq.on('close', () => {\n\t\t\tthis._clients.delete(res);\n\t\t\tthis._clientSessionMap.delete(res);\n\t\t\tthis._updateActiveConnectionsMetric();\n\t\t});\n\n\t\t// Send any queued messages\n\t\tconst clientId = this._generateClientId();\n\t\tconst queued = this._messageQueue.get(clientId);\n\t\tif (queued) {\n\t\t\tfor (const message of queued) {\n\t\t\t\tthis._sendSseEvent(res, 'message', message);\n\t\t\t}\n\t\t\tthis._messageQueue.delete(clientId);\n\t\t}\n\t}\n\n\t/**\n\t * Handle incoming message from client\n\t */\n\tprivate async _handleMessage(\n\t\treq: IncomingMessage,\n\t\tres: ServerResponse,\n\t\t_params: Record<string, string>\n\t): Promise<void> {\n\t\tlet body = '';\n\n\t\tfor await (const chunk of req) {\n\t\t\tbody += chunk.toString();\n\t\t}\n\n\t\ttry {\n\t\t\tconst jsonRpcRequest = JSON.parse(body);\n\t\t\tconst parseResult = safeParse(JsonRpcRequestSchema, jsonRpcRequest);\n\t\t\tif (!parseResult.success) {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'validation' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(200, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(\n\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\t\tid: jsonRpcRequest?.id ?? null,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: -32600,\n\t\t\t\t\t\t\tmessage: 'Invalid Request',\n\t\t\t\t\t\t\tdata: parseResult.issues,\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Process message through MCP server with owner context\n\t\t\tif (this._mcpServer) {\n\t\t\t\tconst sessionId = this._clientSessionMap.get(res);\n\t\t\t\tconst owner = sessionId ?? `sse-${randomUUID()}`;\n\t\t\t\tconst response = await runWithContext(\n\t\t\t\t\t{ requestId: randomUUID(), owner },\n\t\t\t\t\t() => this._mcpServer!.receive(jsonRpcRequest, {\n\t\t\t\t\t\tsessionInfo: {},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tres.writeHead(200, {\n\t\t\t\t\t'Content-Type': 'application/json',\n\t\t\t\t});\n\n\t\t\t\tif (response) {\n\t\t\t\t\tres.end(JSON.stringify(response));\n\t\t\t\t} else {\n\t\t\t\t\tres.end(JSON.stringify({ jsonrpc: '2.0', id: jsonRpcRequest?.id ?? null, result: null }));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'server_not_ready' }, 'Total HTTP request errors');\n\t\t\t\tres.writeHead(503, { 'Content-Type': 'application/json' });\n\t\t\t\tres.end(JSON.stringify({ error: 'Server not ready' }));\n\t\t\t}\n\t\t} catch {\n\t\t\tthis._metrics?.counter('http_request_errors_total', 1, { transport: 'sse', error_type: 'parse_error' }, 'Total HTTP request errors');\n\t\t\tres.writeHead(400, { 'Content-Type': 'application/json' });\n\t\t\tres.end(JSON.stringify({ error: 'Invalid JSON' }));\n\t\t}\n\t}\n\n\t/**\n\t * Send an SSE event to a specific client\n\t */\n\tprivate _sendSseEvent(res: ServerResponse, event: string, data: unknown): void {\n\t\ttry {\n\t\t\tres.write(`event: ${event}\\n`);\n\t\t\tres.write(`data: ${JSON.stringify(data)}\\n\\n`);\n\t\t} catch {\n\t\t\t// Client disconnected\n\t\t\tthis._clients.delete(res);\n\t\t\tthis._updateActiveConnectionsMetric();\n\t\t}\n\t}\n\n\tprivate _updateActiveConnectionsMetric(): void {\n\t\tthis._metrics?.gauge(\n\t\t\t'sse_active_connections',\n\t\t\tthis._clients.size,\n\t\t\t{},\n\t\t\t'Current active SSE connections'\n\t\t);\n\t}\n\n\tprivate _updatePoolMetrics(): void {\n\t\tif (!this._connectionPool || !this._metrics) {\n\t\t\treturn;\n\t\t}\n\t\tconst stats = this._connectionPool.getStats();\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_active_sessions',\n\t\t\tstats.activeSessions,\n\t\t\t{},\n\t\t\t'Active sessions in connection pool'\n\t\t);\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_total_sessions',\n\t\t\tstats.totalSessions,\n\t\t\t{},\n\t\t\t'Total sessions in connection pool'\n\t\t);\n\t\tthis._metrics.gauge(\n\t\t\t'sse_pool_max_sessions',\n\t\t\tstats.maxSessions,\n\t\t\t{},\n\t\t\t'Maximum sessions in connection pool'\n\t\t);\n\t}\n\n\t/**\n\t * Broadcast a message to all connected clients\n\t */\n\tbroadcast(event: string, data: unknown): void {\n\t\tfor (const client of this._clients) {\n\t\t\tthis._sendSseEvent(client, event, data);\n\t\t}\n\t}\n\n\t/**\n\t * Generate a unique client ID\n\t */\n\tprivate _generateClientId(): string {\n\t\treturn `client_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;\n\t}\n\n\t/**\n\t * Get number of connected clients\n\t */\n\tget clientCount(): number {\n\t\treturn this._clients.size;\n\t}\n\n\t/**\n\t * Get the connection pool, if one was configured.\n\t */\n\tget connectionPool(): ConnectionPool | undefined {\n\t\treturn this._connectionPool;\n\t}\n\n\t/**\n\t * Stop the transport server with graceful shutdown.\n\t *\n\t * @param timeout - Maximum time to wait for requests to drain (not used for SSE)\n\t * @returns Promise that resolves when shutdown is complete\n\t */\n\tasync stop(_timeout?: number): Promise<void> {\n\t\tthis._isShuttingDown = true;\n\t\tthis._stopRateLimitCleanup();\n\n\t\t// Terminate connection pool if present\n\t\tif (this._connectionPool) {\n\t\t\tawait this._connectionPool.terminate();\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\t// Close all client connections\n\t\t\tfor (const client of this._clients) {\n\t\t\t\ttry {\n\t\t\t\t\tclient.end();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore errors\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._clients.clear();\n\t\t\tthis._clientSessionMap.clear();\n\t\t\tthis._updateActiveConnectionsMetric();\n\n\t\t\t// Close server\n\t\t\tthis._server.close(() => {\n\t\t\t\tthis.log('info', 'SSE transport stopped');\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n}\n\n/**\n * Create an SSE transport with given options.\n *\n * @param options - Transport configuration\n * @returns A configured SSE transport\n *\n * @example\n * ```typescript\n * const transport = createSseTransport({ port: 3000 });\n * await transport.connect(mcpServer);\n * ```\n */\nexport function createSseTransport(options: SseTransportOptions = {}): SseTransport {\n\treturn new SseTransport(options);\n}\n"],"names":["SseTransport","BaseTransport","Set","Map","options","createServer","req","res","mcpServer","Promise","resolve","startTime","Date","requestPath","requestMethod","durationSeconds","JSON","url","URL","clientIp","sanitizedParams","sessionId","healthData","poolStats","liveness","readiness","statusCode","params","requestedSession","error","Error","connectedPayload","clientId","queued","message","_params","body","chunk","jsonRpcRequest","parseResult","safeParse","JsonRpcRequestSchema","owner","randomUUID","response","runWithContext","event","data","stats","client","Math","_timeout","createSseTransport"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"StreamableHttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/StreamableHttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG3E;;GAEG;AACH,MAAM,WAAW,8BAA+B,SAAQ,gBAAgB;IACvE;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;IAEnB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAElC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,uBAAwB,SAAQ,aAAc,YAAW,UAAU;IAC/E,IAAI,IAAI,IAAI,aAAa,CAA8B;IACvD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,mBAAmB,CAAe;IAC1C,OAAO,CAAC,SAAS,CAAwC;IACzD,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;gBAEpC,OAAO,GAAE,8BAAmC;IAaxD;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAelD;;OAEG;YACW,cAAc;IAoF5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;OAQG;YACW,cAAc;IAsF5B;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAsErB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAmDvB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAS/B;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;;;;;OAMG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAWzE;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;YACW,qBAAqB;IAkBnC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;;;OAIG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAuC3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,GAAE,8BAAmC,GAC1C,uBAAuB,CAEzB"}
1
+ {"version":3,"file":"StreamableHttpTransport.d.ts","sourceRoot":"","sources":["../../src/transport/StreamableHttpTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAG3D,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAI3E;;GAEG;AACH,MAAM,WAAW,8BAA+B,SAAQ,gBAAgB;IACvE;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC;IAEnB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IAE/B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAElC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,uBAAwB,SAAQ,aAAc,YAAW,UAAU;IAC/E,IAAI,IAAI,IAAI,aAAa,CAA8B;IACvD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,mBAAmB,CAAe;IAC1C,OAAO,CAAC,SAAS,CAAwC;IACzD,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,qBAAqB,CAAU;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,gBAAgB,CAAwB;gBAEpC,OAAO,GAAE,8BAAmC;IAaxD;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAelD;;OAEG;YACW,cAAc;IAoF5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;;OAQG;YACW,cAAc;IA2F5B;;;;;;OAMG;IACH,OAAO,CAAC,aAAa;IAsErB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAmDvB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAS/B;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;;;;;OAMG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAWzE;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;OAEG;YACW,qBAAqB;IAkBnC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;;;OAIG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAuC3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAC5C,OAAO,GAAE,8BAAmC,GAC1C,uBAAuB,CAEzB"}
@@ -5,6 +5,7 @@ import { getErrorMessage } from "../errors.js";
5
5
  import { JsonRpcRequestSchema } from "../schema.js";
6
6
  import { BaseTransport } from "./BaseTransport.js";
7
7
  import { readRequestBody } from "./HttpHelpers.js";
8
+ import { runWithContext } from "../context/RequestContext.js";
8
9
  class StreamableHttpTransport extends BaseTransport {
9
10
  get kind() {
10
11
  return 'streamable-http';
@@ -159,9 +160,13 @@ class StreamableHttpTransport extends BaseTransport {
159
160
  this._sendJsonRpcError(res, 503, -32603, 'Server not ready', jsonRpcRequest?.id ?? null);
160
161
  return;
161
162
  }
162
- const response = await this._mcpServer.receive(jsonRpcRequest, {
163
- sessionInfo: {}
164
- });
163
+ const owner = this._stateful ? sessionId ?? randomUUID() : randomUUID();
164
+ const response = await runWithContext({
165
+ requestId: randomUUID(),
166
+ owner
167
+ }, ()=>this._mcpServer.receive(jsonRpcRequest, {
168
+ sessionInfo: {}
169
+ }));
165
170
  clearTimeout(timeout);
166
171
  this._activeRequests--;
167
172
  const responseHeaders = {