@modelcontextprotocol/sdk 1.18.1 → 1.19.1

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 (332) hide show
  1. package/README.md +766 -738
  2. package/dist/cjs/cli.js +35 -37
  3. package/dist/cjs/cli.js.map +1 -1
  4. package/dist/cjs/client/auth.d.ts +12 -12
  5. package/dist/cjs/client/auth.d.ts.map +1 -1
  6. package/dist/cjs/client/auth.js +76 -83
  7. package/dist/cjs/client/auth.js.map +1 -1
  8. package/dist/cjs/client/index.d.ts +186 -123
  9. package/dist/cjs/client/index.d.ts.map +1 -1
  10. package/dist/cjs/client/index.js +40 -41
  11. package/dist/cjs/client/index.js.map +1 -1
  12. package/dist/cjs/client/middleware.d.ts +2 -2
  13. package/dist/cjs/client/middleware.d.ts.map +1 -1
  14. package/dist/cjs/client/middleware.js +22 -27
  15. package/dist/cjs/client/middleware.js.map +1 -1
  16. package/dist/cjs/client/sse.d.ts +4 -4
  17. package/dist/cjs/client/sse.d.ts.map +1 -1
  18. package/dist/cjs/client/sse.js +34 -21
  19. package/dist/cjs/client/sse.js.map +1 -1
  20. package/dist/cjs/client/stdio.d.ts +4 -4
  21. package/dist/cjs/client/stdio.d.ts.map +1 -1
  22. package/dist/cjs/client/stdio.js +32 -32
  23. package/dist/cjs/client/stdio.js.map +1 -1
  24. package/dist/cjs/client/streamableHttp.d.ts +7 -6
  25. package/dist/cjs/client/streamableHttp.d.ts.map +1 -1
  26. package/dist/cjs/client/streamableHttp.js +55 -38
  27. package/dist/cjs/client/streamableHttp.js.map +1 -1
  28. package/dist/cjs/client/websocket.d.ts +2 -2
  29. package/dist/cjs/client/websocket.d.ts.map +1 -1
  30. package/dist/cjs/client/websocket.js +5 -7
  31. package/dist/cjs/client/websocket.js.map +1 -1
  32. package/dist/cjs/examples/client/multipleClientsParallel.js +2 -2
  33. package/dist/cjs/examples/client/multipleClientsParallel.js.map +1 -1
  34. package/dist/cjs/examples/client/parallelToolCallsClient.js +6 -5
  35. package/dist/cjs/examples/client/parallelToolCallsClient.js.map +1 -1
  36. package/dist/cjs/examples/client/simpleOAuthClient.js +15 -13
  37. package/dist/cjs/examples/client/simpleOAuthClient.js.map +1 -1
  38. package/dist/cjs/examples/client/simpleStreamableHttp.js +15 -11
  39. package/dist/cjs/examples/client/simpleStreamableHttp.js.map +1 -1
  40. package/dist/cjs/examples/client/streamableHttpWithSseFallbackClient.js +2 -2
  41. package/dist/cjs/examples/client/streamableHttpWithSseFallbackClient.js.map +1 -1
  42. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.d.ts +1 -1
  43. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.d.ts.map +1 -1
  44. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.js +22 -16
  45. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.js.map +1 -1
  46. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js +18 -18
  47. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  48. package/dist/cjs/examples/server/mcpServerOutputSchema.js +19 -17
  49. package/dist/cjs/examples/server/mcpServerOutputSchema.js.map +1 -1
  50. package/dist/cjs/examples/server/simpleSseServer.js +8 -8
  51. package/dist/cjs/examples/server/simpleSseServer.js.map +1 -1
  52. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js +22 -22
  53. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  54. package/dist/cjs/examples/server/simpleStreamableHttp.js +78 -78
  55. package/dist/cjs/examples/server/simpleStreamableHttp.js.map +1 -1
  56. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js +18 -18
  57. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  58. package/dist/cjs/examples/server/standaloneSseWithGetStreamableHttp.js +8 -8
  59. package/dist/cjs/examples/server/standaloneSseWithGetStreamableHttp.js.map +1 -1
  60. package/dist/cjs/examples/server/toolWithSampleServer.js +19 -19
  61. package/dist/cjs/examples/server/toolWithSampleServer.js.map +1 -1
  62. package/dist/cjs/examples/shared/inMemoryEventStore.d.ts.map +1 -1
  63. package/dist/cjs/examples/shared/inMemoryEventStore.js.map +1 -1
  64. package/dist/cjs/inMemory.d.ts +3 -3
  65. package/dist/cjs/inMemory.d.ts.map +1 -1
  66. package/dist/cjs/inMemory.js +1 -1
  67. package/dist/cjs/inMemory.js.map +1 -1
  68. package/dist/cjs/server/auth/clients.d.ts +2 -2
  69. package/dist/cjs/server/auth/clients.d.ts.map +1 -1
  70. package/dist/cjs/server/auth/errors.d.ts +1 -1
  71. package/dist/cjs/server/auth/errors.d.ts.map +1 -1
  72. package/dist/cjs/server/auth/errors.js +17 -17
  73. package/dist/cjs/server/auth/errors.js.map +1 -1
  74. package/dist/cjs/server/auth/handlers/authorize.d.ts +3 -3
  75. package/dist/cjs/server/auth/handlers/authorize.d.ts.map +1 -1
  76. package/dist/cjs/server/auth/handlers/authorize.js +21 -18
  77. package/dist/cjs/server/auth/handlers/authorize.js.map +1 -1
  78. package/dist/cjs/server/auth/handlers/metadata.d.ts +2 -2
  79. package/dist/cjs/server/auth/handlers/metadata.js +1 -1
  80. package/dist/cjs/server/auth/handlers/metadata.js.map +1 -1
  81. package/dist/cjs/server/auth/handlers/register.d.ts +4 -4
  82. package/dist/cjs/server/auth/handlers/register.d.ts.map +1 -1
  83. package/dist/cjs/server/auth/handlers/register.js +7 -9
  84. package/dist/cjs/server/auth/handlers/register.js.map +1 -1
  85. package/dist/cjs/server/auth/handlers/revoke.d.ts +4 -4
  86. package/dist/cjs/server/auth/handlers/revoke.d.ts.map +1 -1
  87. package/dist/cjs/server/auth/handlers/revoke.js +9 -9
  88. package/dist/cjs/server/auth/handlers/revoke.js.map +1 -1
  89. package/dist/cjs/server/auth/handlers/token.d.ts +3 -3
  90. package/dist/cjs/server/auth/handlers/token.d.ts.map +1 -1
  91. package/dist/cjs/server/auth/handlers/token.js +14 -14
  92. package/dist/cjs/server/auth/handlers/token.js.map +1 -1
  93. package/dist/cjs/server/auth/middleware/allowedMethods.d.ts +1 -1
  94. package/dist/cjs/server/auth/middleware/allowedMethods.d.ts.map +1 -1
  95. package/dist/cjs/server/auth/middleware/allowedMethods.js +1 -3
  96. package/dist/cjs/server/auth/middleware/allowedMethods.js.map +1 -1
  97. package/dist/cjs/server/auth/middleware/bearerAuth.d.ts +4 -4
  98. package/dist/cjs/server/auth/middleware/bearerAuth.d.ts.map +1 -1
  99. package/dist/cjs/server/auth/middleware/bearerAuth.js +7 -7
  100. package/dist/cjs/server/auth/middleware/bearerAuth.js.map +1 -1
  101. package/dist/cjs/server/auth/middleware/clientAuth.d.ts +4 -4
  102. package/dist/cjs/server/auth/middleware/clientAuth.d.ts.map +1 -1
  103. package/dist/cjs/server/auth/middleware/clientAuth.js +6 -6
  104. package/dist/cjs/server/auth/middleware/clientAuth.js.map +1 -1
  105. package/dist/cjs/server/auth/provider.d.ts +4 -4
  106. package/dist/cjs/server/auth/provider.d.ts.map +1 -1
  107. package/dist/cjs/server/auth/providers/proxyProvider.d.ts +10 -10
  108. package/dist/cjs/server/auth/providers/proxyProvider.d.ts.map +1 -1
  109. package/dist/cjs/server/auth/providers/proxyProvider.js +34 -34
  110. package/dist/cjs/server/auth/providers/proxyProvider.js.map +1 -1
  111. package/dist/cjs/server/auth/router.d.ts +18 -13
  112. package/dist/cjs/server/auth/router.d.ts.map +1 -1
  113. package/dist/cjs/server/auth/router.js +27 -24
  114. package/dist/cjs/server/auth/router.js.map +1 -1
  115. package/dist/cjs/server/auth/types.d.ts +1 -1
  116. package/dist/cjs/server/auth/types.d.ts.map +1 -1
  117. package/dist/cjs/server/completable.d.ts +5 -5
  118. package/dist/cjs/server/completable.d.ts.map +1 -1
  119. package/dist/cjs/server/completable.js +5 -5
  120. package/dist/cjs/server/completable.js.map +1 -1
  121. package/dist/cjs/server/index.d.ts +9 -9
  122. package/dist/cjs/server/index.d.ts.map +1 -1
  123. package/dist/cjs/server/index.js +38 -42
  124. package/dist/cjs/server/index.js.map +1 -1
  125. package/dist/cjs/server/mcp.d.ts +8 -8
  126. package/dist/cjs/server/mcp.d.ts.map +1 -1
  127. package/dist/cjs/server/mcp.js +87 -82
  128. package/dist/cjs/server/mcp.js.map +1 -1
  129. package/dist/cjs/server/sse.d.ts +4 -4
  130. package/dist/cjs/server/sse.d.ts.map +1 -1
  131. package/dist/cjs/server/sse.js +16 -15
  132. package/dist/cjs/server/sse.js.map +1 -1
  133. package/dist/cjs/server/stdio.d.ts +3 -3
  134. package/dist/cjs/server/stdio.d.ts.map +1 -1
  135. package/dist/cjs/server/stdio.js +7 -7
  136. package/dist/cjs/server/stdio.js.map +1 -1
  137. package/dist/cjs/server/streamableHttp.d.ts +5 -5
  138. package/dist/cjs/server/streamableHttp.d.ts.map +1 -1
  139. package/dist/cjs/server/streamableHttp.js +63 -64
  140. package/dist/cjs/server/streamableHttp.js.map +1 -1
  141. package/dist/cjs/shared/auth-utils.d.ts.map +1 -1
  142. package/dist/cjs/shared/auth-utils.js +3 -3
  143. package/dist/cjs/shared/auth-utils.js.map +1 -1
  144. package/dist/cjs/shared/auth.d.ts +1 -1
  145. package/dist/cjs/shared/auth.d.ts.map +1 -1
  146. package/dist/cjs/shared/auth.js +42 -46
  147. package/dist/cjs/shared/auth.js.map +1 -1
  148. package/dist/cjs/shared/metadataUtils.d.ts +1 -1
  149. package/dist/cjs/shared/metadataUtils.js.map +1 -1
  150. package/dist/cjs/shared/protocol.d.ts +6 -6
  151. package/dist/cjs/shared/protocol.d.ts.map +1 -1
  152. package/dist/cjs/shared/protocol.js +42 -43
  153. package/dist/cjs/shared/protocol.js.map +1 -1
  154. package/dist/cjs/shared/stdio.d.ts +1 -1
  155. package/dist/cjs/shared/stdio.d.ts.map +1 -1
  156. package/dist/cjs/shared/stdio.js +3 -3
  157. package/dist/cjs/shared/stdio.js.map +1 -1
  158. package/dist/cjs/shared/transport.d.ts +1 -1
  159. package/dist/cjs/shared/transport.d.ts.map +1 -1
  160. package/dist/cjs/shared/uriTemplate.d.ts.map +1 -1
  161. package/dist/cjs/shared/uriTemplate.js +69 -71
  162. package/dist/cjs/shared/uriTemplate.js.map +1 -1
  163. package/dist/cjs/types.d.ts +9650 -4790
  164. package/dist/cjs/types.d.ts.map +1 -1
  165. package/dist/cjs/types.js +199 -234
  166. package/dist/cjs/types.js.map +1 -1
  167. package/dist/esm/cli.js +45 -47
  168. package/dist/esm/cli.js.map +1 -1
  169. package/dist/esm/client/auth.d.ts +12 -12
  170. package/dist/esm/client/auth.d.ts.map +1 -1
  171. package/dist/esm/client/auth.js +82 -89
  172. package/dist/esm/client/auth.js.map +1 -1
  173. package/dist/esm/client/index.d.ts +186 -123
  174. package/dist/esm/client/index.d.ts.map +1 -1
  175. package/dist/esm/client/index.js +43 -44
  176. package/dist/esm/client/index.js.map +1 -1
  177. package/dist/esm/client/middleware.d.ts +2 -2
  178. package/dist/esm/client/middleware.d.ts.map +1 -1
  179. package/dist/esm/client/middleware.js +23 -28
  180. package/dist/esm/client/middleware.js.map +1 -1
  181. package/dist/esm/client/sse.d.ts +4 -4
  182. package/dist/esm/client/sse.d.ts.map +1 -1
  183. package/dist/esm/client/sse.js +37 -24
  184. package/dist/esm/client/sse.js.map +1 -1
  185. package/dist/esm/client/stdio.d.ts +4 -4
  186. package/dist/esm/client/stdio.d.ts.map +1 -1
  187. package/dist/esm/client/stdio.js +36 -36
  188. package/dist/esm/client/stdio.js.map +1 -1
  189. package/dist/esm/client/streamableHttp.d.ts +7 -6
  190. package/dist/esm/client/streamableHttp.d.ts.map +1 -1
  191. package/dist/esm/client/streamableHttp.js +58 -41
  192. package/dist/esm/client/streamableHttp.js.map +1 -1
  193. package/dist/esm/client/websocket.d.ts +2 -2
  194. package/dist/esm/client/websocket.d.ts.map +1 -1
  195. package/dist/esm/client/websocket.js +6 -8
  196. package/dist/esm/client/websocket.js.map +1 -1
  197. package/dist/esm/examples/client/multipleClientsParallel.js +3 -3
  198. package/dist/esm/examples/client/multipleClientsParallel.js.map +1 -1
  199. package/dist/esm/examples/client/parallelToolCallsClient.js +7 -6
  200. package/dist/esm/examples/client/parallelToolCallsClient.js.map +1 -1
  201. package/dist/esm/examples/client/simpleOAuthClient.js +15 -13
  202. package/dist/esm/examples/client/simpleOAuthClient.js.map +1 -1
  203. package/dist/esm/examples/client/simpleStreamableHttp.js +17 -13
  204. package/dist/esm/examples/client/simpleStreamableHttp.js.map +1 -1
  205. package/dist/esm/examples/client/streamableHttpWithSseFallbackClient.js +3 -3
  206. package/dist/esm/examples/client/streamableHttpWithSseFallbackClient.js.map +1 -1
  207. package/dist/esm/examples/server/demoInMemoryOAuthProvider.d.ts +1 -1
  208. package/dist/esm/examples/server/demoInMemoryOAuthProvider.d.ts.map +1 -1
  209. package/dist/esm/examples/server/demoInMemoryOAuthProvider.js +23 -17
  210. package/dist/esm/examples/server/demoInMemoryOAuthProvider.js.map +1 -1
  211. package/dist/esm/examples/server/jsonResponseStreamableHttp.js +18 -18
  212. package/dist/esm/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  213. package/dist/esm/examples/server/mcpServerOutputSchema.js +22 -20
  214. package/dist/esm/examples/server/mcpServerOutputSchema.js.map +1 -1
  215. package/dist/esm/examples/server/simpleSseServer.js +8 -8
  216. package/dist/esm/examples/server/simpleSseServer.js.map +1 -1
  217. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js +22 -22
  218. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  219. package/dist/esm/examples/server/simpleStreamableHttp.js +78 -78
  220. package/dist/esm/examples/server/simpleStreamableHttp.js.map +1 -1
  221. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js +19 -19
  222. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  223. package/dist/esm/examples/server/standaloneSseWithGetStreamableHttp.js +8 -8
  224. package/dist/esm/examples/server/standaloneSseWithGetStreamableHttp.js.map +1 -1
  225. package/dist/esm/examples/server/toolWithSampleServer.js +22 -22
  226. package/dist/esm/examples/server/toolWithSampleServer.js.map +1 -1
  227. package/dist/esm/examples/shared/inMemoryEventStore.d.ts.map +1 -1
  228. package/dist/esm/examples/shared/inMemoryEventStore.js.map +1 -1
  229. package/dist/esm/inMemory.d.ts +3 -3
  230. package/dist/esm/inMemory.d.ts.map +1 -1
  231. package/dist/esm/inMemory.js +1 -1
  232. package/dist/esm/inMemory.js.map +1 -1
  233. package/dist/esm/server/auth/clients.d.ts +2 -2
  234. package/dist/esm/server/auth/clients.d.ts.map +1 -1
  235. package/dist/esm/server/auth/errors.d.ts +1 -1
  236. package/dist/esm/server/auth/errors.d.ts.map +1 -1
  237. package/dist/esm/server/auth/errors.js +17 -17
  238. package/dist/esm/server/auth/errors.js.map +1 -1
  239. package/dist/esm/server/auth/handlers/authorize.d.ts +3 -3
  240. package/dist/esm/server/auth/handlers/authorize.d.ts.map +1 -1
  241. package/dist/esm/server/auth/handlers/authorize.js +26 -23
  242. package/dist/esm/server/auth/handlers/authorize.js.map +1 -1
  243. package/dist/esm/server/auth/handlers/metadata.d.ts +2 -2
  244. package/dist/esm/server/auth/handlers/metadata.js +3 -3
  245. package/dist/esm/server/auth/handlers/metadata.js.map +1 -1
  246. package/dist/esm/server/auth/handlers/register.d.ts +4 -4
  247. package/dist/esm/server/auth/handlers/register.d.ts.map +1 -1
  248. package/dist/esm/server/auth/handlers/register.js +12 -14
  249. package/dist/esm/server/auth/handlers/register.js.map +1 -1
  250. package/dist/esm/server/auth/handlers/revoke.d.ts +4 -4
  251. package/dist/esm/server/auth/handlers/revoke.d.ts.map +1 -1
  252. package/dist/esm/server/auth/handlers/revoke.js +16 -16
  253. package/dist/esm/server/auth/handlers/revoke.js.map +1 -1
  254. package/dist/esm/server/auth/handlers/token.d.ts +3 -3
  255. package/dist/esm/server/auth/handlers/token.d.ts.map +1 -1
  256. package/dist/esm/server/auth/handlers/token.js +22 -22
  257. package/dist/esm/server/auth/handlers/token.js.map +1 -1
  258. package/dist/esm/server/auth/middleware/allowedMethods.d.ts +1 -1
  259. package/dist/esm/server/auth/middleware/allowedMethods.d.ts.map +1 -1
  260. package/dist/esm/server/auth/middleware/allowedMethods.js +2 -4
  261. package/dist/esm/server/auth/middleware/allowedMethods.js.map +1 -1
  262. package/dist/esm/server/auth/middleware/bearerAuth.d.ts +4 -4
  263. package/dist/esm/server/auth/middleware/bearerAuth.d.ts.map +1 -1
  264. package/dist/esm/server/auth/middleware/bearerAuth.js +8 -8
  265. package/dist/esm/server/auth/middleware/bearerAuth.js.map +1 -1
  266. package/dist/esm/server/auth/middleware/clientAuth.d.ts +4 -4
  267. package/dist/esm/server/auth/middleware/clientAuth.d.ts.map +1 -1
  268. package/dist/esm/server/auth/middleware/clientAuth.js +8 -8
  269. package/dist/esm/server/auth/middleware/clientAuth.js.map +1 -1
  270. package/dist/esm/server/auth/provider.d.ts +4 -4
  271. package/dist/esm/server/auth/provider.d.ts.map +1 -1
  272. package/dist/esm/server/auth/providers/proxyProvider.d.ts +10 -10
  273. package/dist/esm/server/auth/providers/proxyProvider.d.ts.map +1 -1
  274. package/dist/esm/server/auth/providers/proxyProvider.js +36 -36
  275. package/dist/esm/server/auth/providers/proxyProvider.js.map +1 -1
  276. package/dist/esm/server/auth/router.d.ts +18 -13
  277. package/dist/esm/server/auth/router.d.ts.map +1 -1
  278. package/dist/esm/server/auth/router.js +33 -30
  279. package/dist/esm/server/auth/router.js.map +1 -1
  280. package/dist/esm/server/auth/types.d.ts +1 -1
  281. package/dist/esm/server/auth/types.d.ts.map +1 -1
  282. package/dist/esm/server/completable.d.ts +5 -5
  283. package/dist/esm/server/completable.d.ts.map +1 -1
  284. package/dist/esm/server/completable.js +6 -6
  285. package/dist/esm/server/completable.js.map +1 -1
  286. package/dist/esm/server/index.d.ts +9 -9
  287. package/dist/esm/server/index.d.ts.map +1 -1
  288. package/dist/esm/server/index.js +41 -45
  289. package/dist/esm/server/index.js.map +1 -1
  290. package/dist/esm/server/mcp.d.ts +8 -8
  291. package/dist/esm/server/mcp.d.ts.map +1 -1
  292. package/dist/esm/server/mcp.js +93 -88
  293. package/dist/esm/server/mcp.js.map +1 -1
  294. package/dist/esm/server/sse.d.ts +4 -4
  295. package/dist/esm/server/sse.d.ts.map +1 -1
  296. package/dist/esm/server/sse.js +20 -19
  297. package/dist/esm/server/sse.js.map +1 -1
  298. package/dist/esm/server/stdio.d.ts +3 -3
  299. package/dist/esm/server/stdio.d.ts.map +1 -1
  300. package/dist/esm/server/stdio.js +9 -9
  301. package/dist/esm/server/stdio.js.map +1 -1
  302. package/dist/esm/server/streamableHttp.d.ts +5 -5
  303. package/dist/esm/server/streamableHttp.d.ts.map +1 -1
  304. package/dist/esm/server/streamableHttp.js +67 -68
  305. package/dist/esm/server/streamableHttp.js.map +1 -1
  306. package/dist/esm/shared/auth-utils.d.ts.map +1 -1
  307. package/dist/esm/shared/auth-utils.js +3 -3
  308. package/dist/esm/shared/auth-utils.js.map +1 -1
  309. package/dist/esm/shared/auth.d.ts +1 -1
  310. package/dist/esm/shared/auth.d.ts.map +1 -1
  311. package/dist/esm/shared/auth.js +43 -47
  312. package/dist/esm/shared/auth.js.map +1 -1
  313. package/dist/esm/shared/metadataUtils.d.ts +1 -1
  314. package/dist/esm/shared/metadataUtils.js.map +1 -1
  315. package/dist/esm/shared/protocol.d.ts +6 -6
  316. package/dist/esm/shared/protocol.d.ts.map +1 -1
  317. package/dist/esm/shared/protocol.js +43 -44
  318. package/dist/esm/shared/protocol.js.map +1 -1
  319. package/dist/esm/shared/stdio.d.ts +1 -1
  320. package/dist/esm/shared/stdio.d.ts.map +1 -1
  321. package/dist/esm/shared/stdio.js +4 -4
  322. package/dist/esm/shared/stdio.js.map +1 -1
  323. package/dist/esm/shared/transport.d.ts +1 -1
  324. package/dist/esm/shared/transport.d.ts.map +1 -1
  325. package/dist/esm/shared/uriTemplate.d.ts.map +1 -1
  326. package/dist/esm/shared/uriTemplate.js +69 -71
  327. package/dist/esm/shared/uriTemplate.js.map +1 -1
  328. package/dist/esm/types.d.ts +9650 -4790
  329. package/dist/esm/types.d.ts.map +1 -1
  330. package/dist/esm/types.js +197 -232
  331. package/dist/esm/types.js.map +1 -1
  332. package/package.json +100 -98
package/README.md CHANGED
@@ -7,25 +7,25 @@
7
7
  - [Quickstart](#quick-start)
8
8
  - [What is MCP?](#what-is-mcp)
9
9
  - [Core Concepts](#core-concepts)
10
- - [Server](#server)
11
- - [Resources](#resources)
12
- - [Tools](#tools)
13
- - [Prompts](#prompts)
14
- - [Completions](#completions)
15
- - [Sampling](#sampling)
10
+ - [Server](#server)
11
+ - [Resources](#resources)
12
+ - [Tools](#tools)
13
+ - [Prompts](#prompts)
14
+ - [Completions](#completions)
15
+ - [Sampling](#sampling)
16
16
  - [Running Your Server](#running-your-server)
17
- - [stdio](#stdio)
18
- - [Streamable HTTP](#streamable-http)
19
- - [Testing and Debugging](#testing-and-debugging)
17
+ - [stdio](#stdio)
18
+ - [Streamable HTTP](#streamable-http)
19
+ - [Testing and Debugging](#testing-and-debugging)
20
20
  - [Examples](#examples)
21
- - [Echo Server](#echo-server)
22
- - [SQLite Explorer](#sqlite-explorer)
21
+ - [Echo Server](#echo-server)
22
+ - [SQLite Explorer](#sqlite-explorer)
23
23
  - [Advanced Usage](#advanced-usage)
24
- - [Dynamic Servers](#dynamic-servers)
25
- - [Low-Level Server](#low-level-server)
26
- - [Writing MCP Clients](#writing-mcp-clients)
27
- - [Proxy Authorization Requests Upstream](#proxy-authorization-requests-upstream)
28
- - [Backwards Compatibility](#backwards-compatibility)
24
+ - [Dynamic Servers](#dynamic-servers)
25
+ - [Low-Level Server](#low-level-server)
26
+ - [Writing MCP Clients](#writing-mcp-clients)
27
+ - [Proxy Authorization Requests Upstream](#proxy-authorization-requests-upstream)
28
+ - [Backwards Compatibility](#backwards-compatibility)
29
29
  - [Documentation](#documentation)
30
30
  - [Contributing](#contributing)
31
31
  - [License](#license)
@@ -52,42 +52,45 @@ npm install @modelcontextprotocol/sdk
52
52
  Let's create a simple MCP server that exposes a calculator tool and some data:
53
53
 
54
54
  ```typescript
55
- import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
56
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
57
- import { z } from "zod";
55
+ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
56
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
57
+ import { z } from 'zod';
58
58
 
59
59
  // Create an MCP server
60
60
  const server = new McpServer({
61
- name: "demo-server",
62
- version: "1.0.0"
61
+ name: 'demo-server',
62
+ version: '1.0.0'
63
63
  });
64
64
 
65
65
  // Add an addition tool
66
- server.registerTool("add",
67
- {
68
- title: "Addition Tool",
69
- description: "Add two numbers",
70
- inputSchema: { a: z.number(), b: z.number() }
71
- },
72
- async ({ a, b }) => ({
73
- content: [{ type: "text", text: String(a + b) }]
74
- })
66
+ server.registerTool(
67
+ 'add',
68
+ {
69
+ title: 'Addition Tool',
70
+ description: 'Add two numbers',
71
+ inputSchema: { a: z.number(), b: z.number() }
72
+ },
73
+ async ({ a, b }) => ({
74
+ content: [{ type: 'text', text: String(a + b) }]
75
+ })
75
76
  );
76
77
 
77
78
  // Add a dynamic greeting resource
78
79
  server.registerResource(
79
- "greeting",
80
- new ResourceTemplate("greeting://{name}", { list: undefined }),
81
- {
82
- title: "Greeting Resource", // Display name for UI
83
- description: "Dynamic greeting generator"
84
- },
85
- async (uri, { name }) => ({
86
- contents: [{
87
- uri: uri.href,
88
- text: `Hello, ${name}!`
89
- }]
90
- })
80
+ 'greeting',
81
+ new ResourceTemplate('greeting://{name}', { list: undefined }),
82
+ {
83
+ title: 'Greeting Resource', // Display name for UI
84
+ description: 'Dynamic greeting generator'
85
+ },
86
+ async (uri, { name }) => ({
87
+ contents: [
88
+ {
89
+ uri: uri.href,
90
+ text: `Hello, ${name}!`
91
+ }
92
+ ]
93
+ })
91
94
  );
92
95
 
93
96
  // Start receiving messages on stdin and sending messages on stdout
@@ -112,8 +115,8 @@ The McpServer is your core interface to the MCP protocol. It handles connection
112
115
 
113
116
  ```typescript
114
117
  const server = new McpServer({
115
- name: "my-app",
116
- version: "1.0.0"
118
+ name: 'my-app',
119
+ version: '1.0.0'
117
120
  });
118
121
  ```
119
122
 
@@ -124,62 +127,68 @@ Resources are how you expose data to LLMs. They're similar to GET endpoints in a
124
127
  ```typescript
125
128
  // Static resource
126
129
  server.registerResource(
127
- "config",
128
- "config://app",
129
- {
130
- title: "Application Config",
131
- description: "Application configuration data",
132
- mimeType: "text/plain"
133
- },
134
- async (uri) => ({
135
- contents: [{
136
- uri: uri.href,
137
- text: "App configuration here"
138
- }]
139
- })
130
+ 'config',
131
+ 'config://app',
132
+ {
133
+ title: 'Application Config',
134
+ description: 'Application configuration data',
135
+ mimeType: 'text/plain'
136
+ },
137
+ async uri => ({
138
+ contents: [
139
+ {
140
+ uri: uri.href,
141
+ text: 'App configuration here'
142
+ }
143
+ ]
144
+ })
140
145
  );
141
146
 
142
147
  // Dynamic resource with parameters
143
148
  server.registerResource(
144
- "user-profile",
145
- new ResourceTemplate("users://{userId}/profile", { list: undefined }),
146
- {
147
- title: "User Profile",
148
- description: "User profile information"
149
- },
150
- async (uri, { userId }) => ({
151
- contents: [{
152
- uri: uri.href,
153
- text: `Profile data for user ${userId}`
154
- }]
155
- })
149
+ 'user-profile',
150
+ new ResourceTemplate('users://{userId}/profile', { list: undefined }),
151
+ {
152
+ title: 'User Profile',
153
+ description: 'User profile information'
154
+ },
155
+ async (uri, { userId }) => ({
156
+ contents: [
157
+ {
158
+ uri: uri.href,
159
+ text: `Profile data for user ${userId}`
160
+ }
161
+ ]
162
+ })
156
163
  );
157
164
 
158
165
  // Resource with context-aware completion
159
166
  server.registerResource(
160
- "repository",
161
- new ResourceTemplate("github://repos/{owner}/{repo}", {
162
- list: undefined,
163
- complete: {
164
- // Provide intelligent completions based on previously resolved parameters
165
- repo: (value, context) => {
166
- if (context?.arguments?.["owner"] === "org1") {
167
- return ["project1", "project2", "project3"].filter(r => r.startsWith(value));
167
+ 'repository',
168
+ new ResourceTemplate('github://repos/{owner}/{repo}', {
169
+ list: undefined,
170
+ complete: {
171
+ // Provide intelligent completions based on previously resolved parameters
172
+ repo: (value, context) => {
173
+ if (context?.arguments?.['owner'] === 'org1') {
174
+ return ['project1', 'project2', 'project3'].filter(r => r.startsWith(value));
175
+ }
176
+ return ['default-repo'].filter(r => r.startsWith(value));
177
+ }
168
178
  }
169
- return ["default-repo"].filter(r => r.startsWith(value));
170
- }
171
- }
172
- }),
173
- {
174
- title: "GitHub Repository",
175
- description: "Repository information"
176
- },
177
- async (uri, { owner, repo }) => ({
178
- contents: [{
179
- uri: uri.href,
180
- text: `Repository: ${owner}/${repo}`
181
- }]
182
- })
179
+ }),
180
+ {
181
+ title: 'GitHub Repository',
182
+ description: 'Repository information'
183
+ },
184
+ async (uri, { owner, repo }) => ({
185
+ contents: [
186
+ {
187
+ uri: uri.href,
188
+ text: `Repository: ${owner}/${repo}`
189
+ }
190
+ ]
191
+ })
183
192
  );
184
193
  ```
185
194
 
@@ -190,68 +199,70 @@ Tools let LLMs take actions through your server. Unlike resources, tools are exp
190
199
  ```typescript
191
200
  // Simple tool with parameters
192
201
  server.registerTool(
193
- "calculate-bmi",
194
- {
195
- title: "BMI Calculator",
196
- description: "Calculate Body Mass Index",
197
- inputSchema: {
198
- weightKg: z.number(),
199
- heightM: z.number()
200
- }
201
- },
202
- async ({ weightKg, heightM }) => ({
203
- content: [{
204
- type: "text",
205
- text: String(weightKg / (heightM * heightM))
206
- }]
207
- })
202
+ 'calculate-bmi',
203
+ {
204
+ title: 'BMI Calculator',
205
+ description: 'Calculate Body Mass Index',
206
+ inputSchema: {
207
+ weightKg: z.number(),
208
+ heightM: z.number()
209
+ }
210
+ },
211
+ async ({ weightKg, heightM }) => ({
212
+ content: [
213
+ {
214
+ type: 'text',
215
+ text: String(weightKg / (heightM * heightM))
216
+ }
217
+ ]
218
+ })
208
219
  );
209
220
 
210
221
  // Async tool with external API call
211
222
  server.registerTool(
212
- "fetch-weather",
213
- {
214
- title: "Weather Fetcher",
215
- description: "Get weather data for a city",
216
- inputSchema: { city: z.string() }
217
- },
218
- async ({ city }) => {
219
- const response = await fetch(`https://api.weather.com/${city}`);
220
- const data = await response.text();
221
- return {
222
- content: [{ type: "text", text: data }]
223
- };
224
- }
223
+ 'fetch-weather',
224
+ {
225
+ title: 'Weather Fetcher',
226
+ description: 'Get weather data for a city',
227
+ inputSchema: { city: z.string() }
228
+ },
229
+ async ({ city }) => {
230
+ const response = await fetch(`https://api.weather.com/${city}`);
231
+ const data = await response.text();
232
+ return {
233
+ content: [{ type: 'text', text: data }]
234
+ };
235
+ }
225
236
  );
226
237
 
227
238
  // Tool that returns ResourceLinks
228
239
  server.registerTool(
229
- "list-files",
230
- {
231
- title: "List Files",
232
- description: "List project files",
233
- inputSchema: { pattern: z.string() }
234
- },
235
- async ({ pattern }) => ({
236
- content: [
237
- { type: "text", text: `Found files matching "${pattern}":` },
238
- // ResourceLinks let tools return references without file content
239
- {
240
- type: "resource_link",
241
- uri: "file:///project/README.md",
242
- name: "README.md",
243
- mimeType: "text/markdown",
244
- description: 'A README file'
245
- },
246
- {
247
- type: "resource_link",
248
- uri: "file:///project/src/index.ts",
249
- name: "index.ts",
250
- mimeType: "text/typescript",
251
- description: 'An index file'
252
- }
253
- ]
254
- })
240
+ 'list-files',
241
+ {
242
+ title: 'List Files',
243
+ description: 'List project files',
244
+ inputSchema: { pattern: z.string() }
245
+ },
246
+ async ({ pattern }) => ({
247
+ content: [
248
+ { type: 'text', text: `Found files matching "${pattern}":` },
249
+ // ResourceLinks let tools return references without file content
250
+ {
251
+ type: 'resource_link',
252
+ uri: 'file:///project/README.md',
253
+ name: 'README.md',
254
+ mimeType: 'text/markdown',
255
+ description: 'A README file'
256
+ },
257
+ {
258
+ type: 'resource_link',
259
+ uri: 'file:///project/src/index.ts',
260
+ name: 'index.ts',
261
+ mimeType: 'text/typescript',
262
+ description: 'An index file'
263
+ }
264
+ ]
265
+ })
255
266
  );
256
267
  ```
257
268
 
@@ -264,60 +275,64 @@ Tools can return `ResourceLink` objects to reference resources without embedding
264
275
  Prompts are reusable templates that help LLMs interact with your server effectively:
265
276
 
266
277
  ```typescript
267
- import { completable } from "@modelcontextprotocol/sdk/server/completable.js";
278
+ import { completable } from '@modelcontextprotocol/sdk/server/completable.js';
268
279
 
269
280
  server.registerPrompt(
270
- "review-code",
271
- {
272
- title: "Code Review",
273
- description: "Review code for best practices and potential issues",
274
- argsSchema: { code: z.string() }
275
- },
276
- ({ code }) => ({
277
- messages: [{
278
- role: "user",
279
- content: {
280
- type: "text",
281
- text: `Please review this code:\n\n${code}`
282
- }
283
- }]
284
- })
281
+ 'review-code',
282
+ {
283
+ title: 'Code Review',
284
+ description: 'Review code for best practices and potential issues',
285
+ argsSchema: { code: z.string() }
286
+ },
287
+ ({ code }) => ({
288
+ messages: [
289
+ {
290
+ role: 'user',
291
+ content: {
292
+ type: 'text',
293
+ text: `Please review this code:\n\n${code}`
294
+ }
295
+ }
296
+ ]
297
+ })
285
298
  );
286
299
 
287
300
  // Prompt with context-aware completion
288
301
  server.registerPrompt(
289
- "team-greeting",
290
- {
291
- title: "Team Greeting",
292
- description: "Generate a greeting for team members",
293
- argsSchema: {
294
- department: completable(z.string(), (value) => {
295
- // Department suggestions
296
- return ["engineering", "sales", "marketing", "support"].filter(d => d.startsWith(value));
297
- }),
298
- name: completable(z.string(), (value, context) => {
299
- // Name suggestions based on selected department
300
- const department = context?.arguments?.["department"];
301
- if (department === "engineering") {
302
- return ["Alice", "Bob", "Charlie"].filter(n => n.startsWith(value));
303
- } else if (department === "sales") {
304
- return ["David", "Eve", "Frank"].filter(n => n.startsWith(value));
305
- } else if (department === "marketing") {
306
- return ["Grace", "Henry", "Iris"].filter(n => n.startsWith(value));
302
+ 'team-greeting',
303
+ {
304
+ title: 'Team Greeting',
305
+ description: 'Generate a greeting for team members',
306
+ argsSchema: {
307
+ department: completable(z.string(), value => {
308
+ // Department suggestions
309
+ return ['engineering', 'sales', 'marketing', 'support'].filter(d => d.startsWith(value));
310
+ }),
311
+ name: completable(z.string(), (value, context) => {
312
+ // Name suggestions based on selected department
313
+ const department = context?.arguments?.['department'];
314
+ if (department === 'engineering') {
315
+ return ['Alice', 'Bob', 'Charlie'].filter(n => n.startsWith(value));
316
+ } else if (department === 'sales') {
317
+ return ['David', 'Eve', 'Frank'].filter(n => n.startsWith(value));
318
+ } else if (department === 'marketing') {
319
+ return ['Grace', 'Henry', 'Iris'].filter(n => n.startsWith(value));
320
+ }
321
+ return ['Guest'].filter(n => n.startsWith(value));
322
+ })
307
323
  }
308
- return ["Guest"].filter(n => n.startsWith(value));
309
- })
310
- }
311
- },
312
- ({ department, name }) => ({
313
- messages: [{
314
- role: "assistant",
315
- content: {
316
- type: "text",
317
- text: `Hello ${name}, welcome to the ${department} team!`
318
- }
319
- }]
320
- })
324
+ },
325
+ ({ department, name }) => ({
326
+ messages: [
327
+ {
328
+ role: 'assistant',
329
+ content: {
330
+ type: 'text',
331
+ text: `Hello ${name}, welcome to the ${department} team!`
332
+ }
333
+ }
334
+ ]
335
+ })
321
336
  );
322
337
  ```
323
338
 
@@ -330,21 +345,21 @@ MCP supports argument completions to help users fill in prompt arguments and res
330
345
  ```typescript
331
346
  // Request completions for any argument
332
347
  const result = await client.complete({
333
- ref: {
334
- type: "ref/prompt", // or "ref/resource"
335
- name: "example" // or uri: "template://..."
336
- },
337
- argument: {
338
- name: "argumentName",
339
- value: "partial" // What the user has typed so far
340
- },
341
- context: { // Optional: Include previously resolved arguments
342
- arguments: {
343
- previousArg: "value"
348
+ ref: {
349
+ type: 'ref/prompt', // or "ref/resource"
350
+ name: 'example' // or uri: "template://..."
351
+ },
352
+ argument: {
353
+ name: 'argumentName',
354
+ value: 'partial' // What the user has typed so far
355
+ },
356
+ context: {
357
+ // Optional: Include previously resolved arguments
358
+ arguments: {
359
+ previousArg: 'value'
360
+ }
344
361
  }
345
- }
346
362
  });
347
-
348
363
  ```
349
364
 
350
365
  ### Display Names and Metadata
@@ -356,6 +371,7 @@ All resources, tools, and prompts support an optional `title` field for better U
356
371
  #### Title Precedence for Tools
357
372
 
358
373
  For tools specifically, there are two ways to specify a title:
374
+
359
375
  - `title` field in the tool configuration
360
376
  - `annotations.title` field (when using the older `tool()` method with annotations)
361
377
 
@@ -363,23 +379,32 @@ The precedence order is: `title` → `annotations.title` → `name`
363
379
 
364
380
  ```typescript
365
381
  // Using registerTool (recommended)
366
- server.registerTool("my_tool", {
367
- title: "My Tool", // This title takes precedence
368
- annotations: {
369
- title: "Annotation Title" // This is ignored if title is set
370
- }
371
- }, handler);
382
+ server.registerTool(
383
+ 'my_tool',
384
+ {
385
+ title: 'My Tool', // This title takes precedence
386
+ annotations: {
387
+ title: 'Annotation Title' // This is ignored if title is set
388
+ }
389
+ },
390
+ handler
391
+ );
372
392
 
373
393
  // Using tool with annotations (older API)
374
- server.tool("my_tool", "description", {
375
- title: "Annotation Title" // This is used as title
376
- }, handler);
394
+ server.tool(
395
+ 'my_tool',
396
+ 'description',
397
+ {
398
+ title: 'Annotation Title' // This is used as title
399
+ },
400
+ handler
401
+ );
377
402
  ```
378
403
 
379
404
  When building clients, use the provided utility to get the appropriate display name:
380
405
 
381
406
  ```typescript
382
- import { getDisplayName } from "@modelcontextprotocol/sdk/shared/metadataUtils.js";
407
+ import { getDisplayName } from '@modelcontextprotocol/sdk/shared/metadataUtils.js';
383
408
 
384
409
  // Automatically handles the precedence: title → annotations.title → name
385
410
  const displayName = getDisplayName(tool);
@@ -390,63 +415,62 @@ const displayName = getDisplayName(tool);
390
415
  MCP servers can request LLM completions from connected clients that support sampling.
391
416
 
392
417
  ```typescript
393
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
394
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
395
- import { z } from "zod";
418
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
419
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
420
+ import { z } from 'zod';
396
421
 
397
422
  const mcpServer = new McpServer({
398
- name: "tools-with-sample-server",
399
- version: "1.0.0",
423
+ name: 'tools-with-sample-server',
424
+ version: '1.0.0'
400
425
  });
401
426
 
402
427
  // Tool that uses LLM sampling to summarize any text
403
428
  mcpServer.registerTool(
404
- "summarize",
405
- {
406
- description: "Summarize any text using an LLM",
407
- inputSchema: {
408
- text: z.string().describe("Text to summarize"),
429
+ 'summarize',
430
+ {
431
+ description: 'Summarize any text using an LLM',
432
+ inputSchema: {
433
+ text: z.string().describe('Text to summarize')
434
+ }
409
435
  },
410
- },
411
- async ({ text }) => {
412
- // Call the LLM through MCP sampling
413
- const response = await mcpServer.server.createMessage({
414
- messages: [
415
- {
416
- role: "user",
417
- content: {
418
- type: "text",
419
- text: `Please summarize the following text concisely:\n\n${text}`,
420
- },
421
- },
422
- ],
423
- maxTokens: 500,
424
- });
436
+ async ({ text }) => {
437
+ // Call the LLM through MCP sampling
438
+ const response = await mcpServer.server.createMessage({
439
+ messages: [
440
+ {
441
+ role: 'user',
442
+ content: {
443
+ type: 'text',
444
+ text: `Please summarize the following text concisely:\n\n${text}`
445
+ }
446
+ }
447
+ ],
448
+ maxTokens: 500
449
+ });
425
450
 
426
- return {
427
- content: [
428
- {
429
- type: "text",
430
- text: response.content.type === "text" ? response.content.text : "Unable to generate summary",
431
- },
432
- ],
433
- };
434
- }
451
+ return {
452
+ content: [
453
+ {
454
+ type: 'text',
455
+ text: response.content.type === 'text' ? response.content.text : 'Unable to generate summary'
456
+ }
457
+ ]
458
+ };
459
+ }
435
460
  );
436
461
 
437
462
  async function main() {
438
- const transport = new StdioServerTransport();
439
- await mcpServer.connect(transport);
440
- console.log("MCP server is running...");
463
+ const transport = new StdioServerTransport();
464
+ await mcpServer.connect(transport);
465
+ console.error('MCP server is running...');
441
466
  }
442
467
 
443
- main().catch((error) => {
444
- console.error("Server error:", error);
445
- process.exit(1);
468
+ main().catch(error => {
469
+ console.error('Server error:', error);
470
+ process.exit(1);
446
471
  });
447
472
  ```
448
473
 
449
-
450
474
  ## Running Your Server
451
475
 
452
476
  MCP servers in TypeScript need to be connected to a transport to communicate with clients. How you start the server depends on the choice of transport:
@@ -456,12 +480,12 @@ MCP servers in TypeScript need to be connected to a transport to communicate wit
456
480
  For command-line tools and direct integrations:
457
481
 
458
482
  ```typescript
459
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
460
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
483
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
484
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
461
485
 
462
486
  const server = new McpServer({
463
- name: "example-server",
464
- version: "1.0.0"
487
+ name: 'example-server',
488
+ version: '1.0.0'
465
489
  });
466
490
 
467
491
  // ... set up server resources, tools, and prompts ...
@@ -479,13 +503,11 @@ For remote servers, set up a Streamable HTTP transport that handles both client
479
503
  In some cases, servers need to be stateful. This is achieved by [session management](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#session-management).
480
504
 
481
505
  ```typescript
482
- import express from "express";
483
- import { randomUUID } from "node:crypto";
484
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
485
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
486
- import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"
487
-
488
-
506
+ import express from 'express';
507
+ import { randomUUID } from 'node:crypto';
508
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
509
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
510
+ import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
489
511
 
490
512
  const app = express();
491
513
  app.use(express.json());
@@ -495,69 +517,69 @@ const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
495
517
 
496
518
  // Handle POST requests for client-to-server communication
497
519
  app.post('/mcp', async (req, res) => {
498
- // Check for existing session ID
499
- const sessionId = req.headers['mcp-session-id'] as string | undefined;
500
- let transport: StreamableHTTPServerTransport;
501
-
502
- if (sessionId && transports[sessionId]) {
503
- // Reuse existing transport
504
- transport = transports[sessionId];
505
- } else if (!sessionId && isInitializeRequest(req.body)) {
506
- // New initialization request
507
- transport = new StreamableHTTPServerTransport({
508
- sessionIdGenerator: () => randomUUID(),
509
- onsessioninitialized: (sessionId) => {
510
- // Store the transport by session ID
511
- transports[sessionId] = transport;
512
- },
513
- // DNS rebinding protection is disabled by default for backwards compatibility. If you are running this server
514
- // locally, make sure to set:
515
- // enableDnsRebindingProtection: true,
516
- // allowedHosts: ['127.0.0.1'],
517
- });
518
-
519
- // Clean up transport when closed
520
- transport.onclose = () => {
521
- if (transport.sessionId) {
522
- delete transports[transport.sessionId];
523
- }
524
- };
525
- const server = new McpServer({
526
- name: "example-server",
527
- version: "1.0.0"
528
- });
520
+ // Check for existing session ID
521
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
522
+ let transport: StreamableHTTPServerTransport;
523
+
524
+ if (sessionId && transports[sessionId]) {
525
+ // Reuse existing transport
526
+ transport = transports[sessionId];
527
+ } else if (!sessionId && isInitializeRequest(req.body)) {
528
+ // New initialization request
529
+ transport = new StreamableHTTPServerTransport({
530
+ sessionIdGenerator: () => randomUUID(),
531
+ onsessioninitialized: sessionId => {
532
+ // Store the transport by session ID
533
+ transports[sessionId] = transport;
534
+ }
535
+ // DNS rebinding protection is disabled by default for backwards compatibility. If you are running this server
536
+ // locally, make sure to set:
537
+ // enableDnsRebindingProtection: true,
538
+ // allowedHosts: ['127.0.0.1'],
539
+ });
540
+
541
+ // Clean up transport when closed
542
+ transport.onclose = () => {
543
+ if (transport.sessionId) {
544
+ delete transports[transport.sessionId];
545
+ }
546
+ };
547
+ const server = new McpServer({
548
+ name: 'example-server',
549
+ version: '1.0.0'
550
+ });
529
551
 
530
- // ... set up server resources, tools, and prompts ...
552
+ // ... set up server resources, tools, and prompts ...
531
553
 
532
- // Connect to the MCP server
533
- await server.connect(transport);
534
- } else {
535
- // Invalid request
536
- res.status(400).json({
537
- jsonrpc: '2.0',
538
- error: {
539
- code: -32000,
540
- message: 'Bad Request: No valid session ID provided',
541
- },
542
- id: null,
543
- });
544
- return;
545
- }
554
+ // Connect to the MCP server
555
+ await server.connect(transport);
556
+ } else {
557
+ // Invalid request
558
+ res.status(400).json({
559
+ jsonrpc: '2.0',
560
+ error: {
561
+ code: -32000,
562
+ message: 'Bad Request: No valid session ID provided'
563
+ },
564
+ id: null
565
+ });
566
+ return;
567
+ }
546
568
 
547
- // Handle the request
548
- await transport.handleRequest(req, res, req.body);
569
+ // Handle the request
570
+ await transport.handleRequest(req, res, req.body);
549
571
  });
550
572
 
551
573
  // Reusable handler for GET and DELETE requests
552
574
  const handleSessionRequest = async (req: express.Request, res: express.Response) => {
553
- const sessionId = req.headers['mcp-session-id'] as string | undefined;
554
- if (!sessionId || !transports[sessionId]) {
555
- res.status(400).send('Invalid or missing session ID');
556
- return;
557
- }
558
-
559
- const transport = transports[sessionId];
560
- await transport.handleRequest(req, res);
575
+ const sessionId = req.headers['mcp-session-id'] as string | undefined;
576
+ if (!sessionId || !transports[sessionId]) {
577
+ res.status(400).send('Invalid or missing session ID');
578
+ return;
579
+ }
580
+
581
+ const transport = transports[sessionId];
582
+ await transport.handleRequest(req, res);
561
583
  };
562
584
 
563
585
  // Handle GET requests for server-to-client notifications via SSE
@@ -569,9 +591,7 @@ app.delete('/mcp', handleSessionRequest);
569
591
  app.listen(3000);
570
592
  ```
571
593
 
572
- > [!TIP]
573
- > When using this in a remote environment, make sure to allow the header parameter `mcp-session-id` in CORS. Otherwise, it may result in a `Bad Request: No valid session ID provided` error. Read the following section for examples.
574
-
594
+ > [!TIP] When using this in a remote environment, make sure to allow the header parameter `mcp-session-id` in CORS. Otherwise, it may result in a `Bad Request: No valid session ID provided` error. Read the following section for examples.
575
595
 
576
596
  #### CORS Configuration for Browser-Based Clients
577
597
 
@@ -581,15 +601,18 @@ If you'd like your server to be accessible by browser-based MCP clients, you'll
581
601
  import cors from 'cors';
582
602
 
583
603
  // Add CORS middleware before your MCP routes
584
- app.use(cors({
585
- origin: '*', // Configure appropriately for production, for example:
586
- // origin: ['https://your-remote-domain.com', 'https://your-other-remote-domain.com'],
587
- exposedHeaders: ['Mcp-Session-Id'],
588
- allowedHeaders: ['Content-Type', 'mcp-session-id'],
589
- }));
604
+ app.use(
605
+ cors({
606
+ origin: '*', // Configure appropriately for production, for example:
607
+ // origin: ['https://your-remote-domain.com', 'https://your-other-remote-domain.com'],
608
+ exposedHeaders: ['Mcp-Session-Id'],
609
+ allowedHeaders: ['Content-Type', 'mcp-session-id']
610
+ })
611
+ );
590
612
  ```
591
613
 
592
614
  This configuration is necessary because:
615
+
593
616
  - The MCP streamable HTTP transport uses the `Mcp-Session-Id` header for session management
594
617
  - Browsers restrict access to response headers unless explicitly exposed via CORS
595
618
  - Without this configuration, browser-based clients won't be able to read the session ID from initialization responses
@@ -603,79 +626,83 @@ const app = express();
603
626
  app.use(express.json());
604
627
 
605
628
  app.post('/mcp', async (req: Request, res: Response) => {
606
- // In stateless mode, create a new instance of transport and server for each request
607
- // to ensure complete isolation. A single instance would cause request ID collisions
608
- // when multiple clients connect concurrently.
609
-
610
- try {
611
- const server = getServer();
612
- const transport: StreamableHTTPServerTransport = new StreamableHTTPServerTransport({
613
- sessionIdGenerator: undefined,
614
- });
615
- res.on('close', () => {
616
- console.log('Request closed');
617
- transport.close();
618
- server.close();
619
- });
620
- await server.connect(transport);
621
- await transport.handleRequest(req, res, req.body);
622
- } catch (error) {
623
- console.error('Error handling MCP request:', error);
624
- if (!res.headersSent) {
625
- res.status(500).json({
626
- jsonrpc: '2.0',
627
- error: {
628
- code: -32603,
629
- message: 'Internal server error',
630
- },
631
- id: null,
632
- });
629
+ // In stateless mode, create a new instance of transport and server for each request
630
+ // to ensure complete isolation. A single instance would cause request ID collisions
631
+ // when multiple clients connect concurrently.
632
+
633
+ try {
634
+ const server = getServer();
635
+ const transport: StreamableHTTPServerTransport = new StreamableHTTPServerTransport({
636
+ sessionIdGenerator: undefined
637
+ });
638
+ res.on('close', () => {
639
+ console.log('Request closed');
640
+ transport.close();
641
+ server.close();
642
+ });
643
+ await server.connect(transport);
644
+ await transport.handleRequest(req, res, req.body);
645
+ } catch (error) {
646
+ console.error('Error handling MCP request:', error);
647
+ if (!res.headersSent) {
648
+ res.status(500).json({
649
+ jsonrpc: '2.0',
650
+ error: {
651
+ code: -32603,
652
+ message: 'Internal server error'
653
+ },
654
+ id: null
655
+ });
656
+ }
633
657
  }
634
- }
635
658
  });
636
659
 
637
660
  // SSE notifications not supported in stateless mode
638
661
  app.get('/mcp', async (req: Request, res: Response) => {
639
- console.log('Received GET MCP request');
640
- res.writeHead(405).end(JSON.stringify({
641
- jsonrpc: "2.0",
642
- error: {
643
- code: -32000,
644
- message: "Method not allowed."
645
- },
646
- id: null
647
- }));
662
+ console.log('Received GET MCP request');
663
+ res.writeHead(405).end(
664
+ JSON.stringify({
665
+ jsonrpc: '2.0',
666
+ error: {
667
+ code: -32000,
668
+ message: 'Method not allowed.'
669
+ },
670
+ id: null
671
+ })
672
+ );
648
673
  });
649
674
 
650
675
  // Session termination not needed in stateless mode
651
676
  app.delete('/mcp', async (req: Request, res: Response) => {
652
- console.log('Received DELETE MCP request');
653
- res.writeHead(405).end(JSON.stringify({
654
- jsonrpc: "2.0",
655
- error: {
656
- code: -32000,
657
- message: "Method not allowed."
658
- },
659
- id: null
660
- }));
677
+ console.log('Received DELETE MCP request');
678
+ res.writeHead(405).end(
679
+ JSON.stringify({
680
+ jsonrpc: '2.0',
681
+ error: {
682
+ code: -32000,
683
+ message: 'Method not allowed.'
684
+ },
685
+ id: null
686
+ })
687
+ );
661
688
  });
662
689
 
663
-
664
690
  // Start the server
665
691
  const PORT = 3000;
666
- setupServer().then(() => {
667
- app.listen(PORT, (error) => {
668
- if (error) {
669
- console.error('Failed to start server:', error);
670
- process.exit(1);
671
- }
672
- console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`);
673
- });
674
- }).catch(error => {
675
- console.error('Failed to set up the server:', error);
676
- process.exit(1);
677
- });
678
-
692
+ setupServer()
693
+ .then(() => {
694
+ app.listen(PORT, error => {
695
+ if (error) {
696
+ console.error('Failed to start server:', error);
697
+ process.exit(1);
698
+ }
699
+ console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`);
700
+ });
701
+ })
702
+ .catch(error => {
703
+ console.error('Failed to set up the server:', error);
704
+ process.exit(1);
705
+ });
679
706
  ```
680
707
 
681
708
  This stateless approach is useful for:
@@ -711,57 +738,61 @@ To test your server, you can use the [MCP Inspector](https://github.com/modelcon
711
738
  A simple server demonstrating resources, tools, and prompts:
712
739
 
713
740
  ```typescript
714
- import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
715
- import { z } from "zod";
741
+ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
742
+ import { z } from 'zod';
716
743
 
717
744
  const server = new McpServer({
718
- name: "echo-server",
719
- version: "1.0.0"
745
+ name: 'echo-server',
746
+ version: '1.0.0'
720
747
  });
721
748
 
722
749
  server.registerResource(
723
- "echo",
724
- new ResourceTemplate("echo://{message}", { list: undefined }),
725
- {
726
- title: "Echo Resource",
727
- description: "Echoes back messages as resources"
728
- },
729
- async (uri, { message }) => ({
730
- contents: [{
731
- uri: uri.href,
732
- text: `Resource echo: ${message}`
733
- }]
734
- })
750
+ 'echo',
751
+ new ResourceTemplate('echo://{message}', { list: undefined }),
752
+ {
753
+ title: 'Echo Resource',
754
+ description: 'Echoes back messages as resources'
755
+ },
756
+ async (uri, { message }) => ({
757
+ contents: [
758
+ {
759
+ uri: uri.href,
760
+ text: `Resource echo: ${message}`
761
+ }
762
+ ]
763
+ })
735
764
  );
736
765
 
737
766
  server.registerTool(
738
- "echo",
739
- {
740
- title: "Echo Tool",
741
- description: "Echoes back the provided message",
742
- inputSchema: { message: z.string() }
743
- },
744
- async ({ message }) => ({
745
- content: [{ type: "text", text: `Tool echo: ${message}` }]
746
- })
767
+ 'echo',
768
+ {
769
+ title: 'Echo Tool',
770
+ description: 'Echoes back the provided message',
771
+ inputSchema: { message: z.string() }
772
+ },
773
+ async ({ message }) => ({
774
+ content: [{ type: 'text', text: `Tool echo: ${message}` }]
775
+ })
747
776
  );
748
777
 
749
778
  server.registerPrompt(
750
- "echo",
751
- {
752
- title: "Echo Prompt",
753
- description: "Creates a prompt to process a message",
754
- argsSchema: { message: z.string() }
755
- },
756
- ({ message }) => ({
757
- messages: [{
758
- role: "user",
759
- content: {
760
- type: "text",
761
- text: `Please process this message: ${message}`
762
- }
763
- }]
764
- })
779
+ 'echo',
780
+ {
781
+ title: 'Echo Prompt',
782
+ description: 'Creates a prompt to process a message',
783
+ argsSchema: { message: z.string() }
784
+ },
785
+ ({ message }) => ({
786
+ messages: [
787
+ {
788
+ role: 'user',
789
+ content: {
790
+ type: 'text',
791
+ text: `Please process this message: ${message}`
792
+ }
793
+ }
794
+ ]
795
+ })
765
796
  );
766
797
  ```
767
798
 
@@ -770,81 +801,85 @@ server.registerPrompt(
770
801
  A more complex example showing database integration:
771
802
 
772
803
  ```typescript
773
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
774
- import sqlite3 from "sqlite3";
775
- import { promisify } from "util";
776
- import { z } from "zod";
804
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
805
+ import sqlite3 from 'sqlite3';
806
+ import { promisify } from 'util';
807
+ import { z } from 'zod';
777
808
 
778
809
  const server = new McpServer({
779
- name: "sqlite-explorer",
780
- version: "1.0.0"
810
+ name: 'sqlite-explorer',
811
+ version: '1.0.0'
781
812
  });
782
813
 
783
814
  // Helper to create DB connection
784
815
  const getDb = () => {
785
- const db = new sqlite3.Database("database.db");
786
- return {
787
- all: promisify<string, any[]>(db.all.bind(db)),
788
- close: promisify(db.close.bind(db))
789
- };
816
+ const db = new sqlite3.Database('database.db');
817
+ return {
818
+ all: promisify<string, any[]>(db.all.bind(db)),
819
+ close: promisify(db.close.bind(db))
820
+ };
790
821
  };
791
822
 
792
823
  server.registerResource(
793
- "schema",
794
- "schema://main",
795
- {
796
- title: "Database Schema",
797
- description: "SQLite database schema",
798
- mimeType: "text/plain"
799
- },
800
- async (uri) => {
801
- const db = getDb();
802
- try {
803
- const tables = await db.all(
804
- "SELECT sql FROM sqlite_master WHERE type='table'"
805
- );
806
- return {
807
- contents: [{
808
- uri: uri.href,
809
- text: tables.map((t: {sql: string}) => t.sql).join("\n")
810
- }]
811
- };
812
- } finally {
813
- await db.close();
824
+ 'schema',
825
+ 'schema://main',
826
+ {
827
+ title: 'Database Schema',
828
+ description: 'SQLite database schema',
829
+ mimeType: 'text/plain'
830
+ },
831
+ async uri => {
832
+ const db = getDb();
833
+ try {
834
+ const tables = await db.all("SELECT sql FROM sqlite_master WHERE type='table'");
835
+ return {
836
+ contents: [
837
+ {
838
+ uri: uri.href,
839
+ text: tables.map((t: { sql: string }) => t.sql).join('\n')
840
+ }
841
+ ]
842
+ };
843
+ } finally {
844
+ await db.close();
845
+ }
814
846
  }
815
- }
816
847
  );
817
848
 
818
849
  server.registerTool(
819
- "query",
820
- {
821
- title: "SQL Query",
822
- description: "Execute SQL queries on the database",
823
- inputSchema: { sql: z.string() }
824
- },
825
- async ({ sql }) => {
826
- const db = getDb();
827
- try {
828
- const results = await db.all(sql);
829
- return {
830
- content: [{
831
- type: "text",
832
- text: JSON.stringify(results, null, 2)
833
- }]
834
- };
835
- } catch (err: unknown) {
836
- const error = err as Error;
837
- return {
838
- content: [{
839
- type: "text",
840
- text: `Error: ${error.message}`
841
- }],
842
- isError: true
843
- };
844
- } finally {
845
- await db.close();
850
+ 'query',
851
+ {
852
+ title: 'SQL Query',
853
+ description: 'Execute SQL queries on the database',
854
+ inputSchema: { sql: z.string() }
855
+ },
856
+ async ({ sql }) => {
857
+ const db = getDb();
858
+ try {
859
+ const results = await db.all(sql);
860
+ return {
861
+ content: [
862
+ {
863
+ type: 'text',
864
+ text: JSON.stringify(results, null, 2)
865
+ }
866
+ ]
867
+ };
868
+ } catch (err: unknown) {
869
+ const error = err as Error;
870
+ return {
871
+ content: [
872
+ {
873
+ type: 'text',
874
+ text: `Error: ${error.message}`
875
+ }
876
+ ],
877
+ isError: true
878
+ };
879
+ } finally {
880
+ await db.close();
881
+ }
846
882
  }
847
- }
848
883
  );
849
884
  ```
850
885
 
@@ -855,57 +890,49 @@ server.registerTool(
855
890
  If you want to offer an initial set of tools/prompts/resources, but later add additional ones based on user action or external state change, you can add/update/remove them _after_ the Server is connected. This will automatically emit the corresponding `listChanged` notifications:
856
891
 
857
892
  ```ts
858
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
859
- import { z } from "zod";
893
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
894
+ import { z } from 'zod';
860
895
 
861
896
  const server = new McpServer({
862
- name: "Dynamic Example",
863
- version: "1.0.0"
897
+ name: 'Dynamic Example',
898
+ version: '1.0.0'
864
899
  });
865
900
 
866
- const listMessageTool = server.tool(
867
- "listMessages",
868
- { channel: z.string() },
869
- async ({ channel }) => ({
870
- content: [{ type: "text", text: await listMessages(channel) }]
871
- })
872
- );
901
+ const listMessageTool = server.tool('listMessages', { channel: z.string() }, async ({ channel }) => ({
902
+ content: [{ type: 'text', text: await listMessages(channel) }]
903
+ }));
873
904
 
874
- const putMessageTool = server.tool(
875
- "putMessage",
876
- { channel: z.string(), message: z.string() },
877
- async ({ channel, message }) => ({
878
- content: [{ type: "text", text: await putMessage(channel, message) }]
879
- })
880
- );
905
+ const putMessageTool = server.tool('putMessage', { channel: z.string(), message: z.string() }, async ({ channel, message }) => ({
906
+ content: [{ type: 'text', text: await putMessage(channel, message) }]
907
+ }));
881
908
  // Until we upgrade auth, `putMessage` is disabled (won't show up in listTools)
882
- putMessageTool.disable()
909
+ putMessageTool.disable();
883
910
 
884
911
  const upgradeAuthTool = server.tool(
885
- "upgradeAuth",
886
- { permission: z.enum(["write", "admin"])},
887
- // Any mutations here will automatically emit `listChanged` notifications
888
- async ({ permission }) => {
889
- const { ok, err, previous } = await upgradeAuthAndStoreToken(permission)
890
- if (!ok) return {content: [{ type: "text", text: `Error: ${err}` }]}
891
-
892
- // If we previously had read-only access, 'putMessage' is now available
893
- if (previous === "read") {
894
- putMessageTool.enable()
895
- }
912
+ 'upgradeAuth',
913
+ { permission: z.enum(['write', 'admin']) },
914
+ // Any mutations here will automatically emit `listChanged` notifications
915
+ async ({ permission }) => {
916
+ const { ok, err, previous } = await upgradeAuthAndStoreToken(permission);
917
+ if (!ok) return { content: [{ type: 'text', text: `Error: ${err}` }] };
918
+
919
+ // If we previously had read-only access, 'putMessage' is now available
920
+ if (previous === 'read') {
921
+ putMessageTool.enable();
922
+ }
896
923
 
897
- if (permission === 'write') {
898
- // If we've just upgraded to 'write' permissions, we can still call 'upgradeAuth'
899
- // but can only upgrade to 'admin'.
900
- upgradeAuthTool.update({
901
- paramsSchema: { permission: z.enum(["admin"]) }, // change validation rules
902
- })
903
- } else {
904
- // If we're now an admin, we no longer have anywhere to upgrade to, so fully remove that tool
905
- upgradeAuthTool.remove()
924
+ if (permission === 'write') {
925
+ // If we've just upgraded to 'write' permissions, we can still call 'upgradeAuth'
926
+ // but can only upgrade to 'admin'.
927
+ upgradeAuthTool.update({
928
+ paramsSchema: { permission: z.enum(['admin']) } // change validation rules
929
+ });
930
+ } else {
931
+ // If we're now an admin, we no longer have anywhere to upgrade to, so fully remove that tool
932
+ upgradeAuthTool.remove();
933
+ }
906
934
  }
907
- }
908
- )
935
+ );
909
936
 
910
937
  // Connect as normal
911
938
  const transport = new StdioServerTransport();
@@ -918,8 +945,8 @@ When performing bulk updates that trigger notifications (e.g., enabling or disab
918
945
 
919
946
  This feature coalesces multiple, rapid calls for the same notification type into a single message. For example, if you disable five tools in a row, only one `notifications/tools/list_changed` message will be sent instead of five.
920
947
 
921
- > [!IMPORTANT]
922
- > This feature is designed for "simple" notifications that do not carry unique data in their parameters. To prevent silent data loss, debouncing is **automatically bypassed** for any notification that contains a `params` object or a `relatedRequestId`. Such notifications will always be sent immediately.
948
+ > [!IMPORTANT] This feature is designed for "simple" notifications that do not carry unique data in their parameters. To prevent silent data loss, debouncing is **automatically bypassed** for any notification that contains a `params` object or a `relatedRequestId`. Such
949
+ > notifications will always be sent immediately.
923
950
 
924
951
  This is an opt-in feature configured during server initialization.
925
952
 
@@ -954,53 +981,56 @@ server.registerTool("tool3", ...).disable();
954
981
  For more control, you can use the low-level Server class directly:
955
982
 
956
983
  ```typescript
957
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
958
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
959
- import {
960
- ListPromptsRequestSchema,
961
- GetPromptRequestSchema
962
- } from "@modelcontextprotocol/sdk/types.js";
984
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
985
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
986
+ import { ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
963
987
 
964
988
  const server = new Server(
965
- {
966
- name: "example-server",
967
- version: "1.0.0"
968
- },
969
- {
970
- capabilities: {
971
- prompts: {}
989
+ {
990
+ name: 'example-server',
991
+ version: '1.0.0'
992
+ },
993
+ {
994
+ capabilities: {
995
+ prompts: {}
996
+ }
972
997
  }
973
- }
974
998
  );
975
999
 
976
1000
  server.setRequestHandler(ListPromptsRequestSchema, async () => {
977
- return {
978
- prompts: [{
979
- name: "example-prompt",
980
- description: "An example prompt template",
981
- arguments: [{
982
- name: "arg1",
983
- description: "Example argument",
984
- required: true
985
- }]
986
- }]
987
- };
1001
+ return {
1002
+ prompts: [
1003
+ {
1004
+ name: 'example-prompt',
1005
+ description: 'An example prompt template',
1006
+ arguments: [
1007
+ {
1008
+ name: 'arg1',
1009
+ description: 'Example argument',
1010
+ required: true
1011
+ }
1012
+ ]
1013
+ }
1014
+ ]
1015
+ };
988
1016
  });
989
1017
 
990
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
991
- if (request.params.name !== "example-prompt") {
992
- throw new Error("Unknown prompt");
993
- }
994
- return {
995
- description: "Example prompt",
996
- messages: [{
997
- role: "user",
998
- content: {
999
- type: "text",
1000
- text: "Example prompt text"
1001
- }
1002
- }]
1003
- };
1018
+ server.setRequestHandler(GetPromptRequestSchema, async request => {
1019
+ if (request.params.name !== 'example-prompt') {
1020
+ throw new Error('Unknown prompt');
1021
+ }
1022
+ return {
1023
+ description: 'Example prompt',
1024
+ messages: [
1025
+ {
1026
+ role: 'user',
1027
+ content: {
1028
+ type: 'text',
1029
+ text: 'Example prompt text'
1030
+ }
1031
+ }
1032
+ ]
1033
+ };
1004
1034
  });
1005
1035
 
1006
1036
  const transport = new StdioServerTransport();
@@ -1014,72 +1044,73 @@ MCP servers can request additional information from users through the elicitatio
1014
1044
  ```typescript
1015
1045
  // Server-side: Restaurant booking tool that asks for alternatives
1016
1046
  server.tool(
1017
- "book-restaurant",
1018
- {
1019
- restaurant: z.string(),
1020
- date: z.string(),
1021
- partySize: z.number()
1022
- },
1023
- async ({ restaurant, date, partySize }) => {
1024
- // Check availability
1025
- const available = await checkAvailability(restaurant, date, partySize);
1026
-
1027
- if (!available) {
1028
- // Ask user if they want to try alternative dates
1029
- const result = await server.server.elicitInput({
1030
- message: `No tables available at ${restaurant} on ${date}. Would you like to check alternative dates?`,
1031
- requestedSchema: {
1032
- type: "object",
1033
- properties: {
1034
- checkAlternatives: {
1035
- type: "boolean",
1036
- title: "Check alternative dates",
1037
- description: "Would you like me to check other dates?"
1038
- },
1039
- flexibleDates: {
1040
- type: "string",
1041
- title: "Date flexibility",
1042
- description: "How flexible are your dates?",
1043
- enum: ["next_day", "same_week", "next_week"],
1044
- enumNames: ["Next day", "Same week", "Next week"]
1047
+ 'book-restaurant',
1048
+ {
1049
+ restaurant: z.string(),
1050
+ date: z.string(),
1051
+ partySize: z.number()
1052
+ },
1053
+ async ({ restaurant, date, partySize }) => {
1054
+ // Check availability
1055
+ const available = await checkAvailability(restaurant, date, partySize);
1056
+
1057
+ if (!available) {
1058
+ // Ask user if they want to try alternative dates
1059
+ const result = await server.server.elicitInput({
1060
+ message: `No tables available at ${restaurant} on ${date}. Would you like to check alternative dates?`,
1061
+ requestedSchema: {
1062
+ type: 'object',
1063
+ properties: {
1064
+ checkAlternatives: {
1065
+ type: 'boolean',
1066
+ title: 'Check alternative dates',
1067
+ description: 'Would you like me to check other dates?'
1068
+ },
1069
+ flexibleDates: {
1070
+ type: 'string',
1071
+ title: 'Date flexibility',
1072
+ description: 'How flexible are your dates?',
1073
+ enum: ['next_day', 'same_week', 'next_week'],
1074
+ enumNames: ['Next day', 'Same week', 'Next week']
1075
+ }
1076
+ },
1077
+ required: ['checkAlternatives']
1078
+ }
1079
+ });
1080
+
1081
+ if (result.action === 'accept' && result.content?.checkAlternatives) {
1082
+ const alternatives = await findAlternatives(restaurant, date, partySize, result.content.flexibleDates as string);
1083
+ return {
1084
+ content: [
1085
+ {
1086
+ type: 'text',
1087
+ text: `Found these alternatives: ${alternatives.join(', ')}`
1088
+ }
1089
+ ]
1090
+ };
1045
1091
  }
1046
- },
1047
- required: ["checkAlternatives"]
1092
+
1093
+ return {
1094
+ content: [
1095
+ {
1096
+ type: 'text',
1097
+ text: 'No booking made. Original date not available.'
1098
+ }
1099
+ ]
1100
+ };
1048
1101
  }
1049
- });
1050
-
1051
- if (result.action === "accept" && result.content?.checkAlternatives) {
1052
- const alternatives = await findAlternatives(
1053
- restaurant,
1054
- date,
1055
- partySize,
1056
- result.content.flexibleDates as string
1057
- );
1102
+
1103
+ // Book the table
1104
+ await makeBooking(restaurant, date, partySize);
1058
1105
  return {
1059
- content: [{
1060
- type: "text",
1061
- text: `Found these alternatives: ${alternatives.join(", ")}`
1062
- }]
1106
+ content: [
1107
+ {
1108
+ type: 'text',
1109
+ text: `Booked table for ${partySize} at ${restaurant} on ${date}`
1110
+ }
1111
+ ]
1063
1112
  };
1064
- }
1065
-
1066
- return {
1067
- content: [{
1068
- type: "text",
1069
- text: "No booking made. Original date not available."
1070
- }]
1071
- };
1072
1113
  }
1073
-
1074
- // Book the table
1075
- await makeBooking(restaurant, date, partySize);
1076
- return {
1077
- content: [{
1078
- type: "text",
1079
- text: `Booked table for ${partySize} at ${restaurant} on ${date}`
1080
- }]
1081
- };
1082
- }
1083
1114
  );
1084
1115
  ```
1085
1116
 
@@ -1087,24 +1118,24 @@ Client-side: Handle elicitation requests
1087
1118
 
1088
1119
  ```typescript
1089
1120
  // This is a placeholder - implement based on your UI framework
1090
- async function getInputFromUser(message: string, schema: any): Promise<{
1091
- action: "accept" | "decline" | "cancel";
1092
- data?: Record<string, any>;
1121
+ async function getInputFromUser(
1122
+ message: string,
1123
+ schema: any
1124
+ ): Promise<{
1125
+ action: 'accept' | 'decline' | 'cancel';
1126
+ data?: Record<string, any>;
1093
1127
  }> {
1094
- // This should be implemented depending on the app
1095
- throw new Error("getInputFromUser must be implemented for your platform");
1128
+ // This should be implemented depending on the app
1129
+ throw new Error('getInputFromUser must be implemented for your platform');
1096
1130
  }
1097
1131
 
1098
- client.setRequestHandler(ElicitRequestSchema, async (request) => {
1099
- const userResponse = await getInputFromUser(
1100
- request.params.message,
1101
- request.params.requestedSchema
1102
- );
1103
-
1104
- return {
1105
- action: userResponse.action,
1106
- content: userResponse.action === "accept" ? userResponse.data : undefined
1107
- };
1132
+ client.setRequestHandler(ElicitRequestSchema, async request => {
1133
+ const userResponse = await getInputFromUser(request.params.message, request.params.requestedSchema);
1134
+
1135
+ return {
1136
+ action: userResponse.action,
1137
+ content: userResponse.action === 'accept' ? userResponse.data : undefined
1138
+ };
1108
1139
  });
1109
1140
  ```
1110
1141
 
@@ -1115,20 +1146,18 @@ client.setRequestHandler(ElicitRequestSchema, async (request) => {
1115
1146
  The SDK provides a high-level client interface:
1116
1147
 
1117
1148
  ```typescript
1118
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
1119
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
1149
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
1150
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
1120
1151
 
1121
1152
  const transport = new StdioClientTransport({
1122
- command: "node",
1123
- args: ["server.js"]
1153
+ command: 'node',
1154
+ args: ['server.js']
1124
1155
  });
1125
1156
 
1126
- const client = new Client(
1127
- {
1128
- name: "example-client",
1129
- version: "1.0.0"
1130
- }
1131
- );
1157
+ const client = new Client({
1158
+ name: 'example-client',
1159
+ version: '1.0.0'
1160
+ });
1132
1161
 
1133
1162
  await client.connect(transport);
1134
1163
 
@@ -1137,10 +1166,10 @@ const prompts = await client.listPrompts();
1137
1166
 
1138
1167
  // Get a prompt
1139
1168
  const prompt = await client.getPrompt({
1140
- name: "example-prompt",
1141
- arguments: {
1142
- arg1: "value"
1143
- }
1169
+ name: 'example-prompt',
1170
+ arguments: {
1171
+ arg1: 'value'
1172
+ }
1144
1173
  });
1145
1174
 
1146
1175
  // List resources
@@ -1148,17 +1177,16 @@ const resources = await client.listResources();
1148
1177
 
1149
1178
  // Read a resource
1150
1179
  const resource = await client.readResource({
1151
- uri: "file:///example.txt"
1180
+ uri: 'file:///example.txt'
1152
1181
  });
1153
1182
 
1154
1183
  // Call a tool
1155
1184
  const result = await client.callTool({
1156
- name: "example-tool",
1157
- arguments: {
1158
- arg1: "value"
1159
- }
1185
+ name: 'example-tool',
1186
+ arguments: {
1187
+ arg1: 'value'
1188
+ }
1160
1189
  });
1161
-
1162
1190
  ```
1163
1191
 
1164
1192
  ### Proxy Authorization Requests Upstream
@@ -1174,31 +1202,33 @@ const app = express();
1174
1202
 
1175
1203
  const proxyProvider = new ProxyOAuthServerProvider({
1176
1204
  endpoints: {
1177
- authorizationUrl: "https://auth.external.com/oauth2/v1/authorize",
1178
- tokenUrl: "https://auth.external.com/oauth2/v1/token",
1179
- revocationUrl: "https://auth.external.com/oauth2/v1/revoke",
1205
+ authorizationUrl: 'https://auth.external.com/oauth2/v1/authorize',
1206
+ tokenUrl: 'https://auth.external.com/oauth2/v1/token',
1207
+ revocationUrl: 'https://auth.external.com/oauth2/v1/revoke'
1180
1208
  },
1181
- verifyAccessToken: async (token) => {
1209
+ verifyAccessToken: async token => {
1182
1210
  return {
1183
1211
  token,
1184
- clientId: "123",
1185
- scopes: ["openid", "email", "profile"],
1186
- }
1212
+ clientId: '123',
1213
+ scopes: ['openid', 'email', 'profile']
1214
+ };
1187
1215
  },
1188
- getClient: async (client_id) => {
1216
+ getClient: async client_id => {
1189
1217
  return {
1190
1218
  client_id,
1191
- redirect_uris: ["http://localhost:3000/callback"],
1192
- }
1219
+ redirect_uris: ['http://localhost:3000/callback']
1220
+ };
1193
1221
  }
1194
- })
1195
-
1196
- app.use(mcpAuthRouter({
1197
- provider: proxyProvider,
1198
- issuerUrl: new URL("http://auth.external.com"),
1199
- baseUrl: new URL("http://mcp.example.com"),
1200
- serviceDocumentationUrl: new URL("https://docs.example.com/"),
1201
- }))
1222
+ });
1223
+
1224
+ app.use(
1225
+ mcpAuthRouter({
1226
+ provider: proxyProvider,
1227
+ issuerUrl: new URL('http://auth.external.com'),
1228
+ baseUrl: new URL('http://mcp.example.com'),
1229
+ serviceDocumentationUrl: new URL('https://docs.example.com/')
1230
+ })
1231
+ );
1202
1232
  ```
1203
1233
 
1204
1234
  This setup allows you to:
@@ -1218,31 +1248,29 @@ Clients and servers with StreamableHttp transport can maintain [backwards compat
1218
1248
  For clients that need to work with both Streamable HTTP and older SSE servers:
1219
1249
 
1220
1250
  ```typescript
1221
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
1222
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
1223
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
1224
- let client: Client|undefined = undefined
1251
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
1252
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
1253
+ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
1254
+ let client: Client | undefined = undefined;
1225
1255
  const baseUrl = new URL(url);
1226
1256
  try {
1227
- client = new Client({
1228
- name: 'streamable-http-client',
1229
- version: '1.0.0'
1230
- });
1231
- const transport = new StreamableHTTPClientTransport(
1232
- new URL(baseUrl)
1233
- );
1234
- await client.connect(transport);
1235
- console.log("Connected using Streamable HTTP transport");
1257
+ client = new Client({
1258
+ name: 'streamable-http-client',
1259
+ version: '1.0.0'
1260
+ });
1261
+ const transport = new StreamableHTTPClientTransport(new URL(baseUrl));
1262
+ await client.connect(transport);
1263
+ console.log('Connected using Streamable HTTP transport');
1236
1264
  } catch (error) {
1237
- // If that fails with a 4xx error, try the older SSE transport
1238
- console.log("Streamable HTTP connection failed, falling back to SSE transport");
1239
- client = new Client({
1240
- name: 'sse-client',
1241
- version: '1.0.0'
1242
- });
1243
- const sseTransport = new SSEClientTransport(baseUrl);
1244
- await client.connect(sseTransport);
1245
- console.log("Connected using SSE transport");
1265
+ // If that fails with a 4xx error, try the older SSE transport
1266
+ console.log('Streamable HTTP connection failed, falling back to SSE transport');
1267
+ client = new Client({
1268
+ name: 'sse-client',
1269
+ version: '1.0.0'
1270
+ });
1271
+ const sseTransport = new SSEClientTransport(baseUrl);
1272
+ await client.connect(sseTransport);
1273
+ console.log('Connected using SSE transport');
1246
1274
  }
1247
1275
  ```
1248
1276
 
@@ -1251,14 +1279,14 @@ try {
1251
1279
  For servers that need to support both Streamable HTTP and older clients:
1252
1280
 
1253
1281
  ```typescript
1254
- import express from "express";
1255
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1256
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
1257
- import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
1282
+ import express from 'express';
1283
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1284
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
1285
+ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
1258
1286
 
1259
1287
  const server = new McpServer({
1260
- name: "backwards-compatible-server",
1261
- version: "1.0.0"
1288
+ name: 'backwards-compatible-server',
1289
+ version: '1.0.0'
1262
1290
  });
1263
1291
 
1264
1292
  // ... set up server resources, tools, and prompts ...
@@ -1268,39 +1296,39 @@ app.use(express.json());
1268
1296
 
1269
1297
  // Store transports for each session type
1270
1298
  const transports = {
1271
- streamable: {} as Record<string, StreamableHTTPServerTransport>,
1272
- sse: {} as Record<string, SSEServerTransport>
1299
+ streamable: {} as Record<string, StreamableHTTPServerTransport>,
1300
+ sse: {} as Record<string, SSEServerTransport>
1273
1301
  };
1274
1302
 
1275
1303
  // Modern Streamable HTTP endpoint
1276
1304
  app.all('/mcp', async (req, res) => {
1277
- // Handle Streamable HTTP transport for modern clients
1278
- // Implementation as shown in the "With Session Management" example
1279
- // ...
1305
+ // Handle Streamable HTTP transport for modern clients
1306
+ // Implementation as shown in the "With Session Management" example
1307
+ // ...
1280
1308
  });
1281
1309
 
1282
1310
  // Legacy SSE endpoint for older clients
1283
1311
  app.get('/sse', async (req, res) => {
1284
- // Create SSE transport for legacy clients
1285
- const transport = new SSEServerTransport('/messages', res);
1286
- transports.sse[transport.sessionId] = transport;
1287
-
1288
- res.on("close", () => {
1289
- delete transports.sse[transport.sessionId];
1290
- });
1291
-
1292
- await server.connect(transport);
1312
+ // Create SSE transport for legacy clients
1313
+ const transport = new SSEServerTransport('/messages', res);
1314
+ transports.sse[transport.sessionId] = transport;
1315
+
1316
+ res.on('close', () => {
1317
+ delete transports.sse[transport.sessionId];
1318
+ });
1319
+
1320
+ await server.connect(transport);
1293
1321
  });
1294
1322
 
1295
1323
  // Legacy message endpoint for older clients
1296
1324
  app.post('/messages', async (req, res) => {
1297
- const sessionId = req.query.sessionId as string;
1298
- const transport = transports.sse[sessionId];
1299
- if (transport) {
1300
- await transport.handlePostMessage(req, res, req.body);
1301
- } else {
1302
- res.status(400).send('No transport found for sessionId');
1303
- }
1325
+ const sessionId = req.query.sessionId as string;
1326
+ const transport = transports.sse[sessionId];
1327
+ if (transport) {
1328
+ await transport.handlePostMessage(req, res, req.body);
1329
+ } else {
1330
+ res.status(400).send('No transport found for sessionId');
1331
+ }
1304
1332
  });
1305
1333
 
1306
1334
  app.listen(3000);