@cyanheads/mcp-ts-core 0.11.5 → 0.12.0

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 (357) hide show
  1. package/AGENTS.md +27 -23
  2. package/CLAUDE.md +27 -23
  3. package/README.md +10 -10
  4. package/biome.json +1 -1
  5. package/changelog/0.12.x/0.12.0.md +96 -0
  6. package/dist/cli/init.js +1 -1
  7. package/dist/cli/init.js.map +1 -1
  8. package/dist/config/index.d.ts +0 -18
  9. package/dist/config/index.d.ts.map +1 -1
  10. package/dist/config/index.js +0 -25
  11. package/dist/config/index.js.map +1 -1
  12. package/dist/core/app.d.ts +5 -7
  13. package/dist/core/app.d.ts.map +1 -1
  14. package/dist/core/app.js +18 -27
  15. package/dist/core/app.js.map +1 -1
  16. package/dist/core/context.d.ts +90 -57
  17. package/dist/core/context.d.ts.map +1 -1
  18. package/dist/core/context.js +32 -33
  19. package/dist/core/context.js.map +1 -1
  20. package/dist/core/gcPressure.d.ts.map +1 -1
  21. package/dist/core/gcPressure.js +3 -4
  22. package/dist/core/gcPressure.js.map +1 -1
  23. package/dist/core/index.d.ts +6 -7
  24. package/dist/core/index.d.ts.map +1 -1
  25. package/dist/core/index.js +10 -2
  26. package/dist/core/index.js.map +1 -1
  27. package/dist/core/serverManifest.d.ts +1 -3
  28. package/dist/core/serverManifest.d.ts.map +1 -1
  29. package/dist/core/serverManifest.js +9 -4
  30. package/dist/core/serverManifest.js.map +1 -1
  31. package/dist/core/worker.d.ts.map +1 -1
  32. package/dist/core/worker.js +32 -35
  33. package/dist/core/worker.js.map +1 -1
  34. package/dist/logs/combined.log +10 -22
  35. package/dist/logs/error.log +6 -18
  36. package/dist/mcp-server/inputRequired.d.ts +52 -0
  37. package/dist/mcp-server/inputRequired.d.ts.map +1 -0
  38. package/dist/mcp-server/inputRequired.js +76 -0
  39. package/dist/mcp-server/inputRequired.js.map +1 -0
  40. package/dist/mcp-server/notifications.d.ts +33 -31
  41. package/dist/mcp-server/notifications.d.ts.map +1 -1
  42. package/dist/mcp-server/notifications.js +34 -26
  43. package/dist/mcp-server/notifications.js.map +1 -1
  44. package/dist/mcp-server/prompts/prompt-registration.d.ts +2 -2
  45. package/dist/mcp-server/prompts/prompt-registration.d.ts.map +1 -1
  46. package/dist/mcp-server/prompts/prompt-registration.js +15 -5
  47. package/dist/mcp-server/prompts/prompt-registration.js.map +1 -1
  48. package/dist/mcp-server/prompts/utils/promptDefinition.d.ts +1 -1
  49. package/dist/mcp-server/prompts/utils/promptDefinition.d.ts.map +1 -1
  50. package/dist/mcp-server/resources/resource-registration.d.ts +3 -3
  51. package/dist/mcp-server/resources/resource-registration.d.ts.map +1 -1
  52. package/dist/mcp-server/resources/resource-registration.js +8 -15
  53. package/dist/mcp-server/resources/resource-registration.js.map +1 -1
  54. package/dist/mcp-server/resources/resourceSubscriptions.d.ts +45 -0
  55. package/dist/mcp-server/resources/resourceSubscriptions.d.ts.map +1 -0
  56. package/dist/mcp-server/resources/resourceSubscriptions.js +51 -0
  57. package/dist/mcp-server/resources/resourceSubscriptions.js.map +1 -0
  58. package/dist/mcp-server/resources/utils/resourceDefinition.d.ts +3 -5
  59. package/dist/mcp-server/resources/utils/resourceDefinition.d.ts.map +1 -1
  60. package/dist/mcp-server/resources/utils/resourceDefinition.js +1 -1
  61. package/dist/mcp-server/resources/utils/resourceDefinition.js.map +1 -1
  62. package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts +8 -15
  63. package/dist/mcp-server/resources/utils/resourceHandlerFactory.d.ts.map +1 -1
  64. package/dist/mcp-server/resources/utils/resourceHandlerFactory.js +21 -22
  65. package/dist/mcp-server/resources/utils/resourceHandlerFactory.js.map +1 -1
  66. package/dist/mcp-server/server.d.ts +12 -21
  67. package/dist/mcp-server/server.d.ts.map +1 -1
  68. package/dist/mcp-server/server.js +38 -28
  69. package/dist/mcp-server/server.js.map +1 -1
  70. package/dist/mcp-server/tools/tool-registration.d.ts +11 -33
  71. package/dist/mcp-server/tools/tool-registration.d.ts.map +1 -1
  72. package/dist/mcp-server/tools/tool-registration.js +17 -243
  73. package/dist/mcp-server/tools/tool-registration.js.map +1 -1
  74. package/dist/mcp-server/tools/utils/toolDefinition.d.ts +1 -3
  75. package/dist/mcp-server/tools/utils/toolDefinition.d.ts.map +1 -1
  76. package/dist/mcp-server/tools/utils/toolDefinition.js +48 -1
  77. package/dist/mcp-server/tools/utils/toolDefinition.js.map +1 -1
  78. package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts +46 -20
  79. package/dist/mcp-server/tools/utils/toolHandlerFactory.d.ts.map +1 -1
  80. package/dist/mcp-server/tools/utils/toolHandlerFactory.js +131 -25
  81. package/dist/mcp-server/tools/utils/toolHandlerFactory.js.map +1 -1
  82. package/dist/mcp-server/transports/ITransport.d.ts +2 -2
  83. package/dist/mcp-server/transports/ITransport.d.ts.map +1 -1
  84. package/dist/mcp-server/transports/auth/authFactory.js +1 -1
  85. package/dist/mcp-server/transports/auth/authFactory.js.map +1 -1
  86. package/dist/mcp-server/transports/auth/lib/authTypes.d.ts +1 -1
  87. package/dist/mcp-server/transports/auth/lib/authTypes.d.ts.map +1 -1
  88. package/dist/mcp-server/transports/auth/lib/authUtils.d.ts.map +1 -1
  89. package/dist/mcp-server/transports/auth/lib/authUtils.js +5 -13
  90. package/dist/mcp-server/transports/auth/lib/authUtils.js.map +1 -1
  91. package/dist/mcp-server/transports/auth/strategies/jwtStrategy.js +5 -11
  92. package/dist/mcp-server/transports/auth/strategies/jwtStrategy.js.map +1 -1
  93. package/dist/mcp-server/transports/auth/strategies/oauthStrategy.d.ts.map +1 -1
  94. package/dist/mcp-server/transports/auth/strategies/oauthStrategy.js +9 -22
  95. package/dist/mcp-server/transports/auth/strategies/oauthStrategy.js.map +1 -1
  96. package/dist/mcp-server/transports/heartbeat.d.ts.map +1 -1
  97. package/dist/mcp-server/transports/heartbeat.js +4 -8
  98. package/dist/mcp-server/transports/heartbeat.js.map +1 -1
  99. package/dist/mcp-server/transports/http/httpErrorHandler.d.ts.map +1 -1
  100. package/dist/mcp-server/transports/http/httpErrorHandler.js +6 -24
  101. package/dist/mcp-server/transports/http/httpErrorHandler.js.map +1 -1
  102. package/dist/mcp-server/transports/http/httpServer.d.ts +3 -3
  103. package/dist/mcp-server/transports/http/httpServer.d.ts.map +1 -1
  104. package/dist/mcp-server/transports/http/httpServer.js +15 -32
  105. package/dist/mcp-server/transports/http/httpServer.js.map +1 -1
  106. package/dist/mcp-server/transports/http/httpTransport.d.ts +25 -8
  107. package/dist/mcp-server/transports/http/httpTransport.d.ts.map +1 -1
  108. package/dist/mcp-server/transports/http/httpTransport.js +156 -373
  109. package/dist/mcp-server/transports/http/httpTransport.js.map +1 -1
  110. package/dist/mcp-server/transports/http/landing-page/assets/styles.d.ts.map +1 -1
  111. package/dist/mcp-server/transports/http/landing-page/assets/styles.js +0 -1
  112. package/dist/mcp-server/transports/http/landing-page/assets/styles.js.map +1 -1
  113. package/dist/mcp-server/transports/http/landing-page/handler.d.ts.map +1 -1
  114. package/dist/mcp-server/transports/http/landing-page/handler.js +4 -8
  115. package/dist/mcp-server/transports/http/landing-page/handler.js.map +1 -1
  116. package/dist/mcp-server/transports/http/landing-page/sections/tools.js +0 -2
  117. package/dist/mcp-server/transports/http/landing-page/sections/tools.js.map +1 -1
  118. package/dist/mcp-server/transports/http/protectedResourceMetadata.d.ts.map +1 -1
  119. package/dist/mcp-server/transports/http/protectedResourceMetadata.js +2 -6
  120. package/dist/mcp-server/transports/http/protectedResourceMetadata.js.map +1 -1
  121. package/dist/mcp-server/transports/http/robotsTxt.js +2 -2
  122. package/dist/mcp-server/transports/http/robotsTxt.js.map +1 -1
  123. package/dist/mcp-server/transports/http/serverCard.d.ts.map +1 -1
  124. package/dist/mcp-server/transports/http/serverCard.js +2 -6
  125. package/dist/mcp-server/transports/http/serverCard.js.map +1 -1
  126. package/dist/mcp-server/transports/http/sessionStore.d.ts +46 -66
  127. package/dist/mcp-server/transports/http/sessionStore.d.ts.map +1 -1
  128. package/dist/mcp-server/transports/http/sessionStore.js +140 -238
  129. package/dist/mcp-server/transports/http/sessionStore.js.map +1 -1
  130. package/dist/mcp-server/transports/manager.d.ts +12 -4
  131. package/dist/mcp-server/transports/manager.d.ts.map +1 -1
  132. package/dist/mcp-server/transports/manager.js +35 -33
  133. package/dist/mcp-server/transports/manager.js.map +1 -1
  134. package/dist/mcp-server/transports/stdio/stdioTransport.d.ts +24 -31
  135. package/dist/mcp-server/transports/stdio/stdioTransport.d.ts.map +1 -1
  136. package/dist/mcp-server/transports/stdio/stdioTransport.js +23 -38
  137. package/dist/mcp-server/transports/stdio/stdioTransport.js.map +1 -1
  138. package/dist/mcp-server/types.d.ts +25 -0
  139. package/dist/mcp-server/types.d.ts.map +1 -0
  140. package/dist/mcp-server/types.js +10 -0
  141. package/dist/mcp-server/types.js.map +1 -0
  142. package/dist/services/canvas/core/CanvasInstance.d.ts +2 -2
  143. package/dist/services/canvas/core/CanvasInstance.d.ts.map +1 -1
  144. package/dist/services/canvas/core/CanvasInstance.js.map +1 -1
  145. package/dist/services/canvas/core/CanvasRegistry.d.ts +4 -4
  146. package/dist/services/canvas/core/CanvasRegistry.d.ts.map +1 -1
  147. package/dist/services/canvas/core/CanvasRegistry.js +8 -18
  148. package/dist/services/canvas/core/CanvasRegistry.js.map +1 -1
  149. package/dist/services/canvas/core/DataCanvas.d.ts +5 -5
  150. package/dist/services/canvas/core/DataCanvas.d.ts.map +1 -1
  151. package/dist/services/canvas/core/DataCanvas.js +2 -3
  152. package/dist/services/canvas/core/DataCanvas.js.map +1 -1
  153. package/dist/services/canvas/core/IDataCanvasProvider.d.ts +11 -11
  154. package/dist/services/canvas/core/IDataCanvasProvider.d.ts.map +1 -1
  155. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts +11 -11
  156. package/dist/services/canvas/providers/duckdb/DuckdbProvider.d.ts.map +1 -1
  157. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js +4 -10
  158. package/dist/services/canvas/providers/duckdb/DuckdbProvider.js.map +1 -1
  159. package/dist/services/llm/providers/openrouter.provider.d.ts.map +1 -1
  160. package/dist/services/llm/providers/openrouter.provider.js +2 -5
  161. package/dist/services/llm/providers/openrouter.provider.js.map +1 -1
  162. package/dist/services/mirror/core/defineMirror.js +1 -1
  163. package/dist/services/mirror/core/defineMirror.js.map +1 -1
  164. package/dist/services/mirror/types.d.ts +5 -5
  165. package/dist/services/mirror/types.d.ts.map +1 -1
  166. package/dist/services/speech/providers/elevenlabs.provider.js +1 -1
  167. package/dist/services/speech/providers/elevenlabs.provider.js.map +1 -1
  168. package/dist/services/speech/providers/whisper.provider.js +1 -1
  169. package/dist/services/speech/providers/whisper.provider.js.map +1 -1
  170. package/dist/storage/core/StorageService.d.ts +1 -1
  171. package/dist/storage/core/StorageService.d.ts.map +1 -1
  172. package/dist/storage/core/StorageService.js +12 -20
  173. package/dist/storage/core/StorageService.js.map +1 -1
  174. package/dist/storage/core/storageFactory.d.ts.map +1 -1
  175. package/dist/storage/core/storageFactory.js.map +1 -1
  176. package/dist/storage/core/storageValidation.d.ts +1 -1
  177. package/dist/storage/core/storageValidation.d.ts.map +1 -1
  178. package/dist/storage/core/storageValidation.js +2 -2
  179. package/dist/storage/core/storageValidation.js.map +1 -1
  180. package/dist/storage/providers/cloudflare/d1Provider.d.ts +1 -1
  181. package/dist/storage/providers/cloudflare/d1Provider.d.ts.map +1 -1
  182. package/dist/storage/providers/cloudflare/d1Provider.js +4 -12
  183. package/dist/storage/providers/cloudflare/d1Provider.js.map +1 -1
  184. package/dist/storage/providers/cloudflare/kvProvider.d.ts +1 -1
  185. package/dist/storage/providers/cloudflare/kvProvider.d.ts.map +1 -1
  186. package/dist/storage/providers/cloudflare/kvProvider.js +3 -8
  187. package/dist/storage/providers/cloudflare/kvProvider.js.map +1 -1
  188. package/dist/storage/providers/cloudflare/r2Provider.d.ts +1 -1
  189. package/dist/storage/providers/cloudflare/r2Provider.d.ts.map +1 -1
  190. package/dist/storage/providers/cloudflare/r2Provider.js +3 -8
  191. package/dist/storage/providers/cloudflare/r2Provider.js.map +1 -1
  192. package/dist/storage/providers/inMemory/inMemoryProvider.d.ts +1 -1
  193. package/dist/storage/providers/inMemory/inMemoryProvider.d.ts.map +1 -1
  194. package/dist/storage/providers/inMemory/inMemoryProvider.js +2 -4
  195. package/dist/storage/providers/inMemory/inMemoryProvider.js.map +1 -1
  196. package/dist/testing/index.d.ts +35 -12
  197. package/dist/testing/index.d.ts.map +1 -1
  198. package/dist/testing/index.js +53 -38
  199. package/dist/testing/index.js.map +1 -1
  200. package/dist/testing/vitest.d.ts +1 -1
  201. package/dist/testing/vitest.d.ts.map +1 -1
  202. package/dist/types-global/errors.d.ts +28 -15
  203. package/dist/types-global/errors.d.ts.map +1 -1
  204. package/dist/types-global/errors.js +8 -1
  205. package/dist/types-global/errors.js.map +1 -1
  206. package/dist/utils/formatting/diffFormatter.d.ts +5 -5
  207. package/dist/utils/formatting/diffFormatter.d.ts.map +1 -1
  208. package/dist/utils/formatting/diffFormatter.js +7 -20
  209. package/dist/utils/formatting/diffFormatter.js.map +1 -1
  210. package/dist/utils/formatting/tableFormatter.d.ts +3 -3
  211. package/dist/utils/formatting/tableFormatter.d.ts.map +1 -1
  212. package/dist/utils/formatting/tableFormatter.js +6 -17
  213. package/dist/utils/formatting/tableFormatter.js.map +1 -1
  214. package/dist/utils/formatting/treeFormatter.d.ts +3 -3
  215. package/dist/utils/formatting/treeFormatter.d.ts.map +1 -1
  216. package/dist/utils/formatting/treeFormatter.js +5 -18
  217. package/dist/utils/formatting/treeFormatter.js.map +1 -1
  218. package/dist/utils/index.d.ts +4 -2
  219. package/dist/utils/index.d.ts.map +1 -1
  220. package/dist/utils/index.js +2 -2
  221. package/dist/utils/index.js.map +1 -1
  222. package/dist/utils/internal/error-handler/errorHandler.d.ts +1 -1
  223. package/dist/utils/internal/error-handler/errorHandler.d.ts.map +1 -1
  224. package/dist/utils/internal/error-handler/errorHandler.js +23 -11
  225. package/dist/utils/internal/error-handler/errorHandler.js.map +1 -1
  226. package/dist/utils/internal/error-handler/types.d.ts +10 -13
  227. package/dist/utils/internal/error-handler/types.d.ts.map +1 -1
  228. package/dist/utils/internal/logger.d.ts +3 -3
  229. package/dist/utils/internal/logger.d.ts.map +1 -1
  230. package/dist/utils/internal/logger.js +11 -5
  231. package/dist/utils/internal/logger.js.map +1 -1
  232. package/dist/utils/internal/performance.d.ts +1 -1
  233. package/dist/utils/internal/performance.d.ts.map +1 -1
  234. package/dist/utils/internal/performance.js +57 -13
  235. package/dist/utils/internal/performance.js.map +1 -1
  236. package/dist/utils/internal/requestContext.d.ts +79 -55
  237. package/dist/utils/internal/requestContext.d.ts.map +1 -1
  238. package/dist/utils/internal/requestContext.js +77 -32
  239. package/dist/utils/internal/requestContext.js.map +1 -1
  240. package/dist/utils/metrics/tokenCounter.d.ts +3 -3
  241. package/dist/utils/metrics/tokenCounter.d.ts.map +1 -1
  242. package/dist/utils/metrics/tokenCounter.js.map +1 -1
  243. package/dist/utils/network/fetchWithTimeout.d.ts +2 -2
  244. package/dist/utils/network/fetchWithTimeout.d.ts.map +1 -1
  245. package/dist/utils/network/fetchWithTimeout.js +8 -24
  246. package/dist/utils/network/fetchWithTimeout.js.map +1 -1
  247. package/dist/utils/network/retry.d.ts +2 -2
  248. package/dist/utils/network/retry.d.ts.map +1 -1
  249. package/dist/utils/overflow/outlineOnOverflow.d.ts +1 -1
  250. package/dist/utils/overflow/outlineOnOverflow.d.ts.map +1 -1
  251. package/dist/utils/pagination/pagination.d.ts +3 -3
  252. package/dist/utils/pagination/pagination.d.ts.map +1 -1
  253. package/dist/utils/pagination/pagination.js +3 -3
  254. package/dist/utils/pagination/pagination.js.map +1 -1
  255. package/dist/utils/parsing/csvParser.d.ts +2 -2
  256. package/dist/utils/parsing/csvParser.d.ts.map +1 -1
  257. package/dist/utils/parsing/csvParser.js +4 -8
  258. package/dist/utils/parsing/csvParser.js.map +1 -1
  259. package/dist/utils/parsing/dateParser.d.ts +3 -3
  260. package/dist/utils/parsing/dateParser.d.ts.map +1 -1
  261. package/dist/utils/parsing/dateParser.js +3 -2
  262. package/dist/utils/parsing/dateParser.js.map +1 -1
  263. package/dist/utils/parsing/frontmatterParser.d.ts +2 -2
  264. package/dist/utils/parsing/frontmatterParser.d.ts.map +1 -1
  265. package/dist/utils/parsing/frontmatterParser.js +7 -10
  266. package/dist/utils/parsing/frontmatterParser.js.map +1 -1
  267. package/dist/utils/parsing/htmlExtractor.d.ts +2 -2
  268. package/dist/utils/parsing/htmlExtractor.d.ts.map +1 -1
  269. package/dist/utils/parsing/htmlExtractor.js +6 -11
  270. package/dist/utils/parsing/htmlExtractor.js.map +1 -1
  271. package/dist/utils/parsing/jsonParser.d.ts +2 -2
  272. package/dist/utils/parsing/jsonParser.d.ts.map +1 -1
  273. package/dist/utils/parsing/jsonParser.js +4 -8
  274. package/dist/utils/parsing/jsonParser.js.map +1 -1
  275. package/dist/utils/parsing/pdfParser.d.ts +10 -10
  276. package/dist/utils/parsing/pdfParser.d.ts.map +1 -1
  277. package/dist/utils/parsing/pdfParser.js +26 -89
  278. package/dist/utils/parsing/pdfParser.js.map +1 -1
  279. package/dist/utils/parsing/xmlParser.d.ts +2 -2
  280. package/dist/utils/parsing/xmlParser.d.ts.map +1 -1
  281. package/dist/utils/parsing/xmlParser.js +4 -8
  282. package/dist/utils/parsing/xmlParser.js.map +1 -1
  283. package/dist/utils/parsing/yamlParser.d.ts +2 -2
  284. package/dist/utils/parsing/yamlParser.d.ts.map +1 -1
  285. package/dist/utils/parsing/yamlParser.js +4 -8
  286. package/dist/utils/parsing/yamlParser.js.map +1 -1
  287. package/dist/utils/scheduling/scheduler.d.ts.map +1 -1
  288. package/dist/utils/scheduling/scheduler.js +5 -6
  289. package/dist/utils/scheduling/scheduler.js.map +1 -1
  290. package/dist/utils/security/rateLimiter.d.ts +2 -2
  291. package/dist/utils/security/rateLimiter.d.ts.map +1 -1
  292. package/dist/utils/security/rateLimiter.js +1 -1
  293. package/dist/utils/security/rateLimiter.js.map +1 -1
  294. package/dist/utils/telemetry/attributes.d.ts +23 -7
  295. package/dist/utils/telemetry/attributes.d.ts.map +1 -1
  296. package/dist/utils/telemetry/attributes.js +23 -10
  297. package/dist/utils/telemetry/attributes.js.map +1 -1
  298. package/dist/utils/telemetry/trace.d.ts +3 -3
  299. package/dist/utils/telemetry/trace.d.ts.map +1 -1
  300. package/dist/utils/telemetry/trace.js +4 -2
  301. package/dist/utils/telemetry/trace.js.map +1 -1
  302. package/package.json +22 -26
  303. package/scripts/lint-mcp.ts +1 -3
  304. package/scripts/lint-packaging.ts +1 -1
  305. package/skills/add-service/SKILL.md +2 -2
  306. package/skills/add-test/SKILL.md +42 -20
  307. package/skills/add-tool/SKILL.md +68 -19
  308. package/skills/api-config/SKILL.md +1 -11
  309. package/skills/api-context/SKILL.md +175 -111
  310. package/skills/api-linter/SKILL.md +2 -2
  311. package/skills/api-telemetry/SKILL.md +8 -12
  312. package/skills/api-testing/SKILL.md +53 -52
  313. package/skills/code-simplifier/SKILL.md +2 -2
  314. package/skills/design-mcp-server/SKILL.md +31 -17
  315. package/skills/field-test/SKILL.md +4 -2
  316. package/skills/polish-docs-meta/SKILL.md +1 -1
  317. package/skills/polish-docs-meta/references/agent-protocol.md +2 -2
  318. package/skills/polish-docs-meta/references/readme.md +1 -1
  319. package/skills/release-and-publish/SKILL.md +3 -1
  320. package/skills/report-issue-framework/SKILL.md +2 -2
  321. package/skills/report-issue-local/SKILL.md +2 -2
  322. package/skills/security-pass/SKILL.md +16 -14
  323. package/templates/AGENTS.md +6 -6
  324. package/templates/CLAUDE.md +6 -6
  325. package/templates/tests/resources/echo.resource.test.ts +16 -9
  326. package/dist/mcp-server/elicitation.d.ts +0 -64
  327. package/dist/mcp-server/elicitation.d.ts.map +0 -1
  328. package/dist/mcp-server/elicitation.js +0 -81
  329. package/dist/mcp-server/elicitation.js.map +0 -1
  330. package/dist/mcp-server/protocolSession.d.ts +0 -34
  331. package/dist/mcp-server/protocolSession.d.ts.map +0 -1
  332. package/dist/mcp-server/protocolSession.js +0 -13
  333. package/dist/mcp-server/protocolSession.js.map +0 -1
  334. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.d.ts +0 -53
  335. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.d.ts.map +0 -1
  336. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.js +0 -65
  337. package/dist/mcp-server/tasks/core/evictingTaskMessageQueue.js.map +0 -1
  338. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.d.ts +0 -70
  339. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.d.ts.map +0 -1
  340. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.js +0 -130
  341. package/dist/mcp-server/tasks/core/sessionAwareTaskStore.js.map +0 -1
  342. package/dist/mcp-server/tasks/core/storageBackedTaskStore.d.ts +0 -109
  343. package/dist/mcp-server/tasks/core/storageBackedTaskStore.d.ts.map +0 -1
  344. package/dist/mcp-server/tasks/core/storageBackedTaskStore.js +0 -209
  345. package/dist/mcp-server/tasks/core/storageBackedTaskStore.js.map +0 -1
  346. package/dist/mcp-server/tasks/core/taskManager.d.ts +0 -91
  347. package/dist/mcp-server/tasks/core/taskManager.d.ts.map +0 -1
  348. package/dist/mcp-server/tasks/core/taskManager.js +0 -210
  349. package/dist/mcp-server/tasks/core/taskManager.js.map +0 -1
  350. package/dist/mcp-server/tasks/core/taskTypes.d.ts +0 -18
  351. package/dist/mcp-server/tasks/core/taskTypes.d.ts.map +0 -1
  352. package/dist/mcp-server/tasks/core/taskTypes.js +0 -20
  353. package/dist/mcp-server/tasks/core/taskTypes.js.map +0 -1
  354. package/dist/mcp-server/tasks/utils/taskToolDefinition.d.ts +0 -101
  355. package/dist/mcp-server/tasks/utils/taskToolDefinition.d.ts.map +0 -1
  356. package/dist/mcp-server/tasks/utils/taskToolDefinition.js +0 -14
  357. package/dist/mcp-server/tasks/utils/taskToolDefinition.js.map +0 -1
@@ -1,17 +1,17 @@
1
1
  ---
2
2
  name: api-context
3
3
  description: >
4
- Canonical reference for the unified `Context` object passed to every tool and resource handler in `@cyanheads/mcp-ts-core`. Covers the full interface, all sub-APIs (`ctx.log`, `ctx.state`, `ctx.elicit`, `ctx.progress`, `ctx.enrich`, `ctx.content`), and when to use each.
4
+ Canonical reference for the unified `Context` object passed to every tool and resource handler in `@cyanheads/mcp-ts-core`. Covers the full interface, its `RequestContext` base, all sub-APIs (`ctx.log`, `ctx.state`, `ctx.requestInput`, `ctx.inputs`, `ctx.enrich`, `ctx.content`), and when to use each.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.11"
7
+ version: "2.0"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
11
11
 
12
12
  ## Overview
13
13
 
14
- Every tool and resource handler receives a single `Context` (`ctx`) argument. It provides request identity, structured logging, tenant-scoped storage, optional protocol capabilities (elicitation), cancellation, and task progress — all auto-correlated to the current request.
14
+ Every tool and resource handler receives a single `Context` (`ctx`) argument. It provides request identity, structured logging, tenant-scoped storage, multi-round-trip input collection, and cancellation — all auto-correlated to the current request.
15
15
 
16
16
  The framework auto-instruments every handler call (OTel span, duration, payload metrics). Use `ctx.log` for domain-specific logging and `ctx.state` for storage inside handlers. Use the global `logger` and `StorageService` directly only in lifecycle/background code (`setup()`, services).
17
17
 
@@ -22,8 +22,8 @@ The framework auto-instruments every handler call (OTel span, duration, payload
22
22
  ```ts
23
23
  import type { Context } from '@cyanheads/mcp-ts-core';
24
24
 
25
- interface Context {
26
- // Identity & tracing
25
+ interface Context extends RequestContext {
26
+ // Identity & tracing (inherited from RequestContext — see § RequestContext)
27
27
  readonly requestId: string; // Unique per request, auto-generated
28
28
  readonly timestamp: string; // ISO 8601 request start time
29
29
  readonly tenantId?: string; // JWT 'tid' claim; 'default' for stdio and HTTP+MCP_AUTH_MODE=none
@@ -31,15 +31,19 @@ interface Context {
31
31
  readonly traceId?: string; // OTEL trace ID (present when OTEL enabled)
32
32
  readonly spanId?: string; // OTEL span ID (present when OTEL enabled)
33
33
  readonly auth?: AuthContext; // Parsed auth claims (clientId, scopes, sub)
34
+ readonly operation?: string; // Label for the operation this context belongs to
35
+ readonly extra?: Readonly<Record<string, unknown>>; // Correlation bag — the one open field
34
36
 
35
- // Structured logging — auto-includes requestId, traceId, tenantId
37
+ // Structured logging — auto-includes requestId, traceId, tenantId.
38
+ // Dual-sink: Pino on the server, plus notifications/message to the client.
36
39
  readonly log: ContextLogger;
37
40
 
38
41
  // Tenant-scoped key-value storage
39
42
  readonly state: ContextState;
40
43
 
41
- // Optional protocol capabilities (undefined when client doesn't support them)
42
- readonly elicit?: ElicitFn; // callable (message, schema) for form mode + .url(message, url) — see § ctx.elicit
44
+ // Multi-round-trip input — always present, both eras (see § ctx.requestInput)
45
+ readonly requestInput: RequestInputFn; // (spec) => never — suspends and asks the caller
46
+ readonly inputs: ContextInputs; // reader over a retried request's responses
43
47
 
44
48
  // List-changed / resource-updated notifications — wired in every handler ctx;
45
49
  // delivery is request-scoped (see § list-changed notifications)
@@ -51,9 +55,6 @@ interface Context {
51
55
  // Cancellation
52
56
  readonly signal: AbortSignal;
53
57
 
54
- // Task progress — present only when tool is defined with task: true
55
- readonly progress?: ContextProgress;
56
-
57
58
  // Raw URI — present only for resource handlers
58
59
  readonly uri?: URL;
59
60
 
@@ -91,10 +92,65 @@ interface Context {
91
92
 
92
93
  ---
93
94
 
95
+ ## `RequestContext` — the one canonical request shape
96
+
97
+ `Context extends RequestContext`. There is a single request-shape type; the handler-facing `Context` adds handler-only surfaces (`log`, `state`, `signal`, `requestInput`, `inputs`, `enrich`, `content`, `uri`) on top of it and redeclares none of the identity fields. A handler's `ctx` is therefore assignable anywhere a `RequestContext` is — services, storage, the framework logger — with no slice helper and no cast.
98
+
99
+ ```ts
100
+ import { requestContextService, withExtra } from '@cyanheads/mcp-ts-core/utils';
101
+ import type { RequestContext } from '@cyanheads/mcp-ts-core/utils';
102
+
103
+ // A service typed against RequestContext accepts a handler ctx directly.
104
+ async function fetchUser(id: string, ctx: RequestContext) { /* … */ }
105
+ await fetchUser('123', ctx); // ctx is a Context — no conversion
106
+ ```
107
+
108
+ ### Closed by design
109
+
110
+ `RequestContext` has **no index signature**. Its fields are exactly: `auth`, `extra`, `operation`, `requestId`, `sessionId`, `spanId`, `tenantId`, `timestamp`, `traceId`. A misspelled canonical field (`tenatId`) is a compile error instead of a silently-ignored key.
111
+
112
+ Operation-specific correlation data goes in **`extra`** — the one deliberate open bag (`Readonly<Record<string, unknown>>`). The logger flattens `extra` into the emitted line, so log output looks the same as a top-level spread.
113
+
114
+ ### Adding correlation data
115
+
116
+ Three supported ways, most common first:
117
+
118
+ ```ts
119
+ // 1. Per-log-call metadata — the common case. Nothing lands on the context.
120
+ ctx.log.info('Retrying upstream call', { attempt, url });
121
+
122
+ // 2. A copy of this context carrying extra fields. `withExtra` MERGES into any
123
+ // bag the parent already had; a hand-written `{ ...ctx, extra: {…} }` replaces it.
124
+ logger.warning('Retrying upstream call', withExtra(ctx, { attempt, url }));
125
+
126
+ // 3. A derived context for a sub-operation. `additionalContext` lands on `extra`,
127
+ // merged over whatever the parent already carried.
128
+ const childCtx = requestContextService.createRequestContext({
129
+ parentContext: ctx,
130
+ operation: 'processItem',
131
+ additionalContext: { itemId: item.id }, // → childCtx.extra.itemId
132
+ });
133
+
134
+ // Reading an ad-hoc key back off a context:
135
+ const itemId = childCtx.extra?.itemId;
136
+ ```
137
+
138
+ `createRequestContext(params)` takes a closed parameter object — `additionalContext`, `operation`, `parentContext`, `tenantId` — and nothing else; a key it doesn't declare is a compile error rather than an arbitrary passthrough.
139
+
140
+ Never re-open the shape to get past a type error: no index signature, no widening a parameter back to `Record<string, unknown>`, no `as` cast. A `{ ...ctx, someKey }` object literal that fails to compile is the signal to move `someKey` into `extra`, not to loosen the type.
141
+
142
+ `ErrorContext` (the `ErrorHandler` call's `context`) is `Partial<RequestContext>` and is closed the same way — put ad-hoc keys under `extra` via `withExtra`, or pass them in the `ErrorHandler` call's own `context` field.
143
+
144
+ `RequestContextLike` is a deprecated alias for `RequestContext`, kept for one minor. Replace every use with `RequestContext`, and collapse any `RequestContextLike | RequestContext` parameter union to plain `RequestContext`.
145
+
146
+ ---
147
+
94
148
  ## `ctx.log`
95
149
 
96
150
  Request-scoped structured logger. Every log line is automatically annotated with `requestId`, `traceId`, and `tenantId` — no manual spreading needed.
97
151
 
152
+ **Dual-sink.** Each call writes to Pino *and* mirrors onto the MCP wire as a `notifications/message` (the framework advertises the `logging` capability, and the SDK filters by the level the client set via `logging/setLevel`). The wire payload is `{ message, ...data }`; `ctx.log.error` adds `error: <message>`. Delivery is fire-and-forget — a client that never upgraded to SSE, set a higher level, or already disconnected drops the notification, and a failed send never fails the handler. Treat `ctx.log` as client-visible: it is no longer a server-only sink, so don't log anything there you wouldn't put in a tool result.
153
+
98
154
  ### Methods
99
155
 
100
156
  | Method | Level |
@@ -255,71 +311,120 @@ await ctx.state.set(sessionKey, value);
255
311
  ### Behavior notes
256
312
 
257
313
  - **Not a tenant boundary.** `ctx.state` is still tenant-scoped. Building session-scoped state is the consumer's responsibility — prefix with `session/${ctx.sessionId}/` as shown above.
258
- - **Auto-task tools.** `task: true` handlers run in a detached background context with no session attachment — `ctx.sessionId` is always `undefined` regardless of mode.
314
+ - **Protocol revision.** Sessions belong to the 2025-era arm, which negotiates its revision through `initialize` and carries `Mcp-Session-Id`. The [2026-07-28 revision](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports) has no session at all — it is per-request, selected by the request's own `_meta` envelope — so `ctx.sessionId` is `undefined` for every request served on that leg.
259
315
  - **Worker bundle.** Workers use the same HTTP transport plumbing; session behavior matches Node HTTP.
260
316
 
261
317
  ---
262
318
 
263
- ## `ctx.elicit`
319
+ ## `ctx.requestInput` / `ctx.inputs`
320
+
321
+ Always present, on every transport and both protocol eras. A handler that needs something the caller didn't supply **returns** `ctx.requestInput(...)` and is re-entered with the answers on `ctx.inputs` — there is no mid-handler `await` for user input.
264
322
 
265
- Optional — `undefined` when the connected client doesn't advertise the `elicitation` capability (checked per request, after the initialize handshake). Check for presence before calling. A simple truthiness check is enough; no type guards needed.
323
+ `ctx.requestInput(spec)` never returns: it throws an `InputRequiredSignal` that the tool, resource, and prompt handler factories catch and convert into the protocol's [`input_required`](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/mrtr) result. It bypasses the error classifier entirely — no span, no log, no `isError`.
266
324
 
267
- `ctx.elicit` is an `ElicitFn` (exported from the main entry): directly callable for form-mode elicitation, with a `.url(message, url)` method for URL-mode. On the wire, the Zod schema is converted to the restricted flat JSON Schema the MCP spec requires — handlers never deal with that detail.
325
+ One code path serves both eras. A 2026-07-28 client fulfils the embedded requests and retries the call; for a 2025-era session the SDK's legacy shim fulfils the same returns by issuing real `elicitation/create` / `sampling/createMessage` / `roots/list` round trips and re-entering the handler itself.
268
326
 
269
- ### `ctx.elicit` — ask the user for structured input
327
+ ### The shape of a multi-round-trip handler
270
328
 
271
- Presents a form to the user via the MCP elicitation protocol. The user fills in a Zod-validated schema and returns an action (`accept`, `decline`, or `cancel`).
329
+ Read `ctx.inputs` first, request only what is still missing, and write the call in return position so TypeScript narrows the line below it.
272
330
 
273
331
  ```ts
274
- if (ctx.elicit) {
275
- const result = await ctx.elicit(
276
- 'Which output format do you want?',
277
- z.object({
278
- format: z.enum(['json', 'csv', 'markdown']).describe('Output format'),
279
- includeHeaders: z.boolean().default(true).describe('Include column headers'),
280
- }),
281
- );
282
-
283
- if (result.action === 'accept') {
284
- // result.content is Record<string, string | number | boolean | string[]> | undefined
285
- await produceOutput(result.content?.format as string, result.content?.includeHeaders as boolean);
286
- } else {
287
- // 'decline' or 'cancel' — user opted out
288
- throw invalidRequest('User declined input');
289
- }
290
- }
332
+ import { inputRequired, tool, z } from '@cyanheads/mcp-ts-core';
333
+ import { validationError } from '@cyanheads/mcp-ts-core/errors';
334
+
335
+ const Confirm = z.object({
336
+ confirm: z.boolean().describe('Whether to proceed with the deletion.'),
337
+ });
338
+
339
+ export const deletePath = tool('delete_path', {
340
+ description: 'Delete a path after confirming with the user.',
341
+ input: z.object({ path: z.string().describe('Path to delete') }),
342
+ output: z.object({ deleted: z.string().describe('The path that was deleted') }),
343
+ annotations: { destructiveHint: true },
344
+
345
+ handler(input, ctx) {
346
+ // A declined or cancelled prompt is a dead end, not a round to retry —
347
+ // re-asking loops until the round budget runs out.
348
+ const view = ctx.inputs.view('confirm');
349
+ if (view.kind === 'elicit' && view.action !== 'accept') {
350
+ throw validationError(`User ${view.action} the confirmation.`);
351
+ }
352
+
353
+ const answer = ctx.inputs.accepted('confirm', Confirm);
354
+ if (!answer) {
355
+ return ctx.requestInput({
356
+ inputRequests: {
357
+ confirm: inputRequired.elicit({
358
+ message: `Delete ${input.path}?`,
359
+ requestedSchema: Confirm,
360
+ }),
361
+ },
362
+ });
363
+ }
364
+ // `answer` is narrowed here.
365
+ if (!answer.confirm) throw validationError('Deletion not confirmed.');
366
+
367
+ return { deleted: remove(input.path) };
368
+ },
369
+ });
291
370
  ```
292
371
 
293
- `ElicitResult` (from `@modelcontextprotocol/sdk/types.js`):
372
+ `ctx.requestInput` returns `never`, so `return ctx.requestInput(...)` type-checks against any output type. Calling it as a bare statement works at runtime — and is the only option from a service-layer helper — but TypeScript will not narrow across it.
373
+
374
+ ### Building the embedded requests
375
+
376
+ `inputRequired` is re-exported from the main entry. Its per-kind constructors build the entries of `inputRequests`:
377
+
378
+ | Constructor | Wire request | Notes |
379
+ |:---|:---|:---|
380
+ | `inputRequired.elicit({ message, requestedSchema })` | `elicitation/create` (form) | `requestedSchema` accepts a Zod schema; shapes the restricted elicitation JSON Schema can't express throw a `TypeError` before anything is sent |
381
+ | `inputRequired.elicitUrl({ message, url })` | `elicitation/create` (URL) | Authorization flows, hosted forms. On 2026-07-28 URL mode rides the same multi-round-trip flow; the 2025-era `elicitationId` is not part of that shape — correlate with your own identifier inside `requestState` |
382
+ | `inputRequired.createMessage(params)` | `sampling/createMessage` | Ask the client's model |
383
+ | `inputRequired.listRoots()` | `roots/list` | Ask for the client's filesystem roots |
384
+
385
+ At least one of `inputRequests` or `requestState` must be supplied — the builder throws a `TypeError` otherwise.
386
+
387
+ ### `requestState` — carrying server state across rounds
294
388
 
295
389
  ```ts
296
- // Actual SDK type — a flat object, not a discriminated union
297
- interface ElicitResult {
298
- action: 'accept' | 'decline' | 'cancel';
299
- // Present when action === 'accept'; values are primitives or string arrays
300
- content?: Record<string, string | number | boolean | string[]>;
301
- }
390
+ return ctx.requestInput({
391
+ inputRequests: { confirm: inputRequired.elicit({ message, requestedSchema: Confirm }) },
392
+ requestState: JSON.stringify({ jobId }),
393
+ });
394
+ // Next round:
395
+ const state = ctx.inputs.state<string>();
302
396
  ```
303
397
 
304
- > **Note:** `content` is not typed against the Zod schema you pass — it is a `Record` of primitives. Validate `content` against your schema manually (e.g. `MySchema.parse(result.content)`) when `action === 'accept'`.
398
+ `requestState` round-trips **through the client** and comes back as attacker-controlled input. Integrity-protect (HMAC/AEAD) anything that influences authorization, resource access, or business logic, and reject state that fails verification — the SDK does not do this for you.
399
+
400
+ ### `ctx.inputs` — reading a retried request's responses
401
+
402
+ Empty on the first round; populated on re-entry.
403
+
404
+ | Member | Returns |
405
+ |:---|:---|
406
+ | `accepted(key, schema?)` | The accepted form-mode content for `key`, or `undefined` when the key is missing, the user declined or cancelled, the response was another kind, or (with a schema) validation failed |
407
+ | `view(key)` | Discriminated view of one entry: `{ kind: 'missing' }` \| `{ kind: 'elicit', action, content? }` \| `{ kind: 'sampling', result }` \| `{ kind: 'roots', roots }` |
408
+ | `state<T>()` | This round's `requestState` — verified value, raw wire string when no verifier is configured, or `undefined` on the first round |
409
+ | `dropped` | Keys the SDK dropped because the client sent a wrapped rather than a bare response object. Re-issue those requests instead of hard-failing |
410
+ | `responses` | The raw response map, for kinds the helpers don't cover |
411
+
412
+ Two rules follow from what the SDK does *not* do:
413
+
414
+ - **Responses are never re-validated against the schema the request advertised.** Pass the schema to `accepted(key, schema)` wherever the content matters, and treat every value as untrusted client input.
415
+ - **`undefined` from `accepted()` collapses five different outcomes into one.** Missing, declined, cancelled, wrong response kind, and schema-invalid are indistinguishable through it. Branch on `view(key)` when decline/cancel needs different handling from "not asked yet" — as above, re-issuing a request the user already declined just burns rounds.
305
416
 
306
- ### `ctx.elicit.url` — hand the user an external link
417
+ ### Testing
307
418
 
308
- URL-mode elicitation (MCP 2025-11-25): instead of an inline form, the client directs the user to an external URL — authorization flows, hosted forms. The framework generates the protocol-required `elicitationId` internally.
419
+ `createMockContext({ inputResponses, requestState })` seeds `ctx.inputs`, so a handler can be driven straight into its second round:
309
420
 
310
421
  ```ts
311
- if (ctx.elicit) {
312
- const result = await ctx.elicit.url(
313
- 'Authorize access to your account',
314
- 'https://example.com/oauth/authorize?state=...',
315
- );
316
- if (result.action !== 'accept') throw forbidden('Authorization declined');
317
- }
422
+ const ctx = createMockContext({
423
+ inputResponses: { confirm: { action: 'accept', content: { confirm: true } } },
424
+ });
318
425
  ```
319
426
 
320
- `result.content` is absent in URL mode — the interaction completes out-of-band; only `action` reports the outcome.
321
-
322
- **Convention:** Only call `ctx.elicit` from tool handlers, not from services.
427
+ **Convention:** only call `ctx.requestInput` from tool, resource, and prompt handlers — not from services.
323
428
 
324
429
  ---
325
430
 
@@ -342,15 +447,21 @@ A notification fired **from inside a handler** routes through that request's own
342
447
  | Fired from | stdio | HTTP / Workers |
343
448
  |:-----------|:------|:---------------|
344
449
  | A tool / resource handler | ✅ delivered | ✅ delivered (on the request's SSE response stream) |
345
- | A `task: true` background handler, cron, or any non-request scope | ✅ delivered | ⚠️ dropped — no request scope to route through |
450
+ | A `setup()` hook, cron job, or any non-request scope | ✅ delivered | ⚠️ dropped — no request scope to route through |
451
+
452
+ The background-under-HTTP gap is a known limitation; a session-scoped notification bus would close it.
453
+
454
+ ### `notifyResourceUpdated` is subscription-scoped
346
455
 
347
- The background-under-HTTP gap is a known limitation; a session-scoped notification bus would close it. `notifyResourceUpdated` routes to the calling request, not to clients that subscribed to the URI — the framework tracks no subscription state.
456
+ The framework advertises `resources: { subscribe: true }` and backs it with real `resources/subscribe` / `resources/unsubscribe` handlers, so `notifyResourceUpdated(uri)` emits only for URIs the connected client actually subscribed to; an unsubscribed URI logs at debug and sends nothing. Both handlers are idempotent — re-subscribing is a no-op, and unsubscribing from a URI that was never subscribed succeeds.
457
+
458
+ The registry's scope is the `McpServer` instance, which is also the connection: one persistent instance per session on the 2025-era sessionful arm, one per request under per-request serving. On the per-request leg a subscription cannot outlive the request that created it, so a handler-time `ctx.notifyResourceUpdated(uri)` delivers only when that same exchange subscribed first.
348
459
 
349
460
  ---
350
461
 
351
462
  ## `ctx.signal`
352
463
 
353
- Standard `AbortSignal`. Present on every context. Set when the client cancels the request or when a task tool is cancelled.
464
+ Standard `AbortSignal`. Present on every context. Fires when the client cancels the request — and when the transport closes, which aborts every in-flight handler.
354
465
 
355
466
  ```ts
356
467
  // Check before expensive operations
@@ -366,55 +477,6 @@ for (const item of items) {
366
477
  }
367
478
  ```
368
479
 
369
- In task tools (`task: true`), the framework signals `ctx.signal` when the client sends a cancellation request.
370
-
371
- ---
372
-
373
- ## `ctx.progress`
374
-
375
- Present only when the tool definition includes `task: true`. Undefined for standard (non-task) tools and all resource handlers.
376
-
377
- ### Methods
378
-
379
- | Method | Purpose |
380
- |:-------|:--------|
381
- | `ctx.progress.setTotal(n)` | Set the total number of steps (enables percentage calculation on client) |
382
- | `ctx.progress.increment(amount?)` | Advance progress by `amount` (default: 1) |
383
- | `ctx.progress.update(message)` | Send a descriptive status message without advancing the counter |
384
-
385
- ### Usage
386
-
387
- ```ts
388
- const asyncCountdown = tool('async_countdown', {
389
- description: 'Count down from a number with progress updates.',
390
- task: true,
391
- input: z.object({
392
- count: z.number().int().positive().describe('Number to count down from'),
393
- delayMs: z.number().default(1000).describe('Delay between counts in ms'),
394
- }),
395
- output: z.object({
396
- finalCount: z.number().describe('Final count value'),
397
- message: z.string().describe('Completion message'),
398
- }),
399
-
400
- async handler(input, ctx) {
401
- await ctx.progress!.setTotal(input.count);
402
-
403
- for (let i = input.count; i > 0; i--) {
404
- if (ctx.signal.aborted) break;
405
-
406
- await ctx.progress!.update(`Counting: ${i}`);
407
- await new Promise(resolve => setTimeout(resolve, input.delayMs));
408
- await ctx.progress!.increment();
409
- }
410
-
411
- return { finalCount: 0, message: 'Countdown complete' };
412
- },
413
- });
414
- ```
415
-
416
- **Note:** Use the non-null assertion (`ctx.progress!`) when accessing inside a `task: true` handler — the type is `ContextProgress | undefined` even though it's guaranteed present at runtime. TypeScript cannot narrow based on the `task` flag.
417
-
418
480
  ---
419
481
 
420
482
  ## `ctx.uri`
@@ -548,7 +610,7 @@ The `≥5 words` lint rule on contract `recovery` (validated at lint time) makes
548
610
 
549
611
  ## `ctx.enrich`
550
612
 
551
- Always present on `Context`. Accumulates agent-facing **success-path** context — empty-result notices, the query/filter as the server parsed it, pagination totals — onto the request. The framework merges it into `structuredContent`, advertises `output.extend(enrichment)` as the tool's `outputSchema`, and mirrors it into a `content[]` trailer. The success-path counterpart to `ctx.fail` / `ctx.recoveryFor`.
613
+ Always present on `Context`. Accumulates agent-facing **success-path** context — empty-result notices, the query/filter as the server parsed it, pagination totals — onto the request. The framework merges it into `structuredContent`, folds the `enrichment` block into the tool's advertised `outputSchema`, and mirrors it into a `content[]` trailer. The success-path counterpart to `ctx.fail` / `ctx.recoveryFor`.
552
614
 
553
615
  ```ts
554
616
  export const search = tool('search', {
@@ -698,21 +760,23 @@ Test content blocks with `getContentBlocks(ctx)` from `@cyanheads/mcp-ts-core/te
698
760
  | `ctx.requestId` | `string` | Always |
699
761
  | `ctx.timestamp` | `string` | Always |
700
762
  | `ctx.tenantId` | `string \| undefined` | Stdio (`'default'`); HTTP+`MCP_AUTH_MODE=none` (`'default'`); HTTP+`jwt`/`oauth` (JWT `tid` claim — undefined if absent) |
701
- | `ctx.sessionId` | `string \| undefined` | HTTP `stateful` / `auto` mode; stateless HTTP only when `createApp({ context: { exposeStatelessSessionId: true } })`; never in stdio or auto-task handlers |
763
+ | `ctx.sessionId` | `string \| undefined` | HTTP `stateful` / `auto` mode; stateless HTTP only when `createApp({ context: { exposeStatelessSessionId: true } })`; never in stdio or on the session-less 2026-07-28 leg |
702
764
  | `ctx.traceId` | `string \| undefined` | OTEL enabled |
703
765
  | `ctx.spanId` | `string \| undefined` | OTEL enabled |
704
766
  | `ctx.auth` | `AuthContext \| undefined` | Auth enabled |
767
+ | `ctx.operation` | `string \| undefined` | Set by the context that created it (`'HandleToolRequest'` for tool calls) |
768
+ | `ctx.extra` | `Readonly<Record<string, unknown>> \| undefined` | When correlation data was attached — the one open bag on the closed shape |
705
769
  | `ctx.log` | `ContextLogger` | Always |
706
770
  | `ctx.state` | `ContextState` | Always (throws if `tenantId` missing) |
707
771
  | `ctx.signal` | `AbortSignal` | Always |
708
772
  | `ctx.enrich` | `Enrich` | Always; typed on `HandlerContext<R, E>` when an `enrichment` block is declared |
709
773
  | `ctx.content` | `ContentCollect` | Always — prepends image/audio blocks to `content[]`, never `structuredContent` |
710
- | `ctx.elicit` | `function \| undefined` | Client supports elicitation |
774
+ | `ctx.requestInput` | `(spec) => never` | Always — suspends the handler and asks the caller for more input |
775
+ | `ctx.inputs` | `ContextInputs` | Always; empty until the request is retried with responses |
711
776
  | `ctx.notifyResourceListChanged` | `function \| undefined` | Always in handler ctx; delivery request-scoped (see [§ list-changed notifications](#list-changed-notifications-ctxnotify)) |
712
- | `ctx.notifyResourceUpdated` | `function \| undefined` | Always in handler ctx; delivery request-scoped |
777
+ | `ctx.notifyResourceUpdated` | `function \| undefined` | Always in handler ctx; delivery request-scoped **and** limited to URIs the client subscribed to |
713
778
  | `ctx.notifyPromptListChanged` | `function \| undefined` | Always in handler ctx; delivery request-scoped |
714
779
  | `ctx.notifyToolListChanged` | `function \| undefined` | Always in handler ctx; delivery request-scoped |
715
- | `ctx.progress` | `ContextProgress \| undefined` | Tool defined with `task: true` |
716
780
  | `ctx.uri` | `URL \| undefined` | Resource handlers only |
717
781
  | `ctx.fail` | `(reason, msg?, data?, opts?) => McpError` | Definition declares `errors[]` contract |
718
782
  | `ctx.recoveryFor` | `(reason) => { recovery: { hint } } \| {}` | Always (no-op when no contract); strictly typed on `HandlerContext<R>` |
@@ -4,7 +4,7 @@ description: >
4
4
  MCP definition linter rules reference. Use when `bun run lint:mcp` or `bun run devcheck` reports a lint error or warning (`format-parity`, `schema-is-object`, `name-format`, `server-json-*`, etc.) and you need to understand the rule, its severity, and how to fix it. Every rule ID the linter emits has an entry in this doc.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.9"
7
+ version: "1.10"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
@@ -789,7 +789,7 @@ The diagnostic message includes the declared reason(s) for the code so you can c
789
789
 
790
790
  ## Enrichment rules
791
791
 
792
- Validate the `enrichment` block — the success-path counterpart to `errors[]`. Enrichment fields are merged into `structuredContent` and advertised as `output.extend(enrichment)`, so the linter guards the block's shape and its disjointness from `output`. See `api-context`'s `ctx.enrich` and `add-tool`'s **Tool Response Design**.
792
+ Validate the `enrichment` block — the success-path counterpart to `errors[]`. Enrichment fields are merged into `structuredContent` and folded into the advertised `outputSchema`, so the linter guards the block's shape and its disjointness from `output`. See `api-context`'s `ctx.enrich` and `add-tool`'s **Tool Response Design**.
793
793
 
794
794
  ### enrichment-type
795
795
 
@@ -4,14 +4,14 @@ description: >
4
4
  Catalog of OpenTelemetry instrumentation built into framework `@cyanheads/mcp-ts-core` — spans, metrics, completion logs, env config, runtime caveats, custom instrumentation patterns, and cardinality rules. Use when enabling OTel export, adding custom spans or metrics in services, debugging missing telemetry, looking up attribute names, or deciding what's safe to put on a metric attribute vs. a span.
5
5
  metadata:
6
6
  author: cyanheads
7
- version: "1.2"
7
+ version: "1.4"
8
8
  audience: external
9
9
  type: reference
10
10
  ---
11
11
 
12
12
  ## Overview
13
13
 
14
- The framework auto-instruments every tool, resource, prompt, storage, LLM, speech, and graph call — each gets its own span and the standard counters/histograms. HTTP server requests pick up spans from `HttpInstrumentation` (all Node.js HTTP traffic, skips `/healthz`) plus `httpInstrumentationMiddleware` from `@hono/otel` on the MCP HTTP endpoint when installed (optional Tier 3 peer — `bun add @hono/otel`). On Bun, `HttpInstrumentation` silently no-ops and `@hono/otel` is the only HTTP coverage. Auth checks, session lifecycle, and task lifecycle are tracked as **metrics only** — auth decorates the active HTTP span with attributes, sessions and tasks emit counters.
14
+ The framework auto-instruments every tool, resource, prompt, storage, LLM, speech, and graph call — each gets its own span and the standard counters/histograms. HTTP server requests pick up spans from `HttpInstrumentation` (all Node.js HTTP traffic, skips `/healthz`) plus `httpInstrumentationMiddleware` from `@hono/otel` on the MCP HTTP endpoint when installed (optional Tier 3 peer — `bun add @hono/otel`). On Bun, `HttpInstrumentation` silently no-ops and `@hono/otel` is the only HTTP coverage. Auth checks and session lifecycle are tracked as **metrics only** — auth decorates the active HTTP span with attributes, sessions emit counters.
15
15
 
16
16
  `requestId`, `traceId`, and `tenantId` correlate automatically across spans, metrics, and logs. Pino logs get `trace_id`/`span_id` injected when a span is active.
17
17
 
@@ -61,15 +61,17 @@ Every handler call gets a span. Nested operations (storage, graph, LLM) become c
61
61
 
62
62
  | Span name | Source | Key attributes |
63
63
  |:----------|:-------|:---------------|
64
- | `tool_execution:<tool>` | every tool call | `mcp.tool.input_bytes`, `mcp.tool.output_bytes`, `mcp.tool.duration_ms`, `mcp.tool.success`, `mcp.tool.error_code`, `mcp.tool.partial_success`, `mcp.tool.batch.{succeeded,failed}_count` |
65
- | `resource_read:<resource>` | every resource handler | `mcp.resource.uri`, `mcp.resource.mime_type`, `mcp.resource.size_bytes`, `mcp.resource.duration_ms`, `mcp.resource.success`, `mcp.resource.error_code` |
66
- | `prompt_generation:<prompt>` | every prompt handler | `mcp.prompt.input_bytes`, `mcp.prompt.output_bytes`, `mcp.prompt.message_count`, `mcp.prompt.duration_ms`, `mcp.prompt.success`, `mcp.prompt.error_code` |
64
+ | `tool_execution:<tool>` | every tool call | `mcp.tool.input_bytes`, `mcp.tool.output_bytes`, `mcp.tool.duration_ms`, `mcp.tool.success`, `mcp.tool.error_code`, `mcp.tool.input_required`, `mcp.tool.partial_success`, `mcp.tool.batch.{succeeded,failed}_count` |
65
+ | `resource_read:<resource>` | every resource handler | `mcp.resource.uri`, `mcp.resource.mime_type`, `mcp.resource.size_bytes`, `mcp.resource.duration_ms`, `mcp.resource.success`, `mcp.resource.error_code`, `mcp.resource.input_required` |
66
+ | `prompt_generation:<prompt>` | every prompt handler | `mcp.prompt.input_bytes`, `mcp.prompt.output_bytes`, `mcp.prompt.message_count`, `mcp.prompt.duration_ms`, `mcp.prompt.success`, `mcp.prompt.error_code`, `mcp.prompt.input_required` |
67
67
  | `storage:<op>` | `StorageService` (every call) | `mcp.storage.operation`, `mcp.storage.duration_ms`, `mcp.storage.success`, `mcp.storage.key_count` (batch ops) |
68
68
  | `graph:<op>` | `GraphService` (every call) | `mcp.graph.operation`, `mcp.graph.duration_ms`, `mcp.graph.success` |
69
69
  | `gen_ai.chat_completion` | OpenRouter LLM provider | `gen_ai.system=openrouter`, `gen_ai.request.model`, `gen_ai.request.{max_tokens,temperature,top_p,streaming}`, `gen_ai.response.model`, `gen_ai.usage.{input,output,total}_tokens` |
70
70
  | `speech:tts` | ElevenLabs provider | `mcp.speech.provider`, `mcp.speech.operation`, `mcp.speech.input_bytes`, `mcp.speech.output_bytes`, `mcp.speech.duration_ms`, `mcp.speech.success` |
71
71
  | `speech:stt` | Whisper provider | same as `speech:tts` |
72
72
 
73
+ A handler that ends its round with `ctx.requestInput(...)` closes its span `OK` with `mcp.*.input_required` set — no recorded exception, no error-counter increment. Multi-round-trip input is protocol control flow, so it never inflates error rates; split on that attribute to tell an incomplete round from a completed call.
74
+
73
75
  Trace context propagates across boundaries via W3C `traceparent` headers. See `api-utils` → `telemetry/trace` for `withSpan`, `buildTraceparent`, `extractTraceparent`, `createContextWithParentTrace`, `injectCurrentContextInto`, `runInContext` signatures.
74
76
 
75
77
  ---
@@ -118,7 +120,7 @@ All custom metrics are namespaced `mcp.*` (or `process.*` / `http.client.*` wher
118
120
  | `mcp.graph.duration` | histogram | `ms` | `mcp.graph.operation`, `mcp.graph.success` |
119
121
  | `mcp.graph.errors` | counter | `{errors}` | `mcp.graph.operation` |
120
122
 
121
- ### Transport, auth, sessions, tasks
123
+ ### Transport, auth, sessions
122
124
 
123
125
  | Metric | Type | Unit | Attributes |
124
126
  |:-------|:-----|:-----|:-----------|
@@ -128,12 +130,6 @@ All custom metrics are namespaced `mcp.*` (or `process.*` / `http.client.*` wher
128
130
  | `mcp.session.duration` | histogram | `s` | — |
129
131
  | `mcp.sessions.active` | observable gauge | `{sessions}` | — |
130
132
  | `mcp.heartbeat.failures` | counter | `{failures}` | `mcp.connection.transport` (`stdio`/`http`) |
131
- | `mcp.http.close_failures` | counter | `{failures}` | `surface` (`transport`/`server`), `trigger` (`success`/`error`/`sse-abort`) — per-request close threw or timed out |
132
- | `mcp.http.per_request.created` | counter | `{instances}` | `kind` (`server`/`transport`) — per-request `McpServer` and `McpSessionTransport` instances created |
133
- | `mcp.http.per_request.finalized` | counter | `{instances}` | `kind` (`server`/`transport`) — per-request instances reclaimed by GC; persistent gap vs `created` indicates a leak |
134
- | `mcp.tasks.created` | counter | `{tasks}` | `mcp.task.store_type` (`in-memory`/`storage`) |
135
- | `mcp.tasks.status_changes` | counter | `{transitions}` | `mcp.task.status`, `mcp.task.store_type` |
136
- | `mcp.tasks.active` | observable gauge | `{tasks}` | — (in-memory store only) |
137
133
 
138
134
  ### Errors, rate limits, HTTP client
139
135