effect 4.0.7 → 4.1.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 (679) hide show
  1. package/README.md +1 -1
  2. package/dist/BigDecimal.d.ts.map +1 -1
  3. package/dist/BigDecimal.js +3 -0
  4. package/dist/BigDecimal.js.map +1 -1
  5. package/dist/Channel.d.ts +12 -6
  6. package/dist/Channel.d.ts.map +1 -1
  7. package/dist/Channel.js +9 -3
  8. package/dist/Channel.js.map +1 -1
  9. package/dist/Config.d.ts +7 -1
  10. package/dist/Config.d.ts.map +1 -1
  11. package/dist/Config.js.map +1 -1
  12. package/dist/Context.d.ts +18 -1
  13. package/dist/Context.d.ts.map +1 -1
  14. package/dist/Context.js +27 -8
  15. package/dist/Context.js.map +1 -1
  16. package/dist/Cron.d.ts +81 -11
  17. package/dist/Cron.d.ts.map +1 -1
  18. package/dist/Cron.js +101 -26
  19. package/dist/Cron.js.map +1 -1
  20. package/dist/Duration.d.ts +78 -0
  21. package/dist/Duration.d.ts.map +1 -1
  22. package/dist/Duration.js +123 -0
  23. package/dist/Duration.js.map +1 -1
  24. package/dist/Effect.d.ts +164 -7
  25. package/dist/Effect.d.ts.map +1 -1
  26. package/dist/Effect.js +11 -1
  27. package/dist/Effect.js.map +1 -1
  28. package/dist/FileSystem.d.ts +59 -4
  29. package/dist/FileSystem.d.ts.map +1 -1
  30. package/dist/FileSystem.js +9 -2
  31. package/dist/FileSystem.js.map +1 -1
  32. package/dist/Glob.d.ts +165 -0
  33. package/dist/Glob.d.ts.map +1 -0
  34. package/dist/Glob.js +127 -0
  35. package/dist/Glob.js.map +1 -0
  36. package/dist/Match.d.ts +86 -0
  37. package/dist/Match.d.ts.map +1 -1
  38. package/dist/Match.js +72 -0
  39. package/dist/Match.js.map +1 -1
  40. package/dist/Pool.d.ts +51 -0
  41. package/dist/Pool.d.ts.map +1 -1
  42. package/dist/Pool.js +59 -9
  43. package/dist/Pool.js.map +1 -1
  44. package/dist/Random.d.ts.map +1 -1
  45. package/dist/Random.js +3 -3
  46. package/dist/Random.js.map +1 -1
  47. package/dist/RcMap.d.ts.map +1 -1
  48. package/dist/RcMap.js +8 -2
  49. package/dist/RcMap.js.map +1 -1
  50. package/dist/Schedule.d.ts +18 -1
  51. package/dist/Schedule.d.ts.map +1 -1
  52. package/dist/Schedule.js +7 -2
  53. package/dist/Schedule.js.map +1 -1
  54. package/dist/Schema.d.ts +666 -41
  55. package/dist/Schema.d.ts.map +1 -1
  56. package/dist/Schema.js +650 -0
  57. package/dist/Schema.js.map +1 -1
  58. package/dist/SchemaGetter.d.ts +6 -1
  59. package/dist/SchemaGetter.d.ts.map +1 -1
  60. package/dist/SchemaGetter.js +22 -11
  61. package/dist/SchemaGetter.js.map +1 -1
  62. package/dist/SchemaRepresentation.d.ts +14 -0
  63. package/dist/SchemaRepresentation.d.ts.map +1 -1
  64. package/dist/SchemaRepresentation.js +16 -0
  65. package/dist/SchemaRepresentation.js.map +1 -1
  66. package/dist/SchemaTransformation.d.ts +8 -3
  67. package/dist/SchemaTransformation.d.ts.map +1 -1
  68. package/dist/SchemaTransformation.js +6 -3
  69. package/dist/SchemaTransformation.js.map +1 -1
  70. package/dist/ScopedCache.d.ts.map +1 -1
  71. package/dist/ScopedCache.js +5 -7
  72. package/dist/ScopedCache.js.map +1 -1
  73. package/dist/Semaphore.d.ts +130 -0
  74. package/dist/Semaphore.d.ts.map +1 -1
  75. package/dist/Semaphore.js +40 -0
  76. package/dist/Semaphore.js.map +1 -1
  77. package/dist/Stream.d.ts +13 -4
  78. package/dist/Stream.d.ts.map +1 -1
  79. package/dist/Stream.js +9 -0
  80. package/dist/Stream.js.map +1 -1
  81. package/dist/Terminal.d.ts +18 -1
  82. package/dist/Terminal.d.ts.map +1 -1
  83. package/dist/Terminal.js +1 -1
  84. package/dist/Terminal.js.map +1 -1
  85. package/dist/ai/AiError.d.ts +43 -116
  86. package/dist/ai/AiError.d.ts.map +1 -1
  87. package/dist/ai/AiError.js +53 -72
  88. package/dist/ai/AiError.js.map +1 -1
  89. package/dist/ai/Decision.d.ts +196 -15
  90. package/dist/ai/Decision.d.ts.map +1 -1
  91. package/dist/ai/Decision.js +130 -0
  92. package/dist/ai/Decision.js.map +1 -1
  93. package/dist/ai/DecisionModel.d.ts +54 -13
  94. package/dist/ai/DecisionModel.d.ts.map +1 -1
  95. package/dist/ai/DecisionModel.js +123 -12
  96. package/dist/ai/DecisionModel.js.map +1 -1
  97. package/dist/ai/McpServer.d.ts +630 -29
  98. package/dist/ai/McpServer.d.ts.map +1 -1
  99. package/dist/ai/McpServer.js +562 -116
  100. package/dist/ai/McpServer.js.map +1 -1
  101. package/dist/ai/McpTest.d.ts +130 -0
  102. package/dist/ai/McpTest.d.ts.map +1 -0
  103. package/dist/ai/McpTest.js +237 -0
  104. package/dist/ai/McpTest.js.map +1 -0
  105. package/dist/ai/Response.d.ts +1 -25
  106. package/dist/ai/Response.d.ts.map +1 -1
  107. package/dist/ai/Response.js +1 -10
  108. package/dist/ai/Response.js.map +1 -1
  109. package/dist/ai/Tool.d.ts +19 -1
  110. package/dist/ai/Tool.d.ts.map +1 -1
  111. package/dist/ai/Tool.js.map +1 -1
  112. package/dist/ai/index.d.ts +5 -0
  113. package/dist/ai/index.d.ts.map +1 -1
  114. package/dist/ai/index.js +5 -0
  115. package/dist/ai/index.js.map +1 -1
  116. package/dist/ai/internal/mcpCore.js +17 -12
  117. package/dist/ai/internal/mcpCore.js.map +1 -1
  118. package/dist/ai/internal/mcpProtocol/v2024_11_05.js +4 -5
  119. package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
  120. package/dist/ai/internal/mcpProtocol/v2025_03_26.js +4 -5
  121. package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
  122. package/dist/ai/internal/mcpProtocol/v2025_06_18.js +4 -5
  123. package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
  124. package/dist/ai/internal/mcpProtocol/v2025_11_25.js +4 -5
  125. package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
  126. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +18 -10
  127. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  128. package/dist/ai/internal/mcpProtocol.js +13 -0
  129. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  130. package/dist/ai/internal/mcpRuntime.js +5 -3
  131. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  132. package/dist/ai/internal/mcpStatefulRuntime.js +6 -1
  133. package/dist/ai/internal/mcpStatefulRuntime.js.map +1 -1
  134. package/dist/cli/Argument.d.ts +6 -0
  135. package/dist/cli/Argument.d.ts.map +1 -1
  136. package/dist/cli/Argument.js +2 -0
  137. package/dist/cli/Argument.js.map +1 -1
  138. package/dist/cli/CliOutput.d.ts +65 -1
  139. package/dist/cli/CliOutput.d.ts.map +1 -1
  140. package/dist/cli/CliOutput.js +94 -37
  141. package/dist/cli/CliOutput.js.map +1 -1
  142. package/dist/cli/Command.d.ts +23 -0
  143. package/dist/cli/Command.d.ts.map +1 -1
  144. package/dist/cli/Command.js +8 -0
  145. package/dist/cli/Command.js.map +1 -1
  146. package/dist/cli/Flag.d.ts +107 -0
  147. package/dist/cli/Flag.d.ts.map +1 -1
  148. package/dist/cli/Flag.js +37 -0
  149. package/dist/cli/Flag.js.map +1 -1
  150. package/dist/cli/HelpDoc.d.ts +15 -1
  151. package/dist/cli/HelpDoc.d.ts.map +1 -1
  152. package/dist/cli/Param.d.ts +6 -0
  153. package/dist/cli/Param.d.ts.map +1 -1
  154. package/dist/cli/Param.js +2 -0
  155. package/dist/cli/Param.js.map +1 -1
  156. package/dist/cli/Primitive.d.ts +14 -0
  157. package/dist/cli/Primitive.d.ts.map +1 -1
  158. package/dist/cli/Primitive.js +15 -1
  159. package/dist/cli/Primitive.js.map +1 -1
  160. package/dist/cli/Prompt.d.ts +1 -0
  161. package/dist/cli/Prompt.d.ts.map +1 -1
  162. package/dist/cli/Prompt.js +1 -0
  163. package/dist/cli/Prompt.js.map +1 -1
  164. package/dist/cli/internal/help.d.ts.map +1 -1
  165. package/dist/cli/internal/help.js +17 -10
  166. package/dist/cli/internal/help.js.map +1 -1
  167. package/dist/cluster/Sharding.d.ts.map +1 -1
  168. package/dist/cluster/Sharding.js +90 -28
  169. package/dist/cluster/Sharding.js.map +1 -1
  170. package/dist/cluster/ShardingConfig.d.ts +72 -6
  171. package/dist/cluster/ShardingConfig.d.ts.map +1 -1
  172. package/dist/cluster/ShardingConfig.js +4 -0
  173. package/dist/cluster/ShardingConfig.js.map +1 -1
  174. package/dist/cluster/SingleRunner.d.ts +3 -3
  175. package/dist/cluster/SingleRunner.d.ts.map +1 -1
  176. package/dist/cluster/SingleRunner.js +1 -1
  177. package/dist/cluster/SqlMessageStorage.d.ts +37 -6
  178. package/dist/cluster/SqlMessageStorage.d.ts.map +1 -1
  179. package/dist/cluster/SqlMessageStorage.js +34 -7
  180. package/dist/cluster/SqlMessageStorage.js.map +1 -1
  181. package/dist/cluster/SqlRunnerStorage.d.ts.map +1 -1
  182. package/dist/cluster/SqlRunnerStorage.js +23 -8
  183. package/dist/cluster/SqlRunnerStorage.js.map +1 -1
  184. package/dist/crypto/Aead.d.ts +322 -0
  185. package/dist/crypto/Aead.d.ts.map +1 -0
  186. package/dist/crypto/Aead.js +331 -0
  187. package/dist/crypto/Aead.js.map +1 -0
  188. package/dist/crypto/Cipher.d.ts +235 -0
  189. package/dist/crypto/Cipher.d.ts.map +1 -0
  190. package/dist/crypto/Cipher.js +233 -0
  191. package/dist/crypto/Cipher.js.map +1 -0
  192. package/dist/crypto/CryptoError.d.ts +212 -0
  193. package/dist/crypto/CryptoError.d.ts.map +1 -0
  194. package/dist/crypto/CryptoError.js +202 -0
  195. package/dist/crypto/CryptoError.js.map +1 -0
  196. package/dist/crypto/Digest.d.ts +143 -0
  197. package/dist/crypto/Digest.d.ts.map +1 -0
  198. package/dist/crypto/Digest.js +146 -0
  199. package/dist/crypto/Digest.js.map +1 -0
  200. package/dist/crypto/Kdf.d.ts +220 -0
  201. package/dist/crypto/Kdf.d.ts.map +1 -0
  202. package/dist/crypto/Kdf.js +212 -0
  203. package/dist/crypto/Kdf.js.map +1 -0
  204. package/dist/crypto/KeyAgreement.d.ts +323 -0
  205. package/dist/crypto/KeyAgreement.d.ts.map +1 -0
  206. package/dist/crypto/KeyAgreement.js +303 -0
  207. package/dist/crypto/KeyAgreement.js.map +1 -0
  208. package/dist/crypto/KeyFormat.d.ts +309 -0
  209. package/dist/crypto/KeyFormat.d.ts.map +1 -0
  210. package/dist/crypto/KeyFormat.js +556 -0
  211. package/dist/crypto/KeyFormat.js.map +1 -0
  212. package/dist/crypto/KeyWrap.d.ts +389 -0
  213. package/dist/crypto/KeyWrap.d.ts.map +1 -0
  214. package/dist/crypto/KeyWrap.js +381 -0
  215. package/dist/crypto/KeyWrap.js.map +1 -0
  216. package/dist/crypto/Mac.d.ts +277 -0
  217. package/dist/crypto/Mac.d.ts.map +1 -0
  218. package/dist/crypto/Mac.js +288 -0
  219. package/dist/crypto/Mac.js.map +1 -0
  220. package/dist/crypto/SecureRandom.d.ts +340 -0
  221. package/dist/crypto/SecureRandom.d.ts.map +1 -0
  222. package/dist/crypto/SecureRandom.js +257 -0
  223. package/dist/crypto/SecureRandom.js.map +1 -0
  224. package/dist/crypto/Signature.d.ts +448 -0
  225. package/dist/crypto/Signature.d.ts.map +1 -0
  226. package/dist/crypto/Signature.js +484 -0
  227. package/dist/crypto/Signature.js.map +1 -0
  228. package/dist/crypto/WebCrypto.d.ts +61 -0
  229. package/dist/crypto/WebCrypto.d.ts.map +1 -0
  230. package/dist/crypto/WebCrypto.js +63 -0
  231. package/dist/crypto/WebCrypto.js.map +1 -0
  232. package/dist/crypto/index.d.ts +65 -0
  233. package/dist/crypto/index.d.ts.map +1 -0
  234. package/dist/crypto/index.js +66 -0
  235. package/dist/crypto/index.js.map +1 -0
  236. package/dist/crypto/internal/asymmetric.d.ts +2 -0
  237. package/dist/crypto/internal/asymmetric.d.ts.map +1 -0
  238. package/dist/crypto/internal/asymmetric.js +210 -0
  239. package/dist/crypto/internal/asymmetric.js.map +1 -0
  240. package/dist/crypto/internal/chacha.d.ts +46 -0
  241. package/dist/crypto/internal/chacha.d.ts.map +1 -0
  242. package/dist/crypto/internal/chacha.js +885 -0
  243. package/dist/crypto/internal/chacha.js.map +1 -0
  244. package/dist/crypto/internal/der.d.ts +6 -0
  245. package/dist/crypto/internal/der.d.ts.map +1 -0
  246. package/dist/crypto/internal/der.js +86 -0
  247. package/dist/crypto/internal/der.js.map +1 -0
  248. package/dist/crypto/internal/digest.d.ts +2 -0
  249. package/dist/crypto/internal/digest.d.ts.map +1 -0
  250. package/dist/crypto/internal/digest.js +15 -0
  251. package/dist/crypto/internal/digest.js.map +1 -0
  252. package/dist/crypto/internal/key.d.ts +2 -0
  253. package/dist/crypto/internal/key.d.ts.map +1 -0
  254. package/dist/crypto/internal/key.js +170 -0
  255. package/dist/crypto/internal/key.js.map +1 -0
  256. package/dist/crypto/internal/md5.d.ts +39 -0
  257. package/dist/crypto/internal/md5.d.ts.map +1 -0
  258. package/dist/crypto/internal/md5.js +179 -0
  259. package/dist/crypto/internal/md5.js.map +1 -0
  260. package/dist/crypto/internal/webCrypto.d.ts +2 -0
  261. package/dist/crypto/internal/webCrypto.d.ts.map +1 -0
  262. package/dist/crypto/internal/webCrypto.js +111 -0
  263. package/dist/crypto/internal/webCrypto.js.map +1 -0
  264. package/dist/encoding/Base64Url.d.ts.map +1 -1
  265. package/dist/encoding/Base64Url.js +3 -2
  266. package/dist/encoding/Base64Url.js.map +1 -1
  267. package/dist/encoding/Csv.d.ts +608 -0
  268. package/dist/encoding/Csv.d.ts.map +1 -0
  269. package/dist/encoding/Csv.js +718 -0
  270. package/dist/encoding/Csv.js.map +1 -0
  271. package/dist/encoding/Hex.d.ts +3 -2
  272. package/dist/encoding/Hex.d.ts.map +1 -1
  273. package/dist/encoding/Hex.js +3 -2
  274. package/dist/encoding/Hex.js.map +1 -1
  275. package/dist/encoding/SchemaBinary.d.ts.map +1 -1
  276. package/dist/encoding/SchemaBinary.js +42 -4
  277. package/dist/encoding/SchemaBinary.js.map +1 -1
  278. package/dist/encoding/Toml.d.ts +17 -3
  279. package/dist/encoding/Toml.d.ts.map +1 -1
  280. package/dist/encoding/Toml.js +104 -16
  281. package/dist/encoding/Toml.js.map +1 -1
  282. package/dist/encoding/Yaml.d.ts +8 -1
  283. package/dist/encoding/Yaml.d.ts.map +1 -1
  284. package/dist/encoding/Yaml.js +54 -18
  285. package/dist/encoding/Yaml.js.map +1 -1
  286. package/dist/encoding/index.d.ts +5 -0
  287. package/dist/encoding/index.d.ts.map +1 -1
  288. package/dist/encoding/index.js +5 -0
  289. package/dist/encoding/index.js.map +1 -1
  290. package/dist/eventlog/EventJournal.d.ts.map +1 -1
  291. package/dist/eventlog/EventJournal.js +6 -3
  292. package/dist/eventlog/EventJournal.js.map +1 -1
  293. package/dist/eventlog/EventLog.d.ts +119 -4
  294. package/dist/eventlog/EventLog.d.ts.map +1 -1
  295. package/dist/eventlog/EventLog.js +200 -12
  296. package/dist/eventlog/EventLog.js.map +1 -1
  297. package/dist/eventlog/EventLogEncryption.d.ts +41 -4
  298. package/dist/eventlog/EventLogEncryption.d.ts.map +1 -1
  299. package/dist/eventlog/EventLogEncryption.js +83 -64
  300. package/dist/eventlog/EventLogEncryption.js.map +1 -1
  301. package/dist/eventlog/EventLogMessage.d.ts +279 -0
  302. package/dist/eventlog/EventLogMessage.d.ts.map +1 -1
  303. package/dist/eventlog/EventLogMessage.js +217 -1
  304. package/dist/eventlog/EventLogMessage.js.map +1 -1
  305. package/dist/eventlog/EventLogRemote.d.ts +200 -28
  306. package/dist/eventlog/EventLogRemote.d.ts.map +1 -1
  307. package/dist/eventlog/EventLogRemote.js +186 -16
  308. package/dist/eventlog/EventLogRemote.js.map +1 -1
  309. package/dist/eventlog/EventLogServer.d.ts +3 -0
  310. package/dist/eventlog/EventLogServer.d.ts.map +1 -1
  311. package/dist/eventlog/EventLogServer.js +18 -10
  312. package/dist/eventlog/EventLogServer.js.map +1 -1
  313. package/dist/eventlog/EventLogServerEncrypted.d.ts +326 -5
  314. package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
  315. package/dist/eventlog/EventLogServerEncrypted.js +769 -14
  316. package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
  317. package/dist/eventlog/EventLogSessionAuth.d.ts +5 -3
  318. package/dist/eventlog/EventLogSessionAuth.d.ts.map +1 -1
  319. package/dist/eventlog/EventLogSessionAuth.js +41 -64
  320. package/dist/eventlog/EventLogSessionAuth.js.map +1 -1
  321. package/dist/eventlog/EventRow.d.ts +4 -0
  322. package/dist/eventlog/EventRow.d.ts.map +1 -1
  323. package/dist/eventlog/EventRow.js +12 -2
  324. package/dist/eventlog/EventRow.js.map +1 -1
  325. package/dist/eventlog/SqlEventJournal.js +2 -2
  326. package/dist/eventlog/SqlEventJournal.js.map +1 -1
  327. package/dist/eventlog/SqlEventLogServerEncrypted.d.ts +21 -5
  328. package/dist/eventlog/SqlEventLogServerEncrypted.d.ts.map +1 -1
  329. package/dist/eventlog/SqlEventLogServerEncrypted.js +1048 -113
  330. package/dist/eventlog/SqlEventLogServerEncrypted.js.map +1 -1
  331. package/dist/eventlog/SqlEventLogServerUnencrypted.js +2 -2
  332. package/dist/eventlog/SqlEventLogServerUnencrypted.js.map +1 -1
  333. package/dist/eventlog/internal/batches.d.ts +12 -0
  334. package/dist/eventlog/internal/batches.d.ts.map +1 -0
  335. package/dist/eventlog/internal/batches.js +26 -0
  336. package/dist/eventlog/internal/batches.js.map +1 -0
  337. package/dist/eventlog/internal/compaction.d.ts +38 -0
  338. package/dist/eventlog/internal/compaction.d.ts.map +1 -0
  339. package/dist/eventlog/internal/compaction.js +33 -0
  340. package/dist/eventlog/internal/compaction.js.map +1 -0
  341. package/dist/eventlog/internal/identityRootSecretDerivation.js +66 -67
  342. package/dist/eventlog/internal/identityRootSecretDerivation.js.map +1 -1
  343. package/dist/eventlog/internal/remoteCompaction.d.ts +31 -0
  344. package/dist/eventlog/internal/remoteCompaction.d.ts.map +1 -0
  345. package/dist/eventlog/internal/remoteCompaction.js +76 -0
  346. package/dist/eventlog/internal/remoteCompaction.js.map +1 -0
  347. package/dist/http/Cookies.d.ts +172 -0
  348. package/dist/http/Cookies.d.ts.map +1 -1
  349. package/dist/http/Cookies.js +143 -1
  350. package/dist/http/Cookies.js.map +1 -1
  351. package/dist/http/FetchHttpClient.d.ts +26 -2
  352. package/dist/http/FetchHttpClient.d.ts.map +1 -1
  353. package/dist/http/FetchHttpClient.js +78 -15
  354. package/dist/http/FetchHttpClient.js.map +1 -1
  355. package/dist/http/HttpClient.d.ts +79 -8
  356. package/dist/http/HttpClient.d.ts.map +1 -1
  357. package/dist/http/HttpClient.js +65 -5
  358. package/dist/http/HttpClient.js.map +1 -1
  359. package/dist/http/HttpClientRequest.d.ts +9 -5
  360. package/dist/http/HttpClientRequest.d.ts.map +1 -1
  361. package/dist/http/HttpClientRequest.js +2 -3
  362. package/dist/http/HttpClientRequest.js.map +1 -1
  363. package/dist/http/HttpClientResponse.d.ts.map +1 -1
  364. package/dist/http/HttpClientResponse.js +3 -2
  365. package/dist/http/HttpClientResponse.js.map +1 -1
  366. package/dist/http/HttpMethod.d.ts +7 -1
  367. package/dist/http/HttpMethod.d.ts.map +1 -1
  368. package/dist/http/HttpMethod.js +3 -8
  369. package/dist/http/HttpMethod.js.map +1 -1
  370. package/dist/http/HttpServerRequest.d.ts +5 -2
  371. package/dist/http/HttpServerRequest.d.ts.map +1 -1
  372. package/dist/http/HttpServerRequest.js +6 -17
  373. package/dist/http/HttpServerRequest.js.map +1 -1
  374. package/dist/http/HttpServerResponse.d.ts.map +1 -1
  375. package/dist/http/HttpServerResponse.js +3 -2
  376. package/dist/http/HttpServerResponse.js.map +1 -1
  377. package/dist/http/HttpTraceContext.d.ts +2 -1
  378. package/dist/http/HttpTraceContext.d.ts.map +1 -1
  379. package/dist/http/HttpTraceContext.js +7 -5
  380. package/dist/http/HttpTraceContext.js.map +1 -1
  381. package/dist/http/ProblemDetails.d.ts +96 -0
  382. package/dist/http/ProblemDetails.d.ts.map +1 -0
  383. package/dist/http/ProblemDetails.js +98 -0
  384. package/dist/http/ProblemDetails.js.map +1 -0
  385. package/dist/http/index.d.ts +5 -0
  386. package/dist/http/index.d.ts.map +1 -1
  387. package/dist/http/index.js +5 -0
  388. package/dist/http/index.js.map +1 -1
  389. package/dist/http/internal/decompression.js +3 -2
  390. package/dist/http/internal/decompression.js.map +1 -1
  391. package/dist/http/internal/urlParams.js +8 -0
  392. package/dist/http/internal/urlParams.js.map +1 -1
  393. package/dist/http-api/HttpApiBuilder.js +19 -5
  394. package/dist/http-api/HttpApiBuilder.js.map +1 -1
  395. package/dist/http-api/HttpApiClient.d.ts +63 -0
  396. package/dist/http-api/HttpApiClient.d.ts.map +1 -1
  397. package/dist/http-api/HttpApiClient.js +51 -0
  398. package/dist/http-api/HttpApiClient.js.map +1 -1
  399. package/dist/http-api/HttpApiEndpoint.d.ts.map +1 -1
  400. package/dist/http-api/HttpApiEndpoint.js +14 -5
  401. package/dist/http-api/HttpApiEndpoint.js.map +1 -1
  402. package/dist/http-api/HttpApiError.d.ts +185 -13
  403. package/dist/http-api/HttpApiError.d.ts.map +1 -1
  404. package/dist/http-api/HttpApiError.js +128 -0
  405. package/dist/http-api/HttpApiError.js.map +1 -1
  406. package/dist/http-api/HttpApiMiddleware.d.ts +64 -17
  407. package/dist/http-api/HttpApiMiddleware.d.ts.map +1 -1
  408. package/dist/http-api/HttpApiMiddleware.js +85 -1
  409. package/dist/http-api/HttpApiMiddleware.js.map +1 -1
  410. package/dist/http-api/HttpApiSchema.d.ts +76 -14
  411. package/dist/http-api/HttpApiSchema.d.ts.map +1 -1
  412. package/dist/http-api/HttpApiSchema.js +53 -0
  413. package/dist/http-api/HttpApiSchema.js.map +1 -1
  414. package/dist/index.d.ts +5 -5
  415. package/dist/index.d.ts.map +1 -1
  416. package/dist/index.js +5 -5
  417. package/dist/index.js.map +1 -1
  418. package/dist/internal/effect.js +25 -14
  419. package/dist/internal/effect.js.map +1 -1
  420. package/dist/internal/glob.d.ts +2 -0
  421. package/dist/internal/glob.d.ts.map +1 -0
  422. package/dist/internal/glob.js +630 -0
  423. package/dist/internal/glob.js.map +1 -0
  424. package/dist/internal/matcher.js +10 -0
  425. package/dist/internal/matcher.js.map +1 -1
  426. package/dist/internal/persistence.js +9 -0
  427. package/dist/internal/persistence.js.map +1 -1
  428. package/dist/internal/rcRef.js +4 -1
  429. package/dist/internal/rcRef.js.map +1 -1
  430. package/dist/internal/schema/toCodeDocument.js +6 -3
  431. package/dist/internal/schema/toCodeDocument.js.map +1 -1
  432. package/dist/internal/trie.js +42 -13
  433. package/dist/internal/trie.js.map +1 -1
  434. package/dist/internal/ulid.js +41 -0
  435. package/dist/internal/ulid.js.map +1 -1
  436. package/dist/internal/uuid.js +52 -8
  437. package/dist/internal/uuid.js.map +1 -1
  438. package/dist/internal/version.js +1 -1
  439. package/dist/observability/Otlp.d.ts +15 -4
  440. package/dist/observability/Otlp.d.ts.map +1 -1
  441. package/dist/observability/Otlp.js +10 -0
  442. package/dist/observability/Otlp.js.map +1 -1
  443. package/dist/observability/OtlpResource.d.ts +7 -0
  444. package/dist/observability/OtlpResource.d.ts.map +1 -1
  445. package/dist/observability/OtlpResource.js +11 -1
  446. package/dist/observability/OtlpResource.js.map +1 -1
  447. package/dist/persistence/KeyValueStore.d.ts +47 -2
  448. package/dist/persistence/KeyValueStore.d.ts.map +1 -1
  449. package/dist/persistence/KeyValueStore.js +129 -18
  450. package/dist/persistence/KeyValueStore.js.map +1 -1
  451. package/dist/persistence/PersistedQueue.d.ts +9 -0
  452. package/dist/persistence/PersistedQueue.d.ts.map +1 -1
  453. package/dist/persistence/PersistedQueue.js +94 -52
  454. package/dist/persistence/PersistedQueue.js.map +1 -1
  455. package/dist/persistence/Persistence.d.ts +10 -4
  456. package/dist/persistence/Persistence.d.ts.map +1 -1
  457. package/dist/persistence/Persistence.js +18 -11
  458. package/dist/persistence/Persistence.js.map +1 -1
  459. package/dist/process/ChildProcess.d.ts +207 -67
  460. package/dist/process/ChildProcess.d.ts.map +1 -1
  461. package/dist/process/ChildProcess.js +56 -158
  462. package/dist/process/ChildProcess.js.map +1 -1
  463. package/dist/process/ChildProcessSpawner.d.ts +5 -0
  464. package/dist/process/ChildProcessSpawner.d.ts.map +1 -1
  465. package/dist/process/ChildProcessSpawner.js.map +1 -1
  466. package/dist/process/CommandLine.d.ts +294 -0
  467. package/dist/process/CommandLine.d.ts.map +1 -0
  468. package/dist/process/CommandLine.js +481 -0
  469. package/dist/process/CommandLine.js.map +1 -0
  470. package/dist/process/index.d.ts +5 -0
  471. package/dist/process/index.d.ts.map +1 -1
  472. package/dist/process/index.js +5 -0
  473. package/dist/process/index.js.map +1 -1
  474. package/dist/reactivity/Atom.d.ts +2 -1
  475. package/dist/reactivity/Atom.d.ts.map +1 -1
  476. package/dist/reactivity/Atom.js +3 -4
  477. package/dist/reactivity/Atom.js.map +1 -1
  478. package/dist/reactivity/AtomRegistry.js.map +1 -1
  479. package/dist/rpc/RpcClient.d.ts +16 -1
  480. package/dist/rpc/RpcClient.d.ts.map +1 -1
  481. package/dist/rpc/RpcClient.js +50 -16
  482. package/dist/rpc/RpcClient.js.map +1 -1
  483. package/dist/rpc/RpcMessage.d.ts +10 -1
  484. package/dist/rpc/RpcMessage.d.ts.map +1 -1
  485. package/dist/rpc/RpcMessage.js +1 -0
  486. package/dist/rpc/RpcMessage.js.map +1 -1
  487. package/dist/rpc/RpcSerialization.d.ts.map +1 -1
  488. package/dist/rpc/RpcSerialization.js +6 -0
  489. package/dist/rpc/RpcSerialization.js.map +1 -1
  490. package/dist/rpc/RpcServer.d.ts +31 -0
  491. package/dist/rpc/RpcServer.d.ts.map +1 -1
  492. package/dist/rpc/RpcServer.js +139 -66
  493. package/dist/rpc/RpcServer.js.map +1 -1
  494. package/dist/schema/Model.d.ts +14 -0
  495. package/dist/schema/Model.d.ts.map +1 -1
  496. package/dist/schema/Model.js +18 -3
  497. package/dist/schema/Model.js.map +1 -1
  498. package/dist/sql/Migrator.d.ts +0 -19
  499. package/dist/sql/Migrator.d.ts.map +1 -1
  500. package/dist/sql/Migrator.js +3 -48
  501. package/dist/sql/Migrator.js.map +1 -1
  502. package/dist/sql/MigratorFileSystem.d.ts +21 -0
  503. package/dist/sql/MigratorFileSystem.d.ts.map +1 -0
  504. package/dist/sql/MigratorFileSystem.js +57 -0
  505. package/dist/sql/MigratorFileSystem.js.map +1 -0
  506. package/dist/sql/SqlClient.d.ts.map +1 -1
  507. package/dist/sql/SqlClient.js +5 -9
  508. package/dist/sql/SqlClient.js.map +1 -1
  509. package/dist/sql/Statement.d.ts +20 -6
  510. package/dist/sql/Statement.d.ts.map +1 -1
  511. package/dist/sql/Statement.js +0 -13
  512. package/dist/sql/Statement.js.map +1 -1
  513. package/dist/sql/index.js +1 -1
  514. package/dist/testing/index.d.ts +0 -5
  515. package/dist/testing/index.d.ts.map +1 -1
  516. package/dist/testing/index.js +0 -5
  517. package/dist/testing/index.js.map +1 -1
  518. package/dist/workflow/internal/crypto.js +9 -8
  519. package/dist/workflow/internal/crypto.js.map +1 -1
  520. package/package.json +3 -1
  521. package/src/BigDecimal.ts +3 -0
  522. package/src/Channel.ts +17 -11
  523. package/src/Config.ts +7 -1
  524. package/src/Context.ts +34 -10
  525. package/src/Cron.ts +178 -29
  526. package/src/Duration.ts +140 -0
  527. package/src/Effect.ts +914 -85
  528. package/src/FileSystem.ts +65 -4
  529. package/src/Glob.ts +205 -0
  530. package/src/Match.ts +127 -0
  531. package/src/Pool.ts +73 -15
  532. package/src/Random.ts +3 -3
  533. package/src/RcMap.ts +5 -1
  534. package/src/Schedule.ts +26 -3
  535. package/src/Schema.ts +1189 -62
  536. package/src/SchemaGetter.ts +27 -11
  537. package/src/SchemaRepresentation.ts +19 -0
  538. package/src/SchemaTransformation.ts +8 -3
  539. package/src/ScopedCache.ts +5 -9
  540. package/src/Semaphore.ts +141 -0
  541. package/src/Stream.ts +15 -6
  542. package/src/Terminal.ts +19 -1
  543. package/src/ai/AiError.ts +56 -80
  544. package/src/ai/Decision.ts +257 -6
  545. package/src/ai/DecisionModel.ts +171 -28
  546. package/src/ai/McpServer.ts +1269 -286
  547. package/src/ai/McpTest.ts +380 -0
  548. package/src/ai/Response.ts +2 -22
  549. package/src/ai/Tool.ts +27 -8
  550. package/src/ai/index.ts +6 -0
  551. package/src/ai/internal/mcpCore.ts +78 -44
  552. package/src/ai/internal/mcpProtocol/v2024_11_05.ts +4 -7
  553. package/src/ai/internal/mcpProtocol/v2025_03_26.ts +4 -7
  554. package/src/ai/internal/mcpProtocol/v2025_06_18.ts +4 -7
  555. package/src/ai/internal/mcpProtocol/v2025_11_25.ts +4 -7
  556. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +15 -10
  557. package/src/ai/internal/mcpProtocol.ts +29 -0
  558. package/src/ai/internal/mcpRuntime.ts +9 -5
  559. package/src/ai/internal/mcpStatefulRuntime.ts +14 -2
  560. package/src/cli/Argument.ts +6 -0
  561. package/src/cli/CliOutput.ts +117 -49
  562. package/src/cli/Command.ts +23 -0
  563. package/src/cli/Flag.ts +107 -0
  564. package/src/cli/HelpDoc.ts +18 -1
  565. package/src/cli/Param.ts +6 -0
  566. package/src/cli/Primitive.ts +16 -1
  567. package/src/cli/Prompt.ts +1 -0
  568. package/src/cli/internal/help.ts +21 -9
  569. package/src/cluster/Sharding.ts +93 -26
  570. package/src/cluster/ShardingConfig.ts +41 -3
  571. package/src/cluster/SingleRunner.ts +3 -3
  572. package/src/cluster/SqlMessageStorage.ts +49 -17
  573. package/src/cluster/SqlRunnerStorage.ts +37 -27
  574. package/src/crypto/Aead.ts +517 -0
  575. package/src/crypto/Cipher.ts +326 -0
  576. package/src/crypto/CryptoError.ts +242 -0
  577. package/src/crypto/Digest.ts +167 -0
  578. package/src/crypto/Kdf.ts +315 -0
  579. package/src/crypto/KeyAgreement.ts +489 -0
  580. package/src/crypto/KeyFormat.ts +712 -0
  581. package/src/crypto/KeyWrap.ts +639 -0
  582. package/src/crypto/Mac.ts +386 -0
  583. package/src/crypto/SecureRandom.ts +459 -0
  584. package/src/crypto/Signature.ts +673 -0
  585. package/src/crypto/WebCrypto.ts +64 -0
  586. package/src/crypto/index.ts +78 -0
  587. package/src/crypto/internal/asymmetric.ts +329 -0
  588. package/src/crypto/internal/chacha.ts +1088 -0
  589. package/src/crypto/internal/der.ts +110 -0
  590. package/src/crypto/internal/digest.ts +16 -0
  591. package/src/crypto/internal/key.ts +235 -0
  592. package/src/crypto/internal/md5.ts +170 -0
  593. package/src/crypto/internal/webCrypto.ts +150 -0
  594. package/src/encoding/Base64Url.ts +5 -2
  595. package/src/encoding/Csv.ts +1298 -0
  596. package/src/encoding/Hex.ts +3 -2
  597. package/src/encoding/SchemaBinary.ts +40 -4
  598. package/src/encoding/Toml.ts +85 -20
  599. package/src/encoding/Yaml.ts +61 -18
  600. package/src/encoding/index.ts +6 -0
  601. package/src/eventlog/EventJournal.ts +4 -3
  602. package/src/eventlog/EventLog.ts +340 -15
  603. package/src/eventlog/EventLogEncryption.ts +118 -110
  604. package/src/eventlog/EventLogMessage.ts +273 -1
  605. package/src/eventlog/EventLogRemote.ts +367 -23
  606. package/src/eventlog/EventLogServer.ts +23 -8
  607. package/src/eventlog/EventLogServerEncrypted.ts +1130 -67
  608. package/src/eventlog/EventLogSessionAuth.ts +56 -70
  609. package/src/eventlog/EventRow.ts +12 -3
  610. package/src/eventlog/SqlEventJournal.ts +2 -2
  611. package/src/eventlog/SqlEventLogServerEncrypted.ts +1244 -136
  612. package/src/eventlog/SqlEventLogServerUnencrypted.ts +2 -2
  613. package/src/eventlog/internal/batches.ts +30 -0
  614. package/src/eventlog/internal/compaction.ts +64 -0
  615. package/src/eventlog/internal/identityRootSecretDerivation.ts +93 -123
  616. package/src/eventlog/internal/remoteCompaction.ts +92 -0
  617. package/src/http/Cookies.ts +281 -1
  618. package/src/http/FetchHttpClient.ts +88 -16
  619. package/src/http/HttpClient.ts +89 -22
  620. package/src/http/HttpClientRequest.ts +12 -9
  621. package/src/http/HttpClientResponse.ts +3 -2
  622. package/src/http/HttpMethod.ts +10 -2
  623. package/src/http/HttpServerRequest.ts +15 -30
  624. package/src/http/HttpServerResponse.ts +3 -2
  625. package/src/http/HttpTraceContext.ts +7 -4
  626. package/src/http/ProblemDetails.ts +149 -0
  627. package/src/http/index.ts +6 -0
  628. package/src/http/internal/decompression.ts +4 -4
  629. package/src/http/internal/urlParams.ts +8 -0
  630. package/src/http-api/HttpApiBuilder.ts +24 -12
  631. package/src/http-api/HttpApiClient.ts +67 -1
  632. package/src/http-api/HttpApiEndpoint.ts +14 -5
  633. package/src/http-api/HttpApiError.ts +250 -0
  634. package/src/http-api/HttpApiMiddleware.ts +95 -1
  635. package/src/http-api/HttpApiSchema.ts +105 -14
  636. package/src/index.ts +6 -6
  637. package/src/internal/effect.ts +34 -18
  638. package/src/internal/glob.ts +736 -0
  639. package/src/internal/matcher.ts +17 -0
  640. package/src/internal/persistence.ts +11 -0
  641. package/src/internal/rcRef.ts +4 -1
  642. package/src/internal/schema/toCodeDocument.ts +7 -3
  643. package/src/internal/trie.ts +43 -14
  644. package/src/internal/ulid.ts +44 -0
  645. package/src/internal/uuid.ts +57 -16
  646. package/src/internal/version.ts +1 -1
  647. package/src/observability/Otlp.ts +21 -4
  648. package/src/observability/OtlpResource.ts +9 -1
  649. package/src/persistence/KeyValueStore.ts +219 -22
  650. package/src/persistence/PersistedQueue.ts +128 -59
  651. package/src/persistence/Persistence.ts +20 -13
  652. package/src/process/ChildProcess.ts +255 -260
  653. package/src/process/ChildProcessSpawner.ts +5 -0
  654. package/src/process/CommandLine.ts +630 -0
  655. package/src/process/index.ts +6 -0
  656. package/src/reactivity/Atom.ts +5 -5
  657. package/src/reactivity/AtomRegistry.ts +1 -1
  658. package/src/rpc/RpcClient.ts +62 -26
  659. package/src/rpc/RpcMessage.ts +10 -1
  660. package/src/rpc/RpcSerialization.ts +3 -0
  661. package/src/rpc/RpcServer.ts +176 -78
  662. package/src/schema/Model.ts +26 -3
  663. package/src/sql/Migrator.ts +4 -63
  664. package/src/sql/MigratorFileSystem.ts +71 -0
  665. package/src/sql/SqlClient.ts +2 -16
  666. package/src/sql/Statement.ts +8 -7
  667. package/src/sql/index.ts +1 -1
  668. package/src/testing/index.ts +0 -6
  669. package/src/workflow/internal/crypto.ts +15 -11
  670. package/dist/Crypto.d.ts +0 -244
  671. package/dist/Crypto.d.ts.map +0 -1
  672. package/dist/Crypto.js +0 -139
  673. package/dist/Crypto.js.map +0 -1
  674. package/dist/testing/TestCrypto.d.ts +0 -73
  675. package/dist/testing/TestCrypto.d.ts.map +0 -1
  676. package/dist/testing/TestCrypto.js +0 -87
  677. package/dist/testing/TestCrypto.js.map +0 -1
  678. package/src/Crypto.ts +0 -347
  679. package/src/testing/TestCrypto.ts +0 -94
@@ -16,6 +16,7 @@ import * as Cause from "../Cause.ts"
16
16
  import * as Context from "../Context.ts"
17
17
  import * as Data from "../Data.ts"
18
18
  import * as Deferred from "../Deferred.ts"
19
+ import * as Duration from "../Duration.ts"
19
20
  import * as Effect from "../Effect.ts"
20
21
  import * as ErrorReporter from "../ErrorReporter.ts"
21
22
  import * as Exit from "../Exit.ts"
@@ -46,6 +47,8 @@ import * as SchemaAST from "../SchemaAST.ts"
46
47
  import * as Scope from "../Scope.ts"
47
48
  import type { Stdio } from "../Stdio.ts"
48
49
  import * as Stream from "../Stream.ts"
50
+ import * as Tracer from "../Tracer.ts"
51
+ import type * as Types from "../Types.ts"
49
52
  import * as AiError from "./AiError.ts"
50
53
  import * as McpCore from "./internal/mcpCore.ts"
51
54
  import * as McpProtocolInternal from "./internal/mcpProtocol.ts"
@@ -105,6 +108,7 @@ const internalState = new WeakMap<object, {
105
108
  readonly core: McpCore.McpCore
106
109
  readonly notifications: Queue.Dequeue<QueuedServerNotification>
107
110
  readonly notificationDelivery: { consumers: number; listChangeRevision: number; requestEndpoints: number }
111
+ readonly globalMiddleware: Array<middleware.Fn<any, any, any>>
108
112
  }>()
109
113
 
110
114
  // Request-scoped HTTP servers deliver a request's own notifications through
@@ -166,13 +170,29 @@ const toInternalServerNotification = (
166
170
  }
167
171
  }
168
172
 
169
- // Request services must come from the invocation, including when a handler is registered during a request.
170
- const omitRequestServices = Context.omit(
171
- McpRequestContext,
172
- McpServerClient,
173
- HttpServerRequest.HttpServerRequest,
174
- CurrentLogLevel
175
- )
173
+ const middlewareKeyPrefix = "effect/ai/McpServer/Middleware-"
174
+
175
+ // Do not capture request services or middleware stacks at registration.
176
+ const requestServiceKeys = new Set<string>([
177
+ McpRequestContext.key,
178
+ McpServerClient.key,
179
+ HttpServerRequest.HttpServerRequest.key,
180
+ HttpServerRequest.ParsedSearchParams.key,
181
+ HttpRouter.RouteContext.key,
182
+ CurrentLogLevel.key,
183
+ Scope.Scope.key,
184
+ Tracer.ParentSpan.key
185
+ ])
186
+
187
+ const omitRequestServices = <Services>(context: Context.Context<Services>): Context.Context<Services> => {
188
+ const services = new Map<string, any>()
189
+ for (const [key, value] of context.mapUnsafe) {
190
+ if (!requestServiceKeys.has(key) && !key.startsWith(middlewareKeyPrefix)) {
191
+ services.set(key, value)
192
+ }
193
+ }
194
+ return Context.makeUnsafe(services)
195
+ }
176
196
 
177
197
  const provideInvocationContext = <A, E, R>(
178
198
  effect: Effect.Effect<A, E, R>,
@@ -199,6 +219,703 @@ const provideInvocationContext = <A, E, R>(
199
219
  >
200
220
  }
201
221
 
222
+ // -----------------------------------------------------------------------------
223
+ // Request-level dependencies
224
+ // -----------------------------------------------------------------------------
225
+
226
+ /**
227
+ * Marks a request-level dependency of an MCP registration or middleware.
228
+ *
229
+ * **Details**
230
+ *
231
+ * Registrations carry handler dependencies as `McpRequest<"Requires", S>`.
232
+ * MCP middleware and transports discharge these markers; providing `S` with
233
+ * `Layer.provide` or `Effect.provide` does not.
234
+ *
235
+ * `layerHttp` and `layerHttpRequestScoped` convert the markers they don't
236
+ * discharge into `HttpRouter.Request` markers, so `HttpRouter.middleware` can
237
+ * satisfy them. On stdio and custom transports an undischarged marker is a
238
+ * compile error.
239
+ *
240
+ * @see {@link middleware} for discharging request-level dependencies
241
+ *
242
+ * @stability unstable
243
+ * @category utility types
244
+ * @since 4.0.0
245
+ */
246
+ export interface McpRequest<Kind extends string, T> {
247
+ readonly _: unique symbol
248
+ readonly kind: Kind
249
+ readonly type: T
250
+ }
251
+
252
+ /**
253
+ * Helper types for `McpRequest` markers.
254
+ *
255
+ * @stability unstable
256
+ * @category utility types
257
+ * @since 4.0.0
258
+ */
259
+ export declare namespace McpRequest {
260
+ /**
261
+ * Wraps each member of a union in an `McpRequest` marker of the supplied kind.
262
+ *
263
+ * @stability unstable
264
+ * @category utility types
265
+ * @since 4.0.0
266
+ */
267
+ export type From<Kind extends string, R> = R extends infer T ? McpRequest<Kind, T> : never
268
+
269
+ /**
270
+ * Extracts the services from `McpRequest` markers of the supplied kind.
271
+ *
272
+ * @stability unstable
273
+ * @category utility types
274
+ * @since 4.0.0
275
+ */
276
+ export type Only<Kind extends string, A> = A extends McpRequest<Kind, infer T> ? T : never
277
+
278
+ /**
279
+ * Removes `McpRequest` markers from a union.
280
+ *
281
+ * @stability unstable
282
+ * @category utility types
283
+ * @since 4.0.0
284
+ */
285
+ export type Without<A> = A extends McpRequest<infer _Kind, infer _> ? never : A
286
+ }
287
+
288
+ /**
289
+ * Opaque handler result. Middleware can wrap execution and provide services,
290
+ * but cannot inspect or replace the result.
291
+ *
292
+ * @stability unstable
293
+ * @category middleware
294
+ * @since 4.0.0
295
+ */
296
+ export interface MiddlewareSuccess {
297
+ readonly _: unique symbol
298
+ }
299
+
300
+ /**
301
+ * The request methods that run MCP middleware. More methods may be added, so
302
+ * don't `switch` on it exhaustively without a default case.
303
+ *
304
+ * @stability unstable
305
+ * @category middleware
306
+ * @since 4.0.0
307
+ */
308
+ export type MiddlewareMethod =
309
+ | "tools/call"
310
+ | "resources/read"
311
+ | "prompts/get"
312
+ | "completion/complete"
313
+ | "tools/list"
314
+ | "resources/list"
315
+ | "resources/templates/list"
316
+ | "prompts/list"
317
+
318
+ /**
319
+ * Request metadata passed to MCP middleware.
320
+ *
321
+ * **Details**
322
+ *
323
+ * `target` is the tool name, the requested resource URI, or the prompt name.
324
+ * For `completion/complete` it is the prompt name, or the URI template of the
325
+ * resource template being completed. `payload` holds the request parameters.
326
+ *
327
+ * On list requests, middleware runs only when it wraps a {@link visibility},
328
+ * once for each registration it wraps. `target` is then the tool name, the
329
+ * resource URI, the URI template or the prompt name of that registration, and
330
+ * `payload` is `undefined`.
331
+ *
332
+ * `headers` are the HTTP request headers. They are empty on stdio, on custom
333
+ * transports and for in-process calls. `sessionId` is the `Mcp-Session-Id`
334
+ * header, so it is `undefined` outside sessionful HTTP.
335
+ *
336
+ * @stability unstable
337
+ * @category middleware
338
+ * @since 4.0.0
339
+ */
340
+ export interface MiddlewareOptions {
341
+ readonly method: MiddlewareMethod
342
+ readonly target: string
343
+ readonly payload: unknown
344
+ readonly requestContext: McpRequestContext["Service"]
345
+ readonly headers: Headers.Headers
346
+ readonly sessionId: string | undefined
347
+ }
348
+
349
+ const MiddlewareTypeId = "~effect/ai/McpServer/Middleware"
350
+
351
+ type MiddlewareConfig = {
352
+ provides: any
353
+ error: McpErrorBase
354
+ requires: any
355
+ layerError: any
356
+ layerRequires: any
357
+ }
358
+
359
+ type MiddlewareLayer<Config extends MiddlewareConfig, R> = Layer.Layer<
360
+ McpRequest.From<"Requires", Config["provides"]>,
361
+ Config["layerError"],
362
+ R | Config["layerRequires"] | McpRequest.From<"Requires", Config["requires"]>
363
+ >
364
+
365
+ /**
366
+ * Composable MCP middleware.
367
+ *
368
+ * **Details**
369
+ *
370
+ * Provide `layer` to registration layers, or to the Effect form of a
371
+ * registration, to run the middleware for those registrations. Use
372
+ * `layerGlobal` to run it for every request on the server.
373
+ *
374
+ * Services the middleware reads per request are `McpRequest<"Requires", S>`
375
+ * requirements of `layer` and `layerGlobal`, like the request-level
376
+ * dependencies of a registration. A middleware that provides `S` meets them
377
+ * when it runs outside this one: `a.combine(b)` runs `b` outside `a`, and so
378
+ * does providing `b.layer` or `b.layerGlobal` outside `a.layer`, though
379
+ * `layerGlobal` installs `b` for the whole server. The transport discharges
380
+ * the services it supplies, and `layerHttp` turns the rest into
381
+ * `HttpRouter.Request` requirements that an `HttpRouter.middleware` can meet.
382
+ *
383
+ * @see {@link middleware} for creating MCP middleware
384
+ *
385
+ * @stability unstable
386
+ * @category middleware
387
+ * @since 4.0.0
388
+ */
389
+ export interface Middleware<Config extends MiddlewareConfig> {
390
+ readonly [MiddlewareTypeId]: Config
391
+ readonly layer: MiddlewareLayer<Config, never>
392
+ readonly layerGlobal: MiddlewareLayer<Config, McpServer>
393
+ readonly combine: <Config2 extends MiddlewareConfig>(other: Middleware<Config2>) => Middleware<{
394
+ provides: Config2["provides"] | Config["provides"]
395
+ error: Config2["error"] | Config["error"]
396
+ requires: Exclude<Config["requires"], Config2["provides"]> | Config2["requires"]
397
+ layerError: Config["layerError"] | Config2["layerError"]
398
+ layerRequires: Config["layerRequires"] | Config2["layerRequires"]
399
+ }>
400
+ }
401
+
402
+ /**
403
+ * Creates MCP middleware that runs around `tools/call`, `resources/read`,
404
+ * `prompts/get` and `completion/complete` requests.
405
+ *
406
+ * **Details**
407
+ *
408
+ * Middleware is how request-level dependencies are satisfied: declare the
409
+ * services it provides with `middleware<{ provides: S }>()` and provide them to
410
+ * the handler effect. It receives the request headers, session id and request
411
+ * context, so it can resolve the current user per request.
412
+ *
413
+ * Pass a function, or an Effect that builds the function. Services the Effect
414
+ * reads are requirements of the middleware layer. Services the function reads
415
+ * per request, other than `McpRequestContext`, are per-request requirements
416
+ * of the result; see {@link Middleware} for how they are met.
417
+ *
418
+ * Failures must be `McpErrorBase` values. A middleware failure is sent as a
419
+ * JSON-RPC error with its `code`, `message` and `data`, never as a tool
420
+ * result. Pick custom codes from the implementation-defined range
421
+ * (-32000 to -32019): any numeric `code` is sent as is. Defects are logged,
422
+ * reported to the `ErrorReporter` and sent as `InternalError("Internal error")`.
423
+ * Interruption propagates.
424
+ *
425
+ * Local middleware runs inside global middleware, and middleware provided both
426
+ * locally and globally runs once. Middleware never runs for `initialize`. It
427
+ * runs for list requests only when it wraps a {@link visibility}, so that the
428
+ * visibility check can read the services it provides.
429
+ *
430
+ * **Example** (Resolving the current user per request)
431
+ *
432
+ * ```ts
433
+ * import { Context, Effect, Layer, Schema } from "effect"
434
+ * import { McpSchema, McpServer, Tool, Toolkit } from "effect/ai"
435
+ *
436
+ * class CurrentUser extends Context.Service<CurrentUser, { readonly id: string }>()("CurrentUser") {}
437
+ *
438
+ * class Unauthorized extends Schema.Error<Unauthorized>("Unauthorized")({
439
+ * ...McpSchema.McpErrorBase.fields,
440
+ * _tag: Schema.tag("Unauthorized"),
441
+ * code: Schema.tag(-32001)
442
+ * }) {}
443
+ *
444
+ * const WhoAmI = Tool.make("WhoAmI", { success: Schema.String, dependencies: [CurrentUser] })
445
+ * const Tools = Toolkit.make(WhoAmI)
446
+ *
447
+ * const Auth = McpServer.middleware<{ provides: CurrentUser }>()((effect, { headers }) => {
448
+ * const token = headers["authorization"]
449
+ * return token === undefined
450
+ * ? Effect.fail(new Unauthorized({ message: "Missing credentials" }))
451
+ * : Effect.provideService(effect, CurrentUser, { id: token })
452
+ * })
453
+ *
454
+ * const Registrations = McpServer.toolkit(Tools).pipe(
455
+ * Layer.provide(Auth.layer),
456
+ * Layer.provide(Tools.toLayer({
457
+ * WhoAmI: () => Effect.map(CurrentUser, (user) => user.id)
458
+ * }))
459
+ * )
460
+ * ```
461
+ *
462
+ * @stability unstable
463
+ * @category middleware
464
+ * @since 4.0.0
465
+ */
466
+ export const middleware:
467
+ & middleware.Make<never>
468
+ & (<Config extends { provides?: any } = {}>() => middleware.Make<
469
+ Config extends { provides: infer P } ? P : never
470
+ >) = function() {
471
+ if (arguments.length === 0) {
472
+ return makeMiddleware as any
473
+ }
474
+ return makeMiddleware(arguments[0], arguments[1]) as any
475
+ }
476
+
477
+ /**
478
+ * Types used by `middleware`.
479
+ *
480
+ * @stability unstable
481
+ * @category middleware
482
+ * @since 4.0.0
483
+ */
484
+ export declare namespace middleware {
485
+ /**
486
+ * The middleware function.
487
+ *
488
+ * @stability unstable
489
+ * @category middleware
490
+ * @since 4.0.0
491
+ */
492
+ export type Fn<Provides, E, R> = (
493
+ effect: Effect.Effect<MiddlewareSuccess, McpErrorBase, Types.NoInfer<Provides>>,
494
+ options: MiddlewareOptions
495
+ ) => Effect.Effect<MiddlewareSuccess, E, R>
496
+
497
+ /**
498
+ * The overloads of a middleware constructor.
499
+ *
500
+ * @stability unstable
501
+ * @category middleware
502
+ * @since 4.0.0
503
+ */
504
+ export type Make<Provides> = {
505
+ <E extends McpErrorBase, R, EX, RX, const Global extends boolean = false>(
506
+ middleware: Effect.Effect<Fn<Provides, E, R>, EX, RX>,
507
+ options?: { readonly global?: Global | undefined }
508
+ ): Made<Global, {
509
+ provides: Provides
510
+ error: E
511
+ requires: Exclude<R, McpRequestContext>
512
+ layerError: EX
513
+ layerRequires: Exclude<RX, Scope.Scope>
514
+ }>
515
+ <E extends McpErrorBase, R, const Global extends boolean = false>(
516
+ middleware: Fn<Provides, E, R>,
517
+ options?: { readonly global?: Global | undefined }
518
+ ): Made<Global, {
519
+ provides: Provides
520
+ error: E
521
+ requires: Exclude<R, McpRequestContext>
522
+ layerError: never
523
+ layerRequires: never
524
+ }>
525
+ }
526
+ }
527
+
528
+ /**
529
+ * Creates middleware that hides registrations per request.
530
+ *
531
+ * **Details**
532
+ *
533
+ * The check runs for every registration the middleware is provided to, on list
534
+ * requests and on calls, reads, gets and completions. When it returns `false`
535
+ * the registration is left out of list results, and requests for it fail as if
536
+ * it was not registered.
537
+ *
538
+ * The result is a `Middleware` and composes like one. The check receives the
539
+ * same {@link MiddlewareOptions} as middleware, and services it reads per
540
+ * request, other than `McpRequestContext`, are met the same way. Scope a
541
+ * visibility to some tools by providing its layer to their toolkit only, or
542
+ * branch on `target`.
543
+ *
544
+ * On a list request, the check and the middleware outside the innermost
545
+ * visibility run once for each registration. Middleware inside it does not
546
+ * run. A failure of that middleware or of a check fails the whole list
547
+ * request. It never hides a registration.
548
+ *
549
+ * Unlike `EnabledWhen`, a visibility runs the middleware around it on list
550
+ * requests, and middleware sees requests for hidden registrations.
551
+ *
552
+ * **Example** (Hiding admin tools from other users)
553
+ *
554
+ * ```ts
555
+ * import { Context, Effect, Layer, Schema } from "effect"
556
+ * import { McpServer, Tool, Toolkit } from "effect/ai"
557
+ *
558
+ * class CurrentUser extends Context.Service<CurrentUser, { readonly isAdmin: boolean }>()("CurrentUser") {}
559
+ *
560
+ * const AdminTools = Toolkit.make(Tool.make("DeleteUser", { success: Schema.String }))
561
+ *
562
+ * const Auth = McpServer.middleware<{ provides: CurrentUser }>()((effect, { headers }) =>
563
+ * Effect.provideService(effect, CurrentUser, { isAdmin: headers["x-role"] === "admin" })
564
+ * )
565
+ * const AdminOnly = McpServer.visibility(() => Effect.map(CurrentUser, (user) => user.isAdmin))
566
+ *
567
+ * const Registrations = McpServer.toolkit(AdminTools).pipe(
568
+ * Layer.provide(AdminOnly.combine(Auth).layer),
569
+ * Layer.provide(AdminTools.toLayer({ DeleteUser: () => Effect.succeed("deleted") }))
570
+ * )
571
+ * ```
572
+ *
573
+ * @see {@link middleware} for providing the services a check reads
574
+ *
575
+ * @stability unstable
576
+ * @category middleware
577
+ * @since 4.0.0
578
+ */
579
+ export const visibility: visibility.Make = ((
580
+ check: AnyVisibilityCheck | Effect.Effect<AnyVisibilityCheck, any, any>,
581
+ options?: { readonly global?: boolean | undefined }
582
+ ) => makeMiddleware(Effect.isEffect(check) ? Effect.map(check, makeGate) : makeGate(check), options)) as any
583
+
584
+ /**
585
+ * Types used by `visibility`.
586
+ *
587
+ * @stability unstable
588
+ * @category middleware
589
+ * @since 4.0.0
590
+ */
591
+ export declare namespace visibility {
592
+ /**
593
+ * The visibility check.
594
+ *
595
+ * @stability unstable
596
+ * @category middleware
597
+ * @since 4.0.0
598
+ */
599
+ export type Check<E, R> = (options: MiddlewareOptions) => Effect.Effect<boolean, E, R>
600
+
601
+ /**
602
+ * The overloads of `visibility`.
603
+ *
604
+ * @stability unstable
605
+ * @category middleware
606
+ * @since 4.0.0
607
+ */
608
+ export type Make = {
609
+ <E extends McpErrorBase, R, EX, RX, const Global extends boolean = false>(
610
+ check: Effect.Effect<Check<E, R>, EX, RX>,
611
+ options?: { readonly global?: Global | undefined }
612
+ ): Made<Global, {
613
+ provides: never
614
+ error: E
615
+ requires: Exclude<R, McpRequestContext>
616
+ layerError: EX
617
+ layerRequires: Exclude<RX, Scope.Scope>
618
+ }>
619
+ <E extends McpErrorBase, R, const Global extends boolean = false>(
620
+ check: Check<E, R>,
621
+ options?: { readonly global?: Global | undefined }
622
+ ): Made<Global, {
623
+ provides: never
624
+ error: E
625
+ requires: Exclude<R, McpRequestContext>
626
+ layerError: never
627
+ layerRequires: never
628
+ }>
629
+ }
630
+ }
631
+
632
+ type AnyVisibilityCheck = visibility.Check<any, any>
633
+
634
+ // Raised by a visibility gate. It is left out of the types because `makeInvoke`
635
+ // replaces it with the not-found error of the request. It still has the shape
636
+ // of an MCP error, since middleware outside the gate sees it as one.
637
+ class Hidden extends Data.TaggedError("effect/ai/McpServer/Hidden")<{
638
+ readonly code: number
639
+ readonly message: string
640
+ }> {}
641
+
642
+ const failHidden = Effect.fail(
643
+ new Hidden({ code: McpSchema.INVALID_PARAMS_ERROR_CODE, message: "Not found" })
644
+ ) as Effect.Effect<never>
645
+
646
+ // Marks the middleware functions created by `visibility`.
647
+ const gates = new WeakSet<AnyMiddlewareFn>()
648
+
649
+ const makeGate = (check: AnyVisibilityCheck): AnyMiddlewareFn => {
650
+ const gate: AnyMiddlewareFn = (effect, options) =>
651
+ Effect.flatMap(check(options), (visible) => visible ? effect : failHidden)
652
+ gates.add(gate)
653
+ return gate
654
+ }
655
+
656
+ type Made<Global extends boolean, Config extends MiddlewareConfig> = Global extends true
657
+ ? MiddlewareLayer<Config, McpServer>
658
+ : Middleware<Config>
659
+
660
+ type AnyMiddlewareFn = middleware.Fn<any, any, any>
661
+
662
+ class MiddlewareFn extends Context.Service<MiddlewareFn, AnyMiddlewareFn>()("effect/ai/McpServer/MiddlewareFn") {}
663
+
664
+ const makeMiddleware = (
665
+ fn: AnyMiddlewareFn | Effect.Effect<AnyMiddlewareFn, any, any>,
666
+ options?: { readonly global?: boolean | undefined }
667
+ ) => {
668
+ const middleware = new MiddlewareImpl(
669
+ Effect.isEffect(fn) ? Layer.effect(MiddlewareFn)(fn) : Layer.succeed(MiddlewareFn, fn)
670
+ )
671
+ return options?.global ? middleware.layerGlobal : middleware
672
+ }
673
+
674
+ let middlewareId = 0
675
+
676
+ class MiddlewareImpl {
677
+ readonly [MiddlewareTypeId] = {} as any
678
+ readonly layer: Layer.Layer<never, any, any>
679
+ readonly layerGlobal: Layer.Layer<never, any, any>
680
+ readonly layerFn: Layer.Layer<MiddlewareFn, any, any>
681
+ readonly dependencies: Layer.Layer<any, any, any> | undefined
682
+
683
+ constructor(
684
+ layerFn: Layer.Layer<MiddlewareFn, any, any>,
685
+ dependencies?: Layer.Layer<any, any, any> | undefined
686
+ ) {
687
+ this.layerFn = layerFn
688
+ this.dependencies = dependencies
689
+ const contextKey = `${middlewareKeyPrefix}${++middlewareId}`
690
+ this.layer = Layer.effectContext(Effect.gen(function*() {
691
+ const stack: Array<AnyMiddlewareFn> = [yield* MiddlewareFn]
692
+ if (dependencies) {
693
+ const memoMap = yield* Layer.CurrentMemoMap
694
+ const scope = yield* Effect.scope
695
+ stack.push(...getMiddleware(yield* Layer.buildWithMemoMap(dependencies, memoMap, scope)))
696
+ }
697
+ return Context.makeUnsafe<never>(new Map([[contextKey, stack]]))
698
+ })).pipe(Layer.provide(layerFn))
699
+ this.layerGlobal = Layer.effectDiscard(Effect.gen(function*() {
700
+ const stack: ReadonlyArray<AnyMiddlewareFn> = Context.getOrUndefinedUnsafe(
701
+ yield* Effect.context<never>(),
702
+ contextKey as any
703
+ )!
704
+ const { globalMiddleware } = internalState.get(yield* McpServer)!
705
+ yield* Effect.acquireRelease(
706
+ Effect.sync(() => {
707
+ globalMiddleware.push(...stack)
708
+ }),
709
+ () =>
710
+ Effect.sync(() => {
711
+ for (const fn of stack) {
712
+ const index = globalMiddleware.indexOf(fn)
713
+ if (index !== -1) globalMiddleware.splice(index, 1)
714
+ }
715
+ })
716
+ )
717
+ })).pipe(Layer.provide(this.layer))
718
+ }
719
+
720
+ combine(other: Middleware<any>): Middleware<any> {
721
+ return new MiddlewareImpl(
722
+ this.layerFn,
723
+ this.dependencies ? Layer.provideMerge(this.dependencies, other.layer as any) : other.layer as any
724
+ ) as any
725
+ }
726
+ }
727
+
728
+ // The innermost middleware comes first.
729
+ const getMiddleware = (context: Context.Context<never>): ReadonlyArray<AnyMiddlewareFn> => {
730
+ const stacks: Array<ReadonlyArray<AnyMiddlewareFn>> = []
731
+ let maxLength = 0
732
+ for (const [key, value] of context.mapUnsafe) {
733
+ if (key.startsWith(middlewareKeyPrefix)) {
734
+ stacks.push(value)
735
+ maxLength = Math.max(maxLength, value.length)
736
+ }
737
+ }
738
+ const unique = new Set<AnyMiddlewareFn>()
739
+ for (let i = maxLength - 1; i >= 0; i--) {
740
+ for (const stack of stacks) {
741
+ if (i < stack.length) unique.add(stack[i])
742
+ }
743
+ }
744
+ return Arr.fromIterable(unique).reverse()
745
+ }
746
+
747
+ const isMcpError = (error: unknown): error is McpErrorBase =>
748
+ Predicate.hasProperty(error, "code") && typeof error.code === "number" &&
749
+ Predicate.hasProperty(error, "message") && typeof error.message === "string"
750
+
751
+ // Distinguishes handler failures from failures raised or rewritten by middleware.
752
+ const HandlerFailure = Context.Reference<boolean>("effect/ai/McpServer/HandlerFailure", {
753
+ defaultValue: () => false
754
+ })
755
+ const handlerFailure = Context.make(HandlerFailure, true)
756
+
757
+ const internalError = new InternalError({ message: "Internal error" })
758
+
759
+ const rejectWith = (error: McpErrorBase) =>
760
+ Effect.fail(new McpCore.RequestRejected({ code: error.code, message: error.message, data: error.data, error }))
761
+
762
+ type CallMethod = "tools/call" | "resources/read" | "prompts/get" | "completion/complete"
763
+
764
+ type ListMethod = Exclude<MiddlewareMethod, CallMethod>
765
+
766
+ interface NotFoundErrors {
767
+ readonly "tools/call": McpCore.ToolNotFound
768
+ readonly "resources/read": McpCore.ResourceNotFound
769
+ readonly "prompts/get": McpCore.PromptNotFound
770
+ readonly "completion/complete": InvalidParams
771
+ }
772
+
773
+ const notFound = (method: CallMethod, target: string): NotFoundErrors[CallMethod] => {
774
+ switch (method) {
775
+ case "tools/call":
776
+ return new McpCore.ToolNotFound({ name: target })
777
+ case "resources/read":
778
+ return new McpCore.ResourceNotFound({ uri: target })
779
+ case "prompts/get":
780
+ return new McpCore.PromptNotFound({ name: target })
781
+ case "completion/complete":
782
+ return new InvalidParams({ message: "Unknown completion reference or argument" })
783
+ }
784
+ }
785
+
786
+ const isHidden = (error: unknown): error is Hidden => error instanceof Hidden
787
+
788
+ // Recovers a request rejected by a visibility gate. Any other cause, including
789
+ // one that also holds an interrupt, is propagated unchanged.
790
+ const catchHidden =
791
+ <B, E2>(onHidden: () => Effect.Effect<B, E2>) =>
792
+ <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A | B, Exclude<E, Hidden> | E2, R> =>
793
+ Effect.catchCause(self, (cause): Effect.Effect<B, Exclude<E, Hidden> | E2> => {
794
+ const failure = Cause.findFail(cause)
795
+ return !Cause.hasInterrupts(cause) && Result.isSuccess(failure) && isHidden(failure.success.error)
796
+ ? onHidden()
797
+ : Effect.failCause(cause as Cause.Cause<Exclude<E, Hidden>>)
798
+ })
799
+
800
+ // The innermost middleware comes first. Middleware provided both locally and
801
+ // globally runs once, at its outermost position.
802
+ const middlewareStack = (
803
+ localMiddleware: ReadonlyArray<AnyMiddlewareFn>,
804
+ globalMiddleware: ReadonlyArray<AnyMiddlewareFn>
805
+ ): ReadonlyArray<AnyMiddlewareFn> => {
806
+ if (globalMiddleware.length === 0) {
807
+ return localMiddleware
808
+ }
809
+ if (localMiddleware.length === 0) {
810
+ return globalMiddleware
811
+ }
812
+ const stack = [...localMiddleware, ...globalMiddleware]
813
+ return stack.filter((fn, index) => stack.lastIndexOf(fn) === index)
814
+ }
815
+
816
+ // Runs a handler inside middleware. The handler's own failures pass through, a
817
+ // visibility gate fails with `Hidden`, and other failures become
818
+ // `RequestRejected`: middleware failures as JSON-RPC errors, anything else as
819
+ // a reported internal error.
820
+ const runMiddleware = <A, E>(
821
+ handler: Effect.Effect<A, E, any>,
822
+ middleware: ReadonlyArray<AnyMiddlewareFn>,
823
+ invocation: McpCore.McpInvocation,
824
+ request: Pick<MiddlewareOptions, "method" | "target" | "payload">
825
+ ): Effect.Effect<A, E | Hidden | McpCore.RequestRejected> => {
826
+ const effect = middleware.length === 0 ? handler : Effect.withFiber((fiber) => {
827
+ const headers = Context.getOrUndefined(fiber.context, HttpServerRequest.HttpServerRequest)?.headers ??
828
+ Headers.empty
829
+ const options: MiddlewareOptions = {
830
+ ...request,
831
+ requestContext: invocation.requestContext,
832
+ headers,
833
+ sessionId: headers[MCP_SESSION_ID_HEADER]
834
+ }
835
+ const handled = Effect.catchCause(handler, (cause) => Effect.failCause(Cause.annotate(cause, handlerFailure)))
836
+ return middleware.reduce((effect: Effect.Effect<any, any, any>, fn) => fn(effect, options), handled)
837
+ })
838
+ return provideInvocationContext(effect, invocation).pipe(
839
+ Effect.catchCause((cause): Effect.Effect<never, E | Hidden | McpCore.RequestRejected> => {
840
+ if (Cause.hasInterrupts(cause)) {
841
+ return Effect.failCause(cause)
842
+ }
843
+ const failure = Cause.findFail(cause)
844
+ if (Result.isSuccess(failure) && !Cause.hasDies(cause)) {
845
+ const error = failure.success.error
846
+ if (isHidden(error)) {
847
+ return Effect.fail(error)
848
+ }
849
+ if (middleware.length === 0 || Context.get(Cause.reasonAnnotations(failure.success), HandlerFailure)) {
850
+ return Effect.failCause(cause)
851
+ }
852
+ if (isMcpError(error)) {
853
+ return rejectWith(error)
854
+ }
855
+ }
856
+ return Effect.logError(cause).pipe(
857
+ Effect.andThen(ErrorReporter.report(cause)),
858
+ Effect.andThen(rejectWith(internalError))
859
+ )
860
+ })
861
+ ) as Effect.Effect<A, E | Hidden | McpCore.RequestRejected>
862
+ }
863
+
864
+ // Request services override captured services; global middleware wraps local middleware.
865
+ const makeInvoke = (
866
+ context: Context.Context<never> | undefined,
867
+ globalMiddleware: ReadonlyArray<AnyMiddlewareFn>
868
+ ) => {
869
+ const services = context === undefined ? Context.empty() : omitRequestServices(context)
870
+ const localMiddleware = context === undefined ? [] : getMiddleware(context)
871
+ const invoke = <A, E, M extends CallMethod>(
872
+ handler: Effect.Effect<A, E, any>,
873
+ invocation: McpCore.McpInvocation,
874
+ request: {
875
+ readonly method: M
876
+ readonly target: string
877
+ readonly payload: unknown
878
+ }
879
+ ): Effect.Effect<A, E | NotFoundErrors[M] | McpCore.RequestRejected> =>
880
+ runMiddleware(
881
+ services.mapUnsafe.size === 0
882
+ ? handler
883
+ : Effect.updateContext(handler, (context: Context.Context<any>) => Context.merge(services, context)),
884
+ middlewareStack(localMiddleware, globalMiddleware),
885
+ invocation,
886
+ request
887
+ ).pipe(
888
+ catchHidden(() => Effect.fail(notFound(request.method, request.target) as NotFoundErrors[M]))
889
+ ) as Effect.Effect<A, E | NotFoundErrors[M] | McpCore.RequestRejected>
890
+ // On list requests only the middleware outside the innermost visibility runs.
891
+ const visible = (method: ListMethod, target: string): McpCore.Visible => (invocation) => {
892
+ const middleware = middlewareStack(localMiddleware, globalMiddleware)
893
+ const innermost = middleware.findIndex((fn) => gates.has(fn))
894
+ if (innermost === -1) {
895
+ return Effect.succeed(true)
896
+ }
897
+ return runMiddleware(Effect.void, middleware.slice(innermost), invocation, { method, target, payload: undefined })
898
+ .pipe(
899
+ Effect.as(true),
900
+ catchHidden(() => Effect.succeed(false))
901
+ )
902
+ }
903
+ return { invoke, visible }
904
+ }
905
+
906
+ // Applies the `EnabledWhen` annotation of a registration.
907
+ const isEnabled = (annotations: Context.Context<never>) => {
908
+ const enabledWhen = Context.getOrUndefined(annotations, EnabledWhen)
909
+ return (profile: McpCore.NegotiatedProtocolProfile<string>): boolean =>
910
+ enabledWhen === undefined || enabledWhen({
911
+ protocolVersion: profile.protocolVersion,
912
+ capabilities: profile.clientCapabilities,
913
+ clientInfo: profile.clientInfo
914
+ })
915
+ }
916
+
917
+ const rejectedError = (rejected: McpCore.RequestRejected) => Effect.fail(rejected.error)
918
+
202
919
  /**
203
920
  * Service that stores and serves an MCP server's registered tools, resources,
204
921
  * prompts, completions, and outgoing notifications.
@@ -225,6 +942,7 @@ export class McpServer extends Context.Service<McpServer, {
225
942
  readonly addTool: (options: {
226
943
  readonly tool: McpTool
227
944
  readonly annotations: Context.Context<never>
945
+ readonly services?: Context.Context<never> | undefined
228
946
  readonly handle: (
229
947
  payload: any
230
948
  ) => Effect.Effect<
@@ -235,7 +953,7 @@ export class McpServer extends Context.Service<McpServer, {
235
953
  }) => Effect.Effect<void>
236
954
  readonly callTool: (
237
955
  requests: typeof CallTool.payloadSchema.Type
238
- ) => Effect.Effect<CallToolResult, InternalError | InvalidParams, McpServerClient>
956
+ ) => Effect.Effect<CallToolResult, McpErrorBase | InternalError | InvalidParams, McpServerClient>
239
957
 
240
958
  readonly resources: ReadonlyArray<{
241
959
  readonly resource: Resource
@@ -244,6 +962,7 @@ export class McpServer extends Context.Service<McpServer, {
244
962
  readonly addResource: (options: {
245
963
  readonly resource: Resource
246
964
  readonly annotations: Context.Context<never>
965
+ readonly services?: Context.Context<never> | undefined
247
966
  readonly handle: Effect.Effect<
248
967
  ReadResourceResult,
249
968
  InternalError,
@@ -259,6 +978,7 @@ export class McpServer extends Context.Service<McpServer, {
259
978
  options: {
260
979
  readonly template: ResourceTemplate
261
980
  readonly annotations: Context.Context<never>
981
+ readonly services?: Context.Context<never> | undefined
262
982
  readonly routerPath: string
263
983
  readonly completions: Record<
264
984
  string,
@@ -289,6 +1009,7 @@ export class McpServer extends Context.Service<McpServer, {
289
1009
  readonly addPrompt: (options: {
290
1010
  readonly prompt: Prompt
291
1011
  readonly annotations: Context.Context<never>
1012
+ readonly services?: Context.Context<never> | undefined
292
1013
  readonly completions: Record<
293
1014
  string,
294
1015
  (
@@ -302,11 +1023,11 @@ export class McpServer extends Context.Service<McpServer, {
302
1023
  }) => Effect.Effect<void>
303
1024
  readonly getPromptResult: (
304
1025
  request: typeof GetPrompt.payloadSchema.Type
305
- ) => Effect.Effect<GetPromptResult, InternalError | InvalidParams, McpServerClient>
1026
+ ) => Effect.Effect<GetPromptResult, McpErrorBase | InternalError | InvalidParams, McpServerClient>
306
1027
 
307
1028
  readonly completion: (
308
1029
  complete: typeof Complete.payloadSchema.Type
309
- ) => Effect.Effect<CompleteResult, InvalidParams | InternalError, McpServerClient>
1030
+ ) => Effect.Effect<CompleteResult, McpErrorBase | InvalidParams | InternalError, McpServerClient>
310
1031
  }>()("effect/ai/McpServer") {
311
1032
  /**
312
1033
  * Builds an MCP server service from registered tools, prompts, resources, and completions.
@@ -333,6 +1054,7 @@ export class McpServer extends Context.Service<McpServer, {
333
1054
  readonly annotations: Context.Context<never>
334
1055
  }> = []
335
1056
  const notificationsQueue = yield* Queue.make<QueuedServerNotification>()
1057
+ const globalMiddleware: Array<AnyMiddlewareFn> = []
336
1058
  const notificationDelivery = { consumers: 0, listChangeRevision: 0, requestEndpoints: 0 }
337
1059
  // With only request-scoped endpoints, no long-lived server ever takes from the shared queue.
338
1060
  const withoutSharedConsumer = () =>
@@ -431,22 +1153,20 @@ export class McpServer extends Context.Service<McpServer, {
431
1153
  } else {
432
1154
  tools[existingIndex] = options
433
1155
  }
434
- const enabledWhen = Context.getOrUndefined(options.annotations, EnabledWhen)
1156
+ const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
435
1157
  yield* internalCore.tools.register({
436
1158
  descriptor: new McpTool({
437
1159
  ...options.tool,
438
1160
  title: options.tool.title ?? options.tool.annotations?.title
439
1161
  }),
440
- isVisible: (profile) =>
441
- enabledWhen === undefined || enabledWhen(
442
- {
443
- protocolVersion: profile.protocolVersion,
444
- capabilities: profile.clientCapabilities,
445
- clientInfo: profile.clientInfo
446
- }
447
- ),
1162
+ visible: visible("tools/list", options.tool.name),
1163
+ isVisible: isEnabled(options.annotations),
448
1164
  handle: (call, invocation) =>
449
- provideInvocationContext(options.handle(call.arguments), invocation).pipe(
1165
+ invoke(options.handle(call.arguments), invocation, {
1166
+ method: "tools/call",
1167
+ target: call.name,
1168
+ payload: call
1169
+ }).pipe(
450
1170
  Effect.catchTags({
451
1171
  InternalError: (error) =>
452
1172
  Effect.fail(
@@ -481,12 +1201,14 @@ export class McpServer extends Context.Service<McpServer, {
481
1201
  request,
482
1202
  McpProtocolInternal.invocationFromClient(client)
483
1203
  ).pipe(
484
- Effect.mapError((error) =>
485
- new InvalidParams({
486
- message: error._tag === "ToolNotFound"
487
- ? `Tool '${error.name}' not found`
488
- : error.message
489
- })
1204
+ Effect.catch((error) =>
1205
+ error._tag === "RequestRejected" ? rejectedError(error) : Effect.fail(
1206
+ new InvalidParams({
1207
+ message: error._tag === "ToolNotFound"
1208
+ ? `Tool '${error.name}' not found`
1209
+ : error.message
1210
+ })
1211
+ )
490
1212
  )
491
1213
  )
492
1214
  if (result._tag === "InputRequired") {
@@ -507,80 +1229,87 @@ export class McpServer extends Context.Service<McpServer, {
507
1229
  } else {
508
1230
  resources[existingIndex] = options
509
1231
  }
1232
+ const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
510
1233
  yield* internalCore.resources.register({
511
1234
  descriptor: options.resource,
512
- isVisible: (profile) => {
513
- const enabledWhen = Context.getOrUndefined(options.annotations, EnabledWhen)
514
- return enabledWhen === undefined || enabledWhen({
515
- protocolVersion: profile.protocolVersion,
516
- capabilities: profile.clientCapabilities,
517
- clientInfo: profile.clientInfo
1235
+ visible: visible("resources/list", options.resource.uri),
1236
+ isVisible: isEnabled(options.annotations),
1237
+ read: (invocation) =>
1238
+ invoke(options.handle, invocation, {
1239
+ method: "resources/read",
1240
+ target: options.resource.uri,
1241
+ payload: { uri: options.resource.uri }
518
1242
  })
519
- },
520
- read: (invocation) => provideInvocationContext(options.handle, invocation)
521
1243
  })
522
1244
  yield* notifications.client["notifications/resources/list_changed"]({})
523
1245
  }),
524
- addResourceTemplate: Effect.fnUntraced(function*({ annotations, completions, handle, routerPath, template }) {
525
- const existingIndex = resourceTemplates.findIndex(({ template: current }) =>
526
- current.uriTemplate === template.uriTemplate
527
- )
528
- if (existingIndex === -1) {
529
- resourceTemplates.push({ template, annotations })
530
- } else {
531
- resourceTemplates[existingIndex] = { template, annotations }
532
- }
533
- const templateMatcher = makeUriMatcher<true>()
534
- templateMatcher.add(routerPath, true)
535
- yield* internalCore.resources.registerTemplate({
536
- descriptor: template,
537
- isVisible: (profile) => {
538
- const enabledWhen = Context.getOrUndefined(annotations, EnabledWhen)
539
- return enabledWhen === undefined || enabledWhen({
540
- protocolVersion: profile.protocolVersion,
541
- capabilities: profile.clientCapabilities,
542
- clientInfo: profile.clientInfo
543
- })
544
- },
545
- match: (uri) => {
546
- const match = templateMatcher.find(uri)
547
- if (match === undefined) {
548
- return undefined
549
- }
550
- const params: Array<string> = []
551
- for (const key of Object.keys(match.params)) {
552
- params[Number(key)] = match.params[key]!
553
- }
554
- return params
555
- },
556
- read: (uri, params, invocation) => provideInvocationContext(handle(uri, Array.from(params)), invocation)
557
- })
558
- for (const [param, handle] of Object.entries(completions)) {
559
- yield* internalCore.completions.register(
560
- `resource/${template.uriTemplate}/${param}`,
561
- (request, invocation) =>
562
- provideInvocationContext(handle(request.argument.value, request.context), invocation).pipe(
563
- Effect.map((result) => ({
564
- values: result.completion.values,
565
- total: result.completion.total,
566
- hasMore: result.completion.hasMore,
567
- metadata: result._meta
568
- }))
569
- )
1246
+ addResourceTemplate: Effect.fnUntraced(
1247
+ function*({ annotations, completions, handle, routerPath, services, template }) {
1248
+ const existingIndex = resourceTemplates.findIndex(({ template: current }) =>
1249
+ current.uriTemplate === template.uriTemplate
570
1250
  )
1251
+ if (existingIndex === -1) {
1252
+ resourceTemplates.push({ template, annotations })
1253
+ } else {
1254
+ resourceTemplates[existingIndex] = { template, annotations }
1255
+ }
1256
+ const { invoke, visible } = makeInvoke(services, globalMiddleware)
1257
+ const templateMatcher = makeUriMatcher<true>()
1258
+ templateMatcher.add(routerPath, true)
1259
+ yield* internalCore.resources.registerTemplate({
1260
+ descriptor: template,
1261
+ visible: visible("resources/templates/list", template.uriTemplate),
1262
+ isVisible: isEnabled(annotations),
1263
+ match: (uri) => {
1264
+ const match = templateMatcher.find(uri)
1265
+ if (match === undefined) {
1266
+ return undefined
1267
+ }
1268
+ const params: Array<string> = []
1269
+ for (const key of Object.keys(match.params)) {
1270
+ params[Number(key)] = match.params[key]!
1271
+ }
1272
+ return params
1273
+ },
1274
+ read: (uri, params, invocation) =>
1275
+ invoke(handle(uri, Array.from(params)), invocation, {
1276
+ method: "resources/read",
1277
+ target: uri,
1278
+ payload: { uri }
1279
+ })
1280
+ })
1281
+ for (const [param, handle] of Object.entries(completions)) {
1282
+ yield* internalCore.completions.register(
1283
+ `resource/${template.uriTemplate}/${param}`,
1284
+ (request, invocation) =>
1285
+ invoke(handle(request.argument.value, request.context), invocation, {
1286
+ method: "completion/complete",
1287
+ target: template.uriTemplate,
1288
+ payload: request
1289
+ }).pipe(
1290
+ Effect.map((result) => ({
1291
+ values: result.completion.values,
1292
+ total: result.completion.total,
1293
+ hasMore: result.completion.hasMore,
1294
+ metadata: result._meta
1295
+ }))
1296
+ )
1297
+ )
1298
+ }
1299
+ yield* notifications.client["notifications/resources/list_changed"]({})
571
1300
  }
572
- yield* notifications.client["notifications/resources/list_changed"]({})
573
- }),
1301
+ ),
574
1302
  findResource: Effect.fnUntraced(function*(uri) {
575
1303
  const client = yield* McpServerClient
576
1304
  return yield* internalCore.resources.read(
577
1305
  uri,
578
1306
  McpProtocolInternal.invocationFromClient(client)
579
1307
  ).pipe(
580
- Effect.catchTag(
581
- "ResourceNotFound",
582
- (error) => Effect.fail(new InvalidParams({ message: `Resource '${error.uri}' not found` }))
583
- )
1308
+ Effect.catchTags({
1309
+ ResourceNotFound: (error) =>
1310
+ Effect.fail(new InvalidParams({ message: `Resource '${error.uri}' not found` })),
1311
+ RequestRejected: rejectedError
1312
+ })
584
1313
  )
585
1314
  }),
586
1315
  get prompts() {
@@ -593,18 +1322,17 @@ export class McpServer extends Context.Service<McpServer, {
593
1322
  } else {
594
1323
  prompts[existingIndex] = options
595
1324
  }
1325
+ const { invoke, visible } = makeInvoke(options.services, globalMiddleware)
596
1326
  yield* internalCore.prompts.register({
597
1327
  descriptor: options.prompt,
598
- isVisible: (profile) => {
599
- const enabledWhen = Context.getOrUndefined(options.annotations, EnabledWhen)
600
- return enabledWhen === undefined || enabledWhen({
601
- protocolVersion: profile.protocolVersion,
602
- capabilities: profile.clientCapabilities,
603
- clientInfo: profile.clientInfo
604
- })
605
- },
1328
+ visible: visible("prompts/list", options.prompt.name),
1329
+ isVisible: isEnabled(options.annotations),
606
1330
  get: (params, invocation) =>
607
- provideInvocationContext(options.handle(params), invocation).pipe(
1331
+ invoke(options.handle(params), invocation, {
1332
+ method: "prompts/get",
1333
+ target: options.prompt.name,
1334
+ payload: { name: options.prompt.name, arguments: params }
1335
+ }).pipe(
608
1336
  Effect.map((result) =>
609
1337
  Predicate.isTagged(result, "InputRequired")
610
1338
  ? McpCore.OperationOutcome.InputRequired(result)
@@ -616,7 +1344,11 @@ export class McpServer extends Context.Service<McpServer, {
616
1344
  yield* internalCore.completions.register(
617
1345
  `prompt/${options.prompt.name}/${param}`,
618
1346
  (request, invocation) =>
619
- provideInvocationContext(handle(request.argument.value, request.context), invocation).pipe(
1347
+ invoke(handle(request.argument.value, request.context), invocation, {
1348
+ method: "completion/complete",
1349
+ target: options.prompt.name,
1350
+ payload: request
1351
+ }).pipe(
620
1352
  Effect.map((result) => ({
621
1353
  values: result.completion.values,
622
1354
  total: result.completion.total,
@@ -635,7 +1367,10 @@ export class McpServer extends Context.Service<McpServer, {
635
1367
  params ?? {},
636
1368
  McpProtocolInternal.invocationFromClient(client)
637
1369
  ).pipe(
638
- Effect.catchTag("PromptNotFound", () => new InvalidParams({ message: `Prompt '${name}' not found` }))
1370
+ Effect.catchTags({
1371
+ PromptNotFound: () => new InvalidParams({ message: `Prompt '${name}' not found` }),
1372
+ RequestRejected: rejectedError
1373
+ })
639
1374
  )
640
1375
  return outcome._tag === "Complete"
641
1376
  ? outcome.value
@@ -650,7 +1385,9 @@ export class McpServer extends Context.Service<McpServer, {
650
1385
  : { type: "prompt", name: ref.name },
651
1386
  argument: complete.argument,
652
1387
  context: complete.context
653
- }, McpProtocolInternal.invocationFromClient(client))
1388
+ }, McpProtocolInternal.invocationFromClient(client)).pipe(
1389
+ Effect.catchTag("RequestRejected", rejectedError)
1390
+ )
654
1391
  return {
655
1392
  _meta: result.metadata,
656
1393
  completion: {
@@ -661,17 +1398,28 @@ export class McpServer extends Context.Service<McpServer, {
661
1398
  }
662
1399
  })
663
1400
  })
664
- internalState.set(service, { core: internalCore, notifications: notificationsQueue, notificationDelivery })
1401
+ internalState.set(service, {
1402
+ core: internalCore,
1403
+ notifications: notificationsQueue,
1404
+ notificationDelivery,
1405
+ globalMiddleware
1406
+ })
665
1407
  return service
666
1408
  })
667
1409
 
668
1410
  /**
669
- * Layer that provides the MCP server and client services.
1411
+ * Layer that provides the MCP server service.
1412
+ *
1413
+ * **Details**
1414
+ *
1415
+ * It doesn't run a transport or discharge request-level dependencies. Use it
1416
+ * to call registrations in process, providing their request-level
1417
+ * dependencies with MCP middleware.
670
1418
  *
671
1419
  * @stability unstable
672
1420
  * @since 4.0.0
673
1421
  */
674
- static readonly layer: Layer.Layer<McpServer | McpServerClient> = Layer.effect(McpServer)(McpServer.make) as any
1422
+ static readonly layer: Layer.Layer<McpServer> = Layer.effect(McpServer)(McpServer.make)
675
1423
  }
676
1424
 
677
1425
  const MCP_SESSION_ID_HEADER = "mcp-session-id"
@@ -693,6 +1441,82 @@ class McpClientKey extends Data.Class<{
693
1441
  readonly profile: McpCore.NegotiatedProtocolProfile<string>
694
1442
  }> {}
695
1443
 
1444
+ /**
1445
+ * A client cache hint for one kind of `v2026_07_28` result.
1446
+ *
1447
+ * **Details**
1448
+ *
1449
+ * `ttl` is how long a client may treat the result as fresh. It is sent as a
1450
+ * whole number of milliseconds, rounded down, so it must be finite,
1451
+ * nonnegative and at most `Number.MAX_SAFE_INTEGER` milliseconds. Only
1452
+ * `"private"` scope is supported, so shared caches must not store the result.
1453
+ *
1454
+ * @stability unstable
1455
+ * @category models
1456
+ * @since 4.1.0
1457
+ */
1458
+ export interface CacheHint {
1459
+ readonly ttl: Duration.Input
1460
+ readonly cacheScope: "private"
1461
+ }
1462
+
1463
+ /**
1464
+ * Client cache hints for `v2026_07_28` discovery and list results.
1465
+ *
1466
+ * **Details**
1467
+ *
1468
+ * Each entry sets the freshness and `cacheScope` of one result kind:
1469
+ * `server/discover`, `tools/list`, `resources/list`,
1470
+ * `resources/templates/list` and `prompts/list`. Omitted entries, and
1471
+ * `resources/read` results, keep `{ ttlMs: 0, cacheScope: "private" }`.
1472
+ * Earlier protocol revisions have no cache hints and ignore this option.
1473
+ *
1474
+ * These are hints for clients. The server does not cache results, and
1475
+ * visibility and invocation checks still run on every request.
1476
+ *
1477
+ * **Gotchas**
1478
+ *
1479
+ * A positive `ttl` lets a client keep showing a list after registrations or
1480
+ * per-request visibility change, until the hint expires. Private scope does
1481
+ * not key a client's cache by user, so a client shared between users can
1482
+ * reuse one user's list for another.
1483
+ *
1484
+ * @stability unstable
1485
+ * @category models
1486
+ * @since 4.1.0
1487
+ */
1488
+ export interface CacheHints {
1489
+ readonly discover?: CacheHint | undefined
1490
+ readonly tools?: CacheHint | undefined
1491
+ readonly resources?: CacheHint | undefined
1492
+ readonly resourceTemplates?: CacheHint | undefined
1493
+ readonly prompts?: CacheHint | undefined
1494
+ }
1495
+
1496
+ // Converts each hint to the wire's nonnegative integer `ttlMs` once, when the server is built.
1497
+ const normalizeCacheHints = (
1498
+ cacheHints: CacheHints | undefined
1499
+ ): Effect.Effect<McpProtocolInternal.CacheHints | undefined, Cause.IllegalArgumentError> => {
1500
+ if (cacheHints === undefined) return Effect.succeed(undefined)
1501
+ const normalized: Record<string, { readonly ttlMs: number; readonly cacheScope: "private" }> = {}
1502
+ for (const [name, hint] of Object.entries(cacheHints)) {
1503
+ if (hint === undefined) continue
1504
+ const ttlMs = Option.match(Duration.fromInput(hint.ttl), {
1505
+ onNone: () => NaN,
1506
+ onSome: (ttl) => Math.floor(Duration.toMillis(ttl))
1507
+ })
1508
+ if (!Number.isSafeInteger(ttlMs) || ttlMs < 0 || hint.cacheScope !== "private") {
1509
+ return Effect.fail(
1510
+ new Cause.IllegalArgumentError(
1511
+ `McpServer cacheHints.${name} must have a finite, nonnegative ttl and a "private" cacheScope`
1512
+ )
1513
+ )
1514
+ }
1515
+ normalized[name] = { ttlMs, cacheScope: "private" }
1516
+ }
1517
+ return Effect.succeed(normalized)
1518
+ }
1519
+
696
1520
  /**
697
1521
  * Runs an MCP server over the current `RpcServer.Protocol`.
698
1522
  *
@@ -715,6 +1539,7 @@ export const run: (options: {
715
1539
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
716
1540
  readonly protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
717
1541
  readonly extensions?: ServerExtensions | undefined
1542
+ readonly cacheHints?: CacheHints | undefined
718
1543
  }) => Effect.Effect<
719
1544
  never,
720
1545
  Cause.IllegalArgumentError,
@@ -728,12 +1553,14 @@ export const run: (options: {
728
1553
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
729
1554
  readonly protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
730
1555
  readonly extensions?: ServerExtensions | undefined
1556
+ readonly cacheHints?: CacheHints | undefined
731
1557
  }) {
1558
+ const cacheHints = yield* normalizeCacheHints(options.cacheHints)
732
1559
  const runtimeOption = yield* Effect.serviceOption(McpRuntime.ServerRuntime)
733
1560
  const runtime = Option.isSome(runtimeOption)
734
1561
  ? runtimeOption.value
735
1562
  : yield* McpRuntime.make(options.protocols)
736
- return yield* runWithRuntime(options, runtime, "custom")
1563
+ return yield* runWithRuntime({ ...options, cacheHints }, runtime, "custom")
737
1564
  })
738
1565
 
739
1566
  const runWithRuntime = Effect.fnUntraced(function*(
@@ -745,6 +1572,7 @@ const runWithRuntime = Effect.fnUntraced(function*(
745
1572
  readonly websiteUrl?: string | undefined
746
1573
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
747
1574
  readonly extensions?: ServerExtensions | undefined
1575
+ readonly cacheHints?: McpProtocolInternal.CacheHints | undefined
748
1576
  readonly allowSubscriptions?: boolean | undefined
749
1577
  },
750
1578
  runtime: McpRuntime.ServerRuntimeShape,
@@ -1365,7 +2193,8 @@ const runWithRuntime = Effect.fnUntraced(function*(
1365
2193
  (requestContext?.clientId === clientId ? requestHeaders : undefined) ??
1366
2194
  clientStates.get(clientId)?.sessionHeaders ?? Headers.empty,
1367
2195
  notification,
1368
- defaultLogLevel
2196
+ defaultLogLevel,
2197
+ listChangeRevision
1369
2198
  )
1370
2199
  ) {
1371
2200
  return
@@ -1412,6 +2241,37 @@ const runWithRuntime = Effect.fnUntraced(function*(
1412
2241
  )
1413
2242
  }, Effect.scoped)
1414
2243
 
2244
+ type StatefulProtocolAdapter = McpProtocol.ProtocolAdapter<
2245
+ McpProtocol.ProtocolVersion,
2246
+ McpProtocol.StatefulRuntimeDescriptor
2247
+ >
2248
+
2249
+ /**
2250
+ * Request-level services supplied by a transport.
2251
+ *
2252
+ * **Details**
2253
+ *
2254
+ * Every transport supplies `Scope`. `McpServerClient` is supplied only when
2255
+ * every configured protocol is known to be sessionful: a `v2026_07_28` request
2256
+ * has no client session, and a protocol array widened to `ProtocolAdapter`
2257
+ * might contain one. HTTP transports also supply `HttpServerRequest`.
2258
+ *
2259
+ * @stability unstable
2260
+ * @category utility types
2261
+ * @since 4.0.0
2262
+ */
2263
+ export type ProvidedServices<
2264
+ Protocols extends ReadonlyArray<McpProtocol.ProtocolAdapter>,
2265
+ Http extends boolean = false
2266
+ > =
2267
+ | Scope.Scope
2268
+ | (Protocols[number] extends StatefulProtocolAdapter ? McpServerClient : never)
2269
+ | (Http extends true ? HttpServerRequest.HttpServerRequest : never)
2270
+
2271
+ type RemainingRequestServices<RR, Provided> = Exclude<McpRequest.Only<"Requires", RR>, Provided>
2272
+
2273
+ type RegistrationServices<RR> = Exclude<McpRequest.Without<RR>, McpServer>
2274
+
1415
2275
  /**
1416
2276
  * Creates a layer that starts an MCP server over an existing
1417
2277
  * `RpcServer.Protocol` and provides `McpServer`. Request handlers receive
@@ -1430,6 +2290,11 @@ const runWithRuntime = Effect.fnUntraced(function*(
1430
2290
  * `McpServer.layer`, so registration layers can use the `McpServer` service
1431
2291
  * while the server is running.
1432
2292
  *
2293
+ * Pass registration layers as `registrations` to build them before the server
2294
+ * reads its first request. The transport discharges the request-level
2295
+ * dependencies it supplies (see `ProvidedServices`); any other `McpRequest`
2296
+ * marker stays in the layer's requirements and must be met by MCP middleware.
2297
+ *
1433
2298
  * **Gotchas**
1434
2299
  *
1435
2300
  * Unlike `layerStdio` and `layerHttp`, this layer does not install a concrete
@@ -1443,19 +2308,32 @@ const runWithRuntime = Effect.fnUntraced(function*(
1443
2308
  * @category layers
1444
2309
  * @since 4.0.0
1445
2310
  */
1446
- export const layer = (options: {
2311
+ export const layer = <
2312
+ const Protocols extends Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>,
2313
+ RA = never,
2314
+ RE = never,
2315
+ RR = never
2316
+ >(options: {
1447
2317
  readonly name: string
1448
2318
  readonly version: string
1449
2319
  readonly instructions?: string | undefined
1450
2320
  readonly description?: string | undefined
1451
2321
  readonly websiteUrl?: string | undefined
1452
2322
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
1453
- readonly protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
2323
+ readonly protocols: Protocols
1454
2324
  readonly extensions?: ServerExtensions | undefined
1455
- }): Layer.Layer<McpServer | McpServerClient, Cause.IllegalArgumentError, RpcServer.Protocol> =>
2325
+ readonly cacheHints?: CacheHints | undefined
2326
+ readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
2327
+ }): Layer.Layer<
2328
+ McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols>>,
2329
+ Cause.IllegalArgumentError | RE,
2330
+ | RpcServer.Protocol
2331
+ | RegistrationServices<RR>
2332
+ | McpRequest.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols>>>
2333
+ > =>
1456
2334
  layerWithRuntime(options, "custom").pipe(
1457
2335
  Layer.provide(McpRuntime.layer(options.protocols))
1458
- )
2336
+ ) as any
1459
2337
 
1460
2338
  const layerWithRuntime = (options: {
1461
2339
  readonly name: string
@@ -1465,18 +2343,18 @@ const layerWithRuntime = (options: {
1465
2343
  readonly websiteUrl?: string | undefined
1466
2344
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
1467
2345
  readonly extensions?: ServerExtensions | undefined
2346
+ readonly cacheHints?: CacheHints | undefined
1468
2347
  readonly allowSubscriptions?: boolean | undefined
1469
- }, transport: "custom" | "http" | "stdio"): Layer.Layer<
1470
- McpServer | McpServerClient,
1471
- never,
1472
- RpcServer.Protocol | McpRuntime.ServerRuntime
1473
- > =>
2348
+ readonly registrations?: Layer.Layer<any, any, any> | undefined
2349
+ }, transport: "custom" | "http" | "stdio") =>
1474
2350
  Layer.effectDiscard(
1475
2351
  Effect.gen(function*() {
2352
+ const cacheHints = yield* normalizeCacheHints(options.cacheHints)
1476
2353
  const runtime = yield* McpRuntime.ServerRuntime
1477
- yield* Effect.forkScoped(runWithRuntime(options, runtime, transport))
2354
+ yield* Effect.forkScoped(runWithRuntime({ ...options, cacheHints }, runtime, transport))
1478
2355
  })
1479
2356
  ).pipe(
2357
+ Layer.provide(options.registrations ?? Layer.empty),
1480
2358
  Layer.provideMerge(McpServer.layer)
1481
2359
  )
1482
2360
 
@@ -1495,6 +2373,11 @@ const layerWithRuntime = (options: {
1495
2373
  * `McpRequestContext` and legacy `McpServerClient` services to handlers, and
1496
2374
  * requires `Stdio`.
1497
2375
  *
2376
+ * Pass registration layers as `registrations` to build them before the server
2377
+ * reads its first request. The transport discharges the request-level
2378
+ * dependencies it supplies (see `ProvidedServices`); any other `McpRequest`
2379
+ * marker stays in the layer's requirements and must be met by MCP middleware.
2380
+ *
1498
2381
  * @see {@link layer} for running over an existing `RpcServer.Protocol`
1499
2382
  * @see {@link layerHttp} for the single-endpoint HTTP transport
1500
2383
  *
@@ -1502,16 +2385,29 @@ const layerWithRuntime = (options: {
1502
2385
  * @category layers
1503
2386
  * @since 4.0.0
1504
2387
  */
1505
- export const layerStdio = (options: {
2388
+ export const layerStdio = <
2389
+ const Protocols extends Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>,
2390
+ RA = never,
2391
+ RE = never,
2392
+ RR = never
2393
+ >(options: {
1506
2394
  readonly name: string
1507
2395
  readonly version: string
1508
2396
  readonly instructions?: string | undefined
1509
2397
  readonly description?: string | undefined
1510
2398
  readonly websiteUrl?: string | undefined
1511
2399
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
1512
- readonly protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
2400
+ readonly protocols: Protocols
1513
2401
  readonly extensions?: ServerExtensions | undefined
1514
- }): Layer.Layer<McpServer | McpServerClient, Cause.IllegalArgumentError, Stdio> =>
2402
+ readonly cacheHints?: CacheHints | undefined
2403
+ readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
2404
+ }): Layer.Layer<
2405
+ McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols>>,
2406
+ Cause.IllegalArgumentError | RE,
2407
+ | Stdio
2408
+ | RegistrationServices<RR>
2409
+ | McpRequest.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols>>>
2410
+ > =>
1515
2411
  layerWithRuntime(options, "stdio").pipe(
1516
2412
  Layer.provide(McpRuntime.layer(options.protocols)),
1517
2413
  Layer.provide(RpcServer.layerProtocolStdio),
@@ -1519,7 +2415,7 @@ export const layerStdio = (options: {
1519
2415
  RpcSerialization.RpcSerialization,
1520
2416
  mcpStdioSerialization(options.protocols)
1521
2417
  ))
1522
- )
2418
+ ) as any
1523
2419
 
1524
2420
  const mcpStdioSerialization = (
1525
2421
  protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
@@ -1621,6 +2517,13 @@ const mcpStdioSerialization = (
1621
2517
  * serverless hosts where execution must belong to each request, use
1622
2518
  * `layerHttpRequestScoped` instead.
1623
2519
  *
2520
+ * Pass registration layers as `registrations` to build them before the
2521
+ * endpoint serves its first request. The transport discharges the
2522
+ * request-level dependencies it supplies (see `ProvidedServices`) and converts
2523
+ * the remaining `McpRequest` markers into `HttpRouter.Request` markers, so
2524
+ * `HttpRouter.middleware` can provide them, for example to authenticate the
2525
+ * request and resolve the current user.
2526
+ *
1624
2527
  * `layerHttp` always implements the single-endpoint Streamable HTTP topology.
1625
2528
  * Using `v2024_11_05` here is a custom compatibility transport for that
1626
2529
  * revision's schema. It does not implement the historical two-endpoint
@@ -1638,7 +2541,12 @@ const mcpStdioSerialization = (
1638
2541
  * @category layers
1639
2542
  * @since 4.0.0
1640
2543
  */
1641
- export const layerHttp = (options: {
2544
+ export const layerHttp = <
2545
+ const Protocols extends Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>,
2546
+ RA = never,
2547
+ RE = never,
2548
+ RR = never
2549
+ >(options: {
1642
2550
  readonly name: string
1643
2551
  readonly version: string
1644
2552
  readonly instructions?: string | undefined
@@ -1646,18 +2554,26 @@ export const layerHttp = (options: {
1646
2554
  readonly websiteUrl?: string | undefined
1647
2555
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
1648
2556
  readonly path: HttpRouter.PathInput
1649
- readonly protocols: Arr.NonEmptyReadonlyArray<McpProtocol.ProtocolAdapter>
2557
+ readonly protocols: Protocols
1650
2558
  readonly extensions?: ServerExtensions | undefined
2559
+ readonly cacheHints?: CacheHints | undefined
1651
2560
  readonly allowedOrigins?: ReadonlyArray<string> | undefined
1652
2561
  readonly allowSessionTermination?: boolean | undefined
1653
2562
  readonly allowSubscriptions?: boolean | undefined
1654
- }): Layer.Layer<McpServer | McpServerClient, Cause.IllegalArgumentError, HttpRouter.HttpRouter> => {
2563
+ readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
2564
+ }): Layer.Layer<
2565
+ McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols, true>>,
2566
+ Cause.IllegalArgumentError | RE,
2567
+ | HttpRouter.HttpRouter
2568
+ | RegistrationServices<RR>
2569
+ | HttpRouter.Request.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols, true>>>
2570
+ > => {
1655
2571
  const runtime = McpRuntime.layer(options.protocols)
1656
2572
  return layerWithRuntime(options, "http").pipe(
1657
2573
  Layer.provide(layerMcpProtocolHttp(options)),
1658
2574
  Layer.provide(runtime),
1659
2575
  Layer.provide(RpcSerialization.layerJsonRpc())
1660
- )
2576
+ ) as any
1661
2577
  }
1662
2578
 
1663
2579
  /**
@@ -1688,13 +2604,24 @@ export const layerHttp = (options: {
1688
2604
  * Configuring a sessionful protocol through an untyped caller fails layer
1689
2605
  * construction with `IllegalArgumentError`.
1690
2606
  *
2607
+ * Registrations passed as `registrations` are built once, before the routes
2608
+ * are added, and shared by every POST. Remaining `McpRequest` markers become
2609
+ * `HttpRouter.Request` markers, as with `layerHttp`.
2610
+ *
1691
2611
  * @see {@link layerHttp} for the long-lived HTTP transport and HTTP admission policy
1692
2612
  *
1693
2613
  * @stability unstable
1694
2614
  * @category layers
1695
2615
  * @since 4.0.0
1696
2616
  */
1697
- export const layerHttpRequestScoped = (options: {
2617
+ export const layerHttpRequestScoped = <
2618
+ const Protocols extends Arr.NonEmptyReadonlyArray<
2619
+ McpProtocol.ProtocolAdapter<McpProtocol.ProtocolVersion, McpProtocol.StatelessRuntimeDescriptor>
2620
+ >,
2621
+ RA = never,
2622
+ RE = never,
2623
+ RR = never
2624
+ >(options: {
1698
2625
  readonly name: string
1699
2626
  readonly version: string
1700
2627
  readonly instructions?: string | undefined
@@ -1702,12 +2629,18 @@ export const layerHttpRequestScoped = (options: {
1702
2629
  readonly websiteUrl?: string | undefined
1703
2630
  readonly icons?: ReadonlyArray<McpSchema.Icon> | undefined
1704
2631
  readonly path: HttpRouter.PathInput
1705
- readonly protocols: Arr.NonEmptyReadonlyArray<
1706
- McpProtocol.ProtocolAdapter<McpProtocol.ProtocolVersion, McpProtocol.StatelessRuntimeDescriptor>
1707
- >
2632
+ readonly protocols: Protocols
1708
2633
  readonly extensions?: ServerExtensions | undefined
2634
+ readonly cacheHints?: CacheHints | undefined
1709
2635
  readonly allowedOrigins?: ReadonlyArray<string> | undefined
1710
- }): Layer.Layer<McpServer | McpServerClient, Cause.IllegalArgumentError, HttpRouter.HttpRouter> =>
2636
+ readonly registrations?: Layer.Layer<RA, RE, RR> | undefined
2637
+ }): Layer.Layer<
2638
+ McpServer | McpRequest.From<"Requires", ProvidedServices<Protocols, true>>,
2639
+ Cause.IllegalArgumentError | RE,
2640
+ | HttpRouter.HttpRouter
2641
+ | RegistrationServices<RR>
2642
+ | HttpRouter.Request.From<"Requires", RemainingRequestServices<RR, ProvidedServices<Protocols, true>>>
2643
+ > =>
1711
2644
  Layer.effectDiscard(Effect.gen(function*() {
1712
2645
  const runtime = yield* McpRuntime.ServerRuntime
1713
2646
  const stateful = runtime.protocols.find((protocol) => protocol.runtime._tag === "Stateful")
@@ -1716,6 +2649,7 @@ export const layerHttpRequestScoped = (options: {
1716
2649
  `McpServer.layerHttpRequestScoped does not support the sessionful MCP protocol ${stateful.protocolVersion}`
1717
2650
  )
1718
2651
  }
2652
+ const serverOptions = { ...options, cacheHints: yield* normalizeCacheHints(options.cacheHints) }
1719
2653
  const server = yield* McpServer
1720
2654
  const { core, notificationDelivery } = internalState.get(server)!
1721
2655
  // Subscriptions are disabled, so handlers hold no per-request state and
@@ -1726,7 +2660,7 @@ export const layerHttpRequestScoped = (options: {
1726
2660
  subscribeServerNotifications: Effect.die("Subscriptions are disabled for request-scoped MCP servers"),
1727
2661
  getListChangeRevision: () => notificationDelivery.listChangeRevision,
1728
2662
  defaultLogLevel: yield* CurrentLogLevel,
1729
- serverInfo: options
2663
+ serverInfo: serverOptions
1730
2664
  }) as Effect.Effect<Context.Context<never>>)
1731
2665
  yield* Effect.acquireRelease(
1732
2666
  Effect.sync(() => {
@@ -1746,7 +2680,7 @@ export const layerHttpRequestScoped = (options: {
1746
2680
  Effect.provideService(RpcSerialization.RpcSerialization, mcpHttpSerialization)
1747
2681
  )
1748
2682
  const notifications = yield* Queue.make<QueuedServerNotification>()
1749
- yield* runWithRuntime(options, runtime, "http", { notifications, handlers }).pipe(
2683
+ yield* runWithRuntime(serverOptions, runtime, "http", { notifications, handlers }).pipe(
1750
2684
  Effect.provideService(RpcServer.Protocol, protocol),
1751
2685
  Effect.provideService(McpServer, server),
1752
2686
  Effect.forkScoped({ startImmediately: true })
@@ -1755,9 +2689,10 @@ export const layerHttpRequestScoped = (options: {
1755
2689
  })
1756
2690
  )
1757
2691
  })).pipe(
2692
+ Layer.provide(options.registrations ?? Layer.empty),
1758
2693
  Layer.provideMerge(McpServer.layer),
1759
2694
  Layer.provide(McpRuntime.layer(options.protocols))
1760
- )
2695
+ ) as any
1761
2696
 
1762
2697
  const layerMcpProtocolHttp = (options: {
1763
2698
  readonly path: HttpRouter.PathInput
@@ -2026,20 +2961,50 @@ const toolErrorResult = (message: string): CallToolResult =>
2026
2961
  const toolResultContent = (encoded: unknown): CallToolResult["content"] =>
2027
2962
  encoded === undefined ? [] : [{ type: "text", text: JSON.stringify(encoded) }]
2028
2963
 
2964
+ /**
2965
+ * The requirements of a toolkit registration.
2966
+ *
2967
+ * **Details**
2968
+ *
2969
+ * Services a tool declares with `dependencies` or `Tool.addDependency` are
2970
+ * request-level: they are carried as `McpRequest<"Requires", S>` markers and
2971
+ * must be provided by MCP middleware or the transport. Parameter decoding and
2972
+ * result encoding services are required when the toolkit is registered,
2973
+ * unless a tool also declares them.
2974
+ *
2975
+ * @stability unstable
2976
+ * @category utility types
2977
+ * @since 4.0.0
2978
+ */
2979
+ export type ToolkitRequirements<Tools extends Record<string, Tool.Any>> = 0 extends
2980
+ (1 & Tool.Requirements<Tools[keyof Tools]>) ? any :
2981
+ | Tool.HandlersFor<Tools>
2982
+ | RegistrationRequirements<Tool.SchemaServices<Tools[keyof Tools]>, Tool.Requirements<Tools[keyof Tools]>>
2983
+
2984
+ type RegistrationRequirements<SchemaServices, RequestServices> =
2985
+ | McpServer
2986
+ | Exclude<SchemaServices, RequestServices | McpRequestContext>
2987
+ | McpRequest.From<"Requires", Exclude<RequestServices, McpRequestContext>>
2988
+
2029
2989
  /**
2030
2990
  * Registers a `Toolkit` with the `McpServer`.
2031
2991
  *
2992
+ * **Details**
2993
+ *
2994
+ * The MCP middleware in the current context, provided with
2995
+ * `Effect.provide(middleware.layer)`, runs around every call to the toolkit.
2996
+ *
2997
+ * @see {@link ToolkitRequirements} for which services are request-level
2998
+ *
2032
2999
  * @stability unstable
2033
3000
  * @category handlers
2034
3001
  * @since 4.0.0
2035
3002
  */
2036
3003
  export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
2037
3004
  toolkit: Toolkit.Toolkit<Tools>
2038
- ) => Effect.Effect<
2039
- void,
2040
- never,
2041
- McpServer | Tool.HandlersFor<Tools> | Exclude<Tool.HandlerServices<Tools[keyof Tools]>, McpRequestContext>
2042
- > = Effect.fnUntraced(function*<Tools extends Record<string, Tool.Any>>(
3005
+ ) => Effect.Effect<void, never, ToolkitRequirements<Tools>> = Effect.fnUntraced(function*<
3006
+ Tools extends Record<string, Tool.Any>
3007
+ >(
2043
3008
  toolkit: Toolkit.Toolkit<Tools>
2044
3009
  ) {
2045
3010
  const registry = yield* McpServer
@@ -2058,19 +3023,14 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
2058
3023
  }
2059
3024
  return Context.makeUnsafe(services)
2060
3025
  }))
2061
- const services = omitRequestServices(
2062
- yield* Effect.context<
2063
- Exclude<Tool.HandlerServices<Tools[keyof Tools]>, McpRequestContext>
2064
- >()
2065
- )
2066
- const reportCause = (cause: Cause.Cause<unknown>) => Effect.provideContext(ErrorReporter.report(cause), services)
3026
+ const services = yield* Effect.context<never>()
2067
3027
  // Interruption propagates; anything else is logged, reported and scrubbed.
2068
3028
  const internalToolError = (cause: Cause.Cause<unknown>) => {
2069
3029
  const failure = Cause.findFail(cause)
2070
3030
  return Result.isFailure(failure) && !Cause.hasDies(cause)
2071
3031
  ? Effect.failCause(failure.failure)
2072
3032
  : Effect.logError(cause).pipe(
2073
- Effect.andThen(reportCause(cause)),
3033
+ Effect.andThen(ErrorReporter.report(cause)),
2074
3034
  Effect.as(toolErrorResult(INTERNAL_TOOL_ERROR_MESSAGE))
2075
3035
  )
2076
3036
  }
@@ -2168,10 +3128,10 @@ export const registerToolkit: <Tools extends Record<string, Tool.Any>>(
2168
3128
  })
2169
3129
  )
2170
3130
  ),
2171
- Effect.catchCause(handleCause),
2172
- Effect.provideContext(services as Context.Context<Tool.HandlerServices<Tools[keyof Tools]>>)
2173
- )
2174
- }
3131
+ Effect.catchCause(handleCause)
3132
+ ) as Effect.Effect<CallToolResult, InvalidParams, never>
3133
+ },
3134
+ services
2175
3135
  })
2176
3136
  }
2177
3137
  for (const registration of registrations) {
@@ -2201,7 +3161,14 @@ const toolJsonSchema = (schema: Schema.Constraint, strict: boolean): JsonSchema.
2201
3161
  }
2202
3162
 
2203
3163
  /**
2204
- * Registers an `AiToolkit` with the `McpServer`.
3164
+ * Creates a layer that registers a `Toolkit` with the `McpServer`.
3165
+ *
3166
+ * **Details**
3167
+ *
3168
+ * The layer requires `McpServer`. Pass it to a transport through the
3169
+ * `registrations` option, or provide the transport layer to it.
3170
+ *
3171
+ * @see {@link ToolkitRequirements} for which services are request-level
2205
3172
  *
2206
3173
  * @stability unstable
2207
3174
  * @category layers
@@ -2209,14 +3176,7 @@ const toolJsonSchema = (schema: Schema.Constraint, strict: boolean): JsonSchema.
2209
3176
  */
2210
3177
  export const toolkit = <Tools extends Record<string, Tool.Any>>(
2211
3178
  toolkit: Toolkit.Toolkit<Tools>
2212
- ): Layer.Layer<
2213
- never,
2214
- never,
2215
- Tool.HandlersFor<Tools> | Exclude<Tool.HandlerServices<Tools[keyof Tools]>, McpRequestContext>
2216
- > =>
2217
- Layer.effectDiscard(registerToolkit(toolkit)).pipe(
2218
- Layer.provide(McpServer.layer)
2219
- )
3179
+ ): Layer.Layer<never, never, ToolkitRequirements<Tools>> => Layer.effectDiscard(registerToolkit(toolkit))
2220
3180
 
2221
3181
  /**
2222
3182
  * Utility type that validates a completion-handler record against the allowed
@@ -2272,6 +3232,90 @@ export type ResourceCompletions<Schemas extends ReadonlyArray<Schema.Constraint>
2272
3232
  ) => Effect.Effect<Array<Schemas[K]["Type"]>, any, any>
2273
3233
  }
2274
3234
 
3235
+ // Leave defects and interruption to makeInvoke; convert only expected failures.
3236
+ const handlerFailureToInternalError = (cause: Cause.Cause<unknown>): Effect.Effect<never, InternalError> =>
3237
+ Cause.hasDies(cause) || Cause.hasInterrupts(cause)
3238
+ ? Effect.failCause(cause as Cause.Cause<never>)
3239
+ : Effect.fail(new InternalError({ message: Cause.prettyErrors(cause)[0].message }))
3240
+
3241
+ const completionHandler = (
3242
+ handle: (input: string, context: CompletionContext) => Effect.Effect<any, any, any>,
3243
+ encodeValues: (values: unknown) => Effect.Effect<ReadonlyArray<unknown>, any, any>
3244
+ ) =>
3245
+ (input: string, context: CompletionContext): Effect.Effect<CompleteResult, InternalError> =>
3246
+ handle(input, context).pipe(
3247
+ Effect.flatMap(encodeValues),
3248
+ Effect.map((values) => ({
3249
+ completion: {
3250
+ values: values as Array<string>,
3251
+ total: values.length,
3252
+ hasMore: false
3253
+ }
3254
+ })),
3255
+ Effect.catchCause(handlerFailureToInternalError)
3256
+ ) as any
3257
+
3258
+ type TemplateParamKey<Schemas extends ReadonlyArray<Schema.Constraint>, K extends keyof Schemas> = Schemas[K] extends
3259
+ Param<infer Id, infer _S> ? Id : `param${K & string}`
3260
+
3261
+ type TemplateSchemaServices<Schemas extends ReadonlyArray<Schema.Constraint>, Completions> =
3262
+ | Schemas[number]["DecodingServices"]
3263
+ | {
3264
+ [K in Extract<keyof Schemas, `${number}`>]: TemplateParamKey<Schemas, K> extends keyof Completions
3265
+ ? Schemas[K]["EncodingServices"]
3266
+ : never
3267
+ }[Extract<keyof Schemas, `${number}`>]
3268
+
3269
+ type PromptSchemaServices<Params extends Schema.Struct.Fields, Completions> =
3270
+ | Schema.Struct.DecodingServices<Params>
3271
+ | Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
3272
+
3273
+ /**
3274
+ * The requirements of a resource registration: the content handler's services
3275
+ * are request-level.
3276
+ *
3277
+ * @stability unstable
3278
+ * @category utility types
3279
+ * @since 4.0.0
3280
+ */
3281
+ export type ResourceRequirements<R> = RegistrationRequirements<never, R>
3282
+
3283
+ /**
3284
+ * The requirements of a resource template registration.
3285
+ *
3286
+ * **Details**
3287
+ *
3288
+ * Services read by the content and completion handlers are request-level.
3289
+ * Parameter decoding services, and the encoding services of parameters with a
3290
+ * completion handler, are required when the template is registered, unless a
3291
+ * handler also reads them.
3292
+ *
3293
+ * @stability unstable
3294
+ * @category utility types
3295
+ * @since 4.0.0
3296
+ */
3297
+ export type ResourceTemplateRequirements<Schemas extends ReadonlyArray<Schema.Constraint>, R, Completions> =
3298
+ RegistrationRequirements<TemplateSchemaServices<Schemas, Completions>, R | CompletionServices<Completions>>
3299
+
3300
+ /**
3301
+ * The requirements of a prompt registration.
3302
+ *
3303
+ * **Details**
3304
+ *
3305
+ * Services read by the content and completion handlers are request-level.
3306
+ * Parameter decoding services, and the encoding services of parameters with a
3307
+ * completion handler, are required when the prompt is registered, unless a
3308
+ * handler also reads them.
3309
+ *
3310
+ * @stability unstable
3311
+ * @category utility types
3312
+ * @since 4.0.0
3313
+ */
3314
+ export type PromptRequirements<Params extends Schema.Struct.Fields, R, Completions> = RegistrationRequirements<
3315
+ PromptSchemaServices<Params, Completions>,
3316
+ R | CompletionServices<Completions>
3317
+ >
3318
+
2275
3319
  /**
2276
3320
  * Registers an MCP resource or resource template from an Effect program.
2277
3321
  *
@@ -2306,7 +3350,7 @@ export const registerResource: {
2306
3350
  >
2307
3351
  readonly annotations?: Context.Context<never> | undefined
2308
3352
  }
2309
- ): Effect.Effect<void, never, Exclude<R, McpRequestContext> | McpServer>
3353
+ ): Effect.Effect<void, never, ResourceRequirements<R>>
2310
3354
  /**
2311
3355
  * Registers an MCP resource or resource template from an Effect program.
2312
3356
  *
@@ -2333,18 +3377,7 @@ export const registerResource: {
2333
3377
  R
2334
3378
  >
2335
3379
  readonly annotations?: Context.Context<never> | undefined
2336
- }) => Effect.Effect<
2337
- void,
2338
- never,
2339
- | Exclude<
2340
- | Schemas[number]["DecodingServices"]
2341
- | Schemas[number]["EncodingServices"]
2342
- | R
2343
- | CompletionServices<Completions>,
2344
- McpRequestContext
2345
- >
2346
- | McpServer
2347
- >
3380
+ }) => Effect.Effect<void, never, ResourceTemplateRequirements<Schemas, R, Completions>>
2348
3381
  } = function() {
2349
3382
  if (arguments.length === 1) {
2350
3383
  const options = arguments[0] as {
@@ -2358,20 +3391,17 @@ export const registerResource: {
2358
3391
  readonly annotations?: Context.Context<never> | undefined
2359
3392
  }
2360
3393
  return Effect.gen(function*() {
2361
- const services = omitRequestServices(yield* Effect.context<any>())
3394
+ const services = yield* Effect.context<never>()
2362
3395
  const registry = yield* McpServer
2363
3396
  yield* registry.addResource({
2364
3397
  resource: new Resource({
2365
3398
  ...options,
2366
3399
  annotations: options
2367
3400
  }),
3401
+ services,
2368
3402
  handle: options.content.pipe(
2369
- Effect.provideContext(services),
2370
3403
  Effect.map((content) => resolveResourceContent(options.uri, content)),
2371
- Effect.catchCause((cause) => {
2372
- const prettyError = Cause.prettyErrors(cause)[0]
2373
- return Effect.fail(new InternalError({ message: prettyError.message }))
2374
- })
3404
+ Effect.catchCause(handlerFailureToInternalError)
2375
3405
  ),
2376
3406
  annotations: options.annotations ?? Context.empty()
2377
3407
  })
@@ -2405,7 +3435,7 @@ export const registerResource: {
2405
3435
  >
2406
3436
  readonly annotations?: Context.Context<never> | undefined
2407
3437
  }) {
2408
- const services = omitRequestServices(yield* Effect.context<any>())
3438
+ const services = yield* Effect.context<never>()
2409
3439
  const registry = yield* McpServer
2410
3440
  const decode = Schema.decodeUnknownEffect(schema)
2411
3441
  const template = new ResourceTemplate({
@@ -2421,32 +3451,13 @@ export const registerResource: {
2421
3451
  ) => Effect.Effect<CompleteResult, InternalError>
2422
3452
  > = Object.create(null)
2423
3453
  for (const [param, handle] of Object.entries(options.completion ?? {})) {
2424
- const encodeArray = Schema.encodeUnknownEffect(Schema.Array(params[param]))
2425
- const handler = (
2426
- input: string,
2427
- context: CompletionContext
2428
- ) =>
2429
- handle(input, context).pipe(
2430
- Effect.flatMap(encodeArray),
2431
- Effect.map((values) => ({
2432
- completion: {
2433
- values: values as Array<string>,
2434
- total: values.length,
2435
- hasMore: false
2436
- }
2437
- })),
2438
- Effect.catchCause((cause) => {
2439
- const prettyError = Cause.prettyErrors(cause)[0]
2440
- return Effect.fail(new InternalError({ message: prettyError.message }))
2441
- }),
2442
- Effect.provideContext(services)
2443
- )
2444
- completions[param] = handler
3454
+ completions[param] = completionHandler(handle, Schema.encodeUnknownEffect(Schema.Array(params[param])))
2445
3455
  }
2446
3456
  yield* registry.addResourceTemplate({
2447
3457
  template,
2448
3458
  routerPath,
2449
3459
  completions,
3460
+ services,
2450
3461
  annotations: options.annotations ?? Context.empty(),
2451
3462
  handle: (uri, params) =>
2452
3463
  decode(params).pipe(
@@ -2454,14 +3465,10 @@ export const registerResource: {
2454
3465
  Effect.flatMap((params: any) =>
2455
3466
  options.content(uri, ...params).pipe(
2456
3467
  Effect.map((content) => resolveResourceContent(uri, content)),
2457
- Effect.catchCause((cause) => {
2458
- const prettyError = Cause.prettyErrors(cause)[0]
2459
- return Effect.fail(new InternalError({ message: prettyError.message }))
2460
- })
3468
+ Effect.catchCause(handlerFailureToInternalError)
2461
3469
  )
2462
- ),
2463
- Effect.provideContext(services)
2464
- )
3470
+ )
3471
+ ) as Effect.Effect<ReadResourceResult, InvalidParams | InternalError>
2465
3472
  })
2466
3473
  })
2467
3474
  } as any
@@ -2469,7 +3476,15 @@ export const registerResource: {
2469
3476
  /**
2470
3477
  * Creates a layer that registers an MCP resource or resource template.
2471
3478
  *
3479
+ * **Details**
3480
+ *
3481
+ * Services read by the content and completion handlers are request-level, so
3482
+ * providing them with `Layer.provide` doesn't satisfy them. Read
3483
+ * construction-time services in an enclosing `Layer.unwrap` and close over
3484
+ * them, and provide per-request services with MCP middleware.
3485
+ *
2472
3486
  * @see {@link registerResource} for the Effect-level resource registration API
3487
+ * @see {@link middleware} for providing request-level dependencies
2473
3488
  *
2474
3489
  * @stability unstable
2475
3490
  * @category layers
@@ -2479,7 +3494,15 @@ export const resource: {
2479
3494
  /**
2480
3495
  * Creates a layer that registers an MCP resource or resource template.
2481
3496
  *
3497
+ * **Details**
3498
+ *
3499
+ * Services read by the content and completion handlers are request-level, so
3500
+ * providing them with `Layer.provide` doesn't satisfy them. Read
3501
+ * construction-time services in an enclosing `Layer.unwrap` and close over
3502
+ * them, and provide per-request services with MCP middleware.
3503
+ *
2482
3504
  * @see {@link registerResource} for the Effect-level resource registration API
3505
+ * @see {@link middleware} for providing request-level dependencies
2483
3506
  *
2484
3507
  * @stability unstable
2485
3508
  * @category layers
@@ -2499,11 +3522,19 @@ export const resource: {
2499
3522
  R
2500
3523
  >
2501
3524
  }
2502
- ): Layer.Layer<never, never, Exclude<R, McpRequestContext>>
3525
+ ): Layer.Layer<never, never, ResourceRequirements<R>>
2503
3526
  /**
2504
3527
  * Creates a layer that registers an MCP resource or resource template.
2505
3528
  *
3529
+ * **Details**
3530
+ *
3531
+ * Services read by the content and completion handlers are request-level, so
3532
+ * providing them with `Layer.provide` doesn't satisfy them. Read
3533
+ * construction-time services in an enclosing `Layer.unwrap` and close over
3534
+ * them, and provide per-request services with MCP middleware.
3535
+ *
2506
3536
  * @see {@link registerResource} for the Effect-level resource registration API
3537
+ * @see {@link middleware} for providing request-level dependencies
2507
3538
  *
2508
3539
  * @stability unstable
2509
3540
  * @category layers
@@ -2525,28 +3556,13 @@ export const resource: {
2525
3556
  E,
2526
3557
  R
2527
3558
  >
2528
- }) => Layer.Layer<
2529
- never,
2530
- never,
2531
- Exclude<
2532
- | Schemas[number]["DecodingServices"]
2533
- | Schemas[number]["EncodingServices"]
2534
- | R
2535
- | CompletionServices<Completions>,
2536
- McpRequestContext
2537
- >
2538
- >
3559
+ }) => Layer.Layer<never, never, ResourceTemplateRequirements<Schemas, R, Completions>>
2539
3560
  } = function() {
2540
3561
  if (arguments.length === 1) {
2541
- return Layer.effectDiscard(registerResource(arguments[0])).pipe(
2542
- Layer.provide(McpServer.layer)
2543
- )
3562
+ return Layer.effectDiscard(registerResource(arguments[0]))
2544
3563
  }
2545
3564
  const register = registerResource(...(arguments as any as [any, any]))
2546
- return (options: any) =>
2547
- Layer.effectDiscard(register(options)).pipe(
2548
- Layer.provide(McpServer.layer)
2549
- )
3565
+ return (options: any) => Layer.effectDiscard(register(options))
2550
3566
  } as any
2551
3567
 
2552
3568
  /**
@@ -2585,18 +3601,7 @@ export const registerPrompt = <
2585
3601
  ) => Effect.Effect<Array<PromptMessage> | string, E, R>
2586
3602
  readonly annotations?: Context.Context<never> | undefined
2587
3603
  }
2588
- ): Effect.Effect<
2589
- void,
2590
- never,
2591
- | Exclude<
2592
- | Schema.Struct.DecodingServices<Params>
2593
- | Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
2594
- | R
2595
- | CompletionServices<Completions>,
2596
- McpRequestContext
2597
- >
2598
- | McpServer
2599
- > => {
3604
+ ): Effect.Effect<void, never, PromptRequirements<Params, R, Completions>> => {
2600
3605
  const args = Arr.empty<PromptArgument>()
2601
3606
  const props: Record<string, Schema.Constraint> = options.parameters ?? {}
2602
3607
  for (const [name, prop] of Object.entries(props)) {
@@ -2624,17 +3629,7 @@ export const registerPrompt = <
2624
3629
  > = options.completion ?? {}
2625
3630
  return Effect.gen(function*() {
2626
3631
  const registry = yield* McpServer
2627
- const services = omitRequestServices(
2628
- yield* Effect.context<
2629
- Exclude<
2630
- | R
2631
- | Schema.Struct.DecodingServices<Params>
2632
- | Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
2633
- | CompletionServices<Completions>,
2634
- McpRequestContext
2635
- >
2636
- >()
2637
- )
3632
+ const services = yield* Effect.context<never>()
2638
3633
  const completions: Record<
2639
3634
  string,
2640
3635
  (
@@ -2643,41 +3638,19 @@ export const registerPrompt = <
2643
3638
  ) => Effect.Effect<CompleteResult, InternalError, McpRequestContext>
2644
3639
  > = Object.create(null)
2645
3640
  for (const [param, handle] of Object.entries(completion)) {
2646
- const encodeArray = Schema.encodeEffect(Schema.Array(props[param]))
2647
- const handler = (
2648
- input: string,
2649
- context: CompletionContext
2650
- ) =>
2651
- handle(input, context).pipe(
2652
- Effect.flatMap(encodeArray),
2653
- Effect.map((values) => ({
2654
- completion: {
2655
- values: values as Array<string>,
2656
- total: values.length,
2657
- hasMore: false
2658
- }
2659
- })),
2660
- Effect.catchCause((cause) => {
2661
- const prettyError = Cause.prettyErrors(cause)[0]
2662
- return Effect.fail(new InternalError({ message: prettyError.message }))
2663
- }),
2664
- Effect.provide(services)
2665
- )
2666
- completions[param] = handler as any
3641
+ completions[param] = completionHandler(handle, Schema.encodeUnknownEffect(Schema.Array(props[param])))
2667
3642
  }
2668
3643
  yield* registry.addPrompt({
2669
3644
  prompt,
2670
3645
  completions,
3646
+ services,
2671
3647
  annotations: options.annotations ?? Context.empty(),
2672
3648
  handle: (params) =>
2673
3649
  decode(params).pipe(
2674
3650
  Effect.mapError((error) => new InvalidParams({ message: error.message })),
2675
3651
  Effect.flatMap((params) =>
2676
3652
  options.content(params as any).pipe(
2677
- Effect.catchCause((cause) => {
2678
- const prettyError = Cause.prettyErrors(cause)[0]
2679
- return Effect.fail(new InternalError({ message: prettyError.message }))
2680
- })
3653
+ Effect.catchCause(handlerFailureToInternalError)
2681
3654
  )
2682
3655
  ),
2683
3656
  Effect.map((messages) => {
@@ -2688,9 +3661,8 @@ export const registerPrompt = <
2688
3661
  }] :
2689
3662
  messages
2690
3663
  return new GetPromptResult({ messages, description: prompt.description })
2691
- }),
2692
- Effect.provideContext(services as Context.Context<unknown>)
2693
- )
3664
+ })
3665
+ ) as Effect.Effect<GetPromptResult, InvalidParams | InternalError>
2694
3666
  })
2695
3667
  })
2696
3668
  }
@@ -2698,7 +3670,15 @@ export const registerPrompt = <
2698
3670
  /**
2699
3671
  * Creates a layer that registers an MCP prompt.
2700
3672
  *
3673
+ * **Details**
3674
+ *
3675
+ * Services read by the content and completion handlers are request-level, so
3676
+ * providing them with `Layer.provide` doesn't satisfy them. Read
3677
+ * construction-time services in an enclosing `Layer.unwrap` and close over
3678
+ * them, and provide per-request services with MCP middleware.
3679
+ *
2701
3680
  * @see {@link registerPrompt} for the Effect-level prompt registration API
3681
+ * @see {@link middleware} for providing request-level dependencies
2702
3682
  *
2703
3683
  * @stability unstable
2704
3684
  * @category layers
@@ -2726,20 +3706,7 @@ export const prompt = <
2726
3706
  ) => Effect.Effect<Array<PromptMessage> | string, E, R>
2727
3707
  readonly annotations?: Context.Context<never> | undefined
2728
3708
  }
2729
- ): Layer.Layer<
2730
- never,
2731
- never,
2732
- Exclude<
2733
- | Schema.Struct.DecodingServices<Params>
2734
- | Params[Extract<keyof Completions, keyof Params>]["EncodingServices"]
2735
- | R
2736
- | CompletionServices<Completions>,
2737
- McpRequestContext
2738
- >
2739
- > =>
2740
- Layer.effectDiscard(registerPrompt(options)).pipe(
2741
- Layer.provide(McpServer.layer)
2742
- )
3709
+ ): Layer.Layer<never, never, PromptRequirements<Params, R, Completions>> => Layer.effectDiscard(registerPrompt(options))
2743
3710
 
2744
3711
  /**
2745
3712
  * Collects structured input from the current MCP client and decodes the
@@ -2799,6 +3766,22 @@ export const clientCapabilities: Effect.Effect<
2799
3766
  McpRequestContext
2800
3767
  > = McpRequestContext.useSync((_) => _.clientCapabilities)
2801
3768
 
3769
+ /**
3770
+ * Decodes an `Mcp-Name` header, including base64-wrapped values.
3771
+ * Returns `undefined` for malformed values.
3772
+ *
3773
+ * **Details**
3774
+ *
3775
+ * Use in `HttpRouter.middleware` to identify the tool, prompt or resource
3776
+ * targeted by a `2026-07-28` request. Earlier protocols carry the name only
3777
+ * in the JSON-RPC body.
3778
+ *
3779
+ * @stability unstable
3780
+ * @category decoding
3781
+ * @since 4.0.0
3782
+ */
3783
+ export const decodeNameHeader = (value: string): string | undefined => McpProtocolInternal.decodeRoutingHeader(value)
3784
+
2802
3785
  // -----------------------------------------------------------------------------
2803
3786
  // Internal
2804
3787
  // -----------------------------------------------------------------------------