@modelcontextprotocol/sdk 1.23.0 → 1.24.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 (316) hide show
  1. package/README.md +84 -1507
  2. package/dist/cjs/client/auth-extensions.d.ts +178 -0
  3. package/dist/cjs/client/auth-extensions.d.ts.map +1 -0
  4. package/dist/cjs/client/auth-extensions.js +300 -0
  5. package/dist/cjs/client/auth-extensions.js.map +1 -0
  6. package/dist/cjs/client/auth.d.ts +90 -2
  7. package/dist/cjs/client/auth.d.ts.map +1 -1
  8. package/dist/cjs/client/auth.js +131 -75
  9. package/dist/cjs/client/auth.js.map +1 -1
  10. package/dist/cjs/client/index.d.ts +122 -14
  11. package/dist/cjs/client/index.d.ts.map +1 -1
  12. package/dist/cjs/client/index.js +125 -3
  13. package/dist/cjs/client/index.js.map +1 -1
  14. package/dist/cjs/client/sse.d.ts.map +1 -1
  15. package/dist/cjs/client/sse.js +6 -2
  16. package/dist/cjs/client/sse.js.map +1 -1
  17. package/dist/cjs/client/stdio.d.ts +0 -1
  18. package/dist/cjs/client/stdio.d.ts.map +1 -1
  19. package/dist/cjs/client/stdio.js +36 -11
  20. package/dist/cjs/client/stdio.js.map +1 -1
  21. package/dist/cjs/client/streamableHttp.d.ts +1 -0
  22. package/dist/cjs/client/streamableHttp.d.ts.map +1 -1
  23. package/dist/cjs/client/streamableHttp.js +36 -15
  24. package/dist/cjs/client/streamableHttp.js.map +1 -1
  25. package/dist/cjs/examples/client/simpleClientCredentials.d.ts +20 -0
  26. package/dist/cjs/examples/client/simpleClientCredentials.d.ts.map +1 -0
  27. package/dist/cjs/examples/client/simpleClientCredentials.js +70 -0
  28. package/dist/cjs/examples/client/simpleClientCredentials.js.map +1 -0
  29. package/dist/cjs/examples/client/simpleOAuthClient.js +77 -1
  30. package/dist/cjs/examples/client/simpleOAuthClient.js.map +1 -1
  31. package/dist/cjs/examples/client/simpleStreamableHttp.js +74 -3
  32. package/dist/cjs/examples/client/simpleStreamableHttp.js.map +1 -1
  33. package/dist/cjs/examples/client/simpleTaskInteractiveClient.d.ts +10 -0
  34. package/dist/cjs/examples/client/simpleTaskInteractiveClient.d.ts.map +1 -0
  35. package/dist/cjs/examples/client/simpleTaskInteractiveClient.js +158 -0
  36. package/dist/cjs/examples/client/simpleTaskInteractiveClient.js.map +1 -0
  37. package/dist/cjs/examples/server/elicitationFormExample.js +2 -12
  38. package/dist/cjs/examples/server/elicitationFormExample.js.map +1 -1
  39. package/dist/cjs/examples/server/elicitationUrlExample.js +4 -3
  40. package/dist/cjs/examples/server/elicitationUrlExample.js.map +1 -1
  41. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js +2 -12
  42. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  43. package/dist/cjs/examples/server/simpleSseServer.js +2 -6
  44. package/dist/cjs/examples/server/simpleSseServer.js.map +1 -1
  45. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js +2 -12
  46. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  47. package/dist/cjs/examples/server/simpleStreamableHttp.js +61 -21
  48. package/dist/cjs/examples/server/simpleStreamableHttp.js.map +1 -1
  49. package/dist/cjs/examples/server/simpleTaskInteractive.d.ts +12 -0
  50. package/dist/cjs/examples/server/simpleTaskInteractive.d.ts.map +1 -0
  51. package/dist/cjs/examples/server/simpleTaskInteractive.js +603 -0
  52. package/dist/cjs/examples/server/simpleTaskInteractive.js.map +1 -0
  53. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js +2 -12
  54. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  55. package/dist/cjs/examples/server/ssePollingExample.js +11 -25
  56. package/dist/cjs/examples/server/ssePollingExample.js.map +1 -1
  57. package/dist/cjs/examples/server/standaloneSseWithGetStreamableHttp.js +2 -6
  58. package/dist/cjs/examples/server/standaloneSseWithGetStreamableHttp.js.map +1 -1
  59. package/dist/cjs/examples/server/toolWithSampleServer.js +7 -5
  60. package/dist/cjs/examples/server/toolWithSampleServer.js.map +1 -1
  61. package/dist/cjs/experimental/index.d.ts +13 -0
  62. package/dist/cjs/experimental/index.d.ts.map +1 -0
  63. package/dist/cjs/experimental/index.js +29 -0
  64. package/dist/cjs/experimental/index.js.map +1 -0
  65. package/dist/cjs/experimental/tasks/client.d.ts +121 -0
  66. package/dist/cjs/experimental/tasks/client.d.ts.map +1 -0
  67. package/dist/cjs/experimental/tasks/client.js +189 -0
  68. package/dist/cjs/experimental/tasks/client.js.map +1 -0
  69. package/dist/cjs/experimental/tasks/helpers.d.ts +47 -0
  70. package/dist/cjs/experimental/tasks/helpers.d.ts.map +1 -0
  71. package/dist/cjs/experimental/tasks/helpers.js +70 -0
  72. package/dist/cjs/experimental/tasks/helpers.js.map +1 -0
  73. package/dist/cjs/experimental/tasks/index.d.ts +16 -0
  74. package/dist/cjs/experimental/tasks/index.d.ts.map +1 -0
  75. package/dist/cjs/experimental/tasks/index.js +39 -0
  76. package/dist/cjs/experimental/tasks/index.js.map +1 -0
  77. package/dist/cjs/experimental/tasks/interfaces.d.ts +232 -0
  78. package/dist/cjs/experimental/tasks/interfaces.d.ts.map +1 -0
  79. package/dist/cjs/experimental/tasks/interfaces.js +19 -0
  80. package/dist/cjs/experimental/tasks/interfaces.js.map +1 -0
  81. package/dist/cjs/experimental/tasks/mcp-server.d.ts +77 -0
  82. package/dist/cjs/experimental/tasks/mcp-server.d.ts.map +1 -0
  83. package/dist/cjs/experimental/tasks/mcp-server.js +36 -0
  84. package/dist/cjs/experimental/tasks/mcp-server.js.map +1 -0
  85. package/dist/cjs/experimental/tasks/server.d.ts +83 -0
  86. package/dist/cjs/experimental/tasks/server.d.ts.map +1 -0
  87. package/dist/cjs/experimental/tasks/server.js +93 -0
  88. package/dist/cjs/experimental/tasks/server.js.map +1 -0
  89. package/dist/cjs/experimental/tasks/stores/in-memory.d.ts +94 -0
  90. package/dist/cjs/experimental/tasks/stores/in-memory.d.ts.map +1 -0
  91. package/dist/cjs/experimental/tasks/stores/in-memory.js +253 -0
  92. package/dist/cjs/experimental/tasks/stores/in-memory.js.map +1 -0
  93. package/dist/cjs/experimental/tasks/types.d.ts +10 -0
  94. package/dist/cjs/experimental/tasks/types.d.ts.map +1 -0
  95. package/dist/cjs/experimental/tasks/types.js +28 -0
  96. package/dist/cjs/experimental/tasks/types.js.map +1 -0
  97. package/dist/cjs/server/auth/errors.d.ts +7 -0
  98. package/dist/cjs/server/auth/errors.d.ts.map +1 -1
  99. package/dist/cjs/server/auth/errors.js +11 -2
  100. package/dist/cjs/server/auth/errors.js.map +1 -1
  101. package/dist/cjs/server/auth/handlers/token.d.ts.map +1 -1
  102. package/dist/cjs/server/auth/handlers/token.js +2 -2
  103. package/dist/cjs/server/auth/handlers/token.js.map +1 -1
  104. package/dist/cjs/server/auth/middleware/clientAuth.d.ts.map +1 -1
  105. package/dist/cjs/server/auth/middleware/clientAuth.js +0 -4
  106. package/dist/cjs/server/auth/middleware/clientAuth.js.map +1 -1
  107. package/dist/cjs/server/auth/providers/proxyProvider.d.ts.map +1 -1
  108. package/dist/cjs/server/auth/providers/proxyProvider.js +8 -4
  109. package/dist/cjs/server/auth/providers/proxyProvider.js.map +1 -1
  110. package/dist/cjs/server/auth/router.d.ts.map +1 -1
  111. package/dist/cjs/server/auth/router.js +7 -1
  112. package/dist/cjs/server/auth/router.js.map +1 -1
  113. package/dist/cjs/server/index.d.ts +91 -168
  114. package/dist/cjs/server/index.d.ts.map +1 -1
  115. package/dist/cjs/server/index.js +162 -0
  116. package/dist/cjs/server/index.js.map +1 -1
  117. package/dist/cjs/server/mcp.d.ts +41 -6
  118. package/dist/cjs/server/mcp.d.ts.map +1 -1
  119. package/dist/cjs/server/mcp.js +203 -48
  120. package/dist/cjs/server/mcp.js.map +1 -1
  121. package/dist/cjs/server/middleware/hostHeaderValidation.d.ts +32 -0
  122. package/dist/cjs/server/middleware/hostHeaderValidation.d.ts.map +1 -0
  123. package/dist/cjs/server/middleware/hostHeaderValidation.js +80 -0
  124. package/dist/cjs/server/middleware/hostHeaderValidation.js.map +1 -0
  125. package/dist/cjs/server/sse.d.ts +6 -0
  126. package/dist/cjs/server/sse.d.ts.map +1 -1
  127. package/dist/cjs/server/sse.js +3 -3
  128. package/dist/cjs/server/sse.js.map +1 -1
  129. package/dist/cjs/server/stdio.d.ts +1 -1
  130. package/dist/cjs/server/stdio.js +1 -1
  131. package/dist/cjs/server/streamableHttp.d.ts +11 -0
  132. package/dist/cjs/server/streamableHttp.d.ts.map +1 -1
  133. package/dist/cjs/server/streamableHttp.js +30 -7
  134. package/dist/cjs/server/streamableHttp.js.map +1 -1
  135. package/dist/cjs/server/zod-compat.d.ts +1 -1
  136. package/dist/cjs/server/zod-compat.d.ts.map +1 -1
  137. package/dist/cjs/server/zod-compat.js +2 -2
  138. package/dist/cjs/server/zod-compat.js.map +1 -1
  139. package/dist/cjs/shared/auth.d.ts +1 -1
  140. package/dist/cjs/shared/auth.js +1 -1
  141. package/dist/cjs/shared/auth.js.map +1 -1
  142. package/dist/cjs/shared/protocol.d.ts +220 -3
  143. package/dist/cjs/shared/protocol.d.ts.map +1 -1
  144. package/dist/cjs/shared/protocol.js +699 -38
  145. package/dist/cjs/shared/protocol.js.map +1 -1
  146. package/dist/cjs/shared/responseMessage.d.ts +45 -0
  147. package/dist/cjs/shared/responseMessage.d.ts.map +1 -0
  148. package/dist/cjs/shared/responseMessage.js +23 -0
  149. package/dist/cjs/shared/responseMessage.js.map +1 -0
  150. package/dist/cjs/shared/transport.d.ts +1 -1
  151. package/dist/cjs/types.d.ts +2369 -73
  152. package/dist/cjs/types.d.ts.map +1 -1
  153. package/dist/cjs/types.js +310 -18
  154. package/dist/cjs/types.js.map +1 -1
  155. package/dist/esm/client/auth-extensions.d.ts +178 -0
  156. package/dist/esm/client/auth-extensions.d.ts.map +1 -0
  157. package/dist/esm/client/auth-extensions.js +270 -0
  158. package/dist/esm/client/auth-extensions.js.map +1 -0
  159. package/dist/esm/client/auth.d.ts +90 -2
  160. package/dist/esm/client/auth.d.ts.map +1 -1
  161. package/dist/esm/client/auth.js +129 -75
  162. package/dist/esm/client/auth.js.map +1 -1
  163. package/dist/esm/client/index.d.ts +122 -14
  164. package/dist/esm/client/index.d.ts.map +1 -1
  165. package/dist/esm/client/index.js +126 -4
  166. package/dist/esm/client/index.js.map +1 -1
  167. package/dist/esm/client/sse.d.ts.map +1 -1
  168. package/dist/esm/client/sse.js +7 -3
  169. package/dist/esm/client/sse.js.map +1 -1
  170. package/dist/esm/client/stdio.d.ts +0 -1
  171. package/dist/esm/client/stdio.d.ts.map +1 -1
  172. package/dist/esm/client/stdio.js +36 -11
  173. package/dist/esm/client/stdio.js.map +1 -1
  174. package/dist/esm/client/streamableHttp.d.ts +1 -0
  175. package/dist/esm/client/streamableHttp.d.ts.map +1 -1
  176. package/dist/esm/client/streamableHttp.js +36 -15
  177. package/dist/esm/client/streamableHttp.js.map +1 -1
  178. package/dist/esm/examples/client/simpleClientCredentials.d.ts +20 -0
  179. package/dist/esm/examples/client/simpleClientCredentials.d.ts.map +1 -0
  180. package/dist/esm/examples/client/simpleClientCredentials.js +68 -0
  181. package/dist/esm/examples/client/simpleClientCredentials.js.map +1 -0
  182. package/dist/esm/examples/client/simpleOAuthClient.js +77 -1
  183. package/dist/esm/examples/client/simpleOAuthClient.js.map +1 -1
  184. package/dist/esm/examples/client/simpleStreamableHttp.js +75 -4
  185. package/dist/esm/examples/client/simpleStreamableHttp.js.map +1 -1
  186. package/dist/esm/examples/client/simpleTaskInteractiveClient.d.ts +10 -0
  187. package/dist/esm/examples/client/simpleTaskInteractiveClient.d.ts.map +1 -0
  188. package/dist/esm/examples/client/simpleTaskInteractiveClient.js +156 -0
  189. package/dist/esm/examples/client/simpleTaskInteractiveClient.js.map +1 -0
  190. package/dist/esm/examples/server/elicitationFormExample.js +2 -9
  191. package/dist/esm/examples/server/elicitationFormExample.js.map +1 -1
  192. package/dist/esm/examples/server/elicitationUrlExample.js +4 -3
  193. package/dist/esm/examples/server/elicitationUrlExample.js.map +1 -1
  194. package/dist/esm/examples/server/jsonResponseStreamableHttp.js +2 -9
  195. package/dist/esm/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  196. package/dist/esm/examples/server/simpleSseServer.js +2 -3
  197. package/dist/esm/examples/server/simpleSseServer.js.map +1 -1
  198. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js +2 -9
  199. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  200. package/dist/esm/examples/server/simpleStreamableHttp.js +62 -19
  201. package/dist/esm/examples/server/simpleStreamableHttp.js.map +1 -1
  202. package/dist/esm/examples/server/simpleTaskInteractive.d.ts +12 -0
  203. package/dist/esm/examples/server/simpleTaskInteractive.d.ts.map +1 -0
  204. package/dist/esm/examples/server/simpleTaskInteractive.js +601 -0
  205. package/dist/esm/examples/server/simpleTaskInteractive.js.map +1 -0
  206. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js +2 -9
  207. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  208. package/dist/esm/examples/server/ssePollingExample.js +11 -25
  209. package/dist/esm/examples/server/ssePollingExample.js.map +1 -1
  210. package/dist/esm/examples/server/standaloneSseWithGetStreamableHttp.js +2 -3
  211. package/dist/esm/examples/server/standaloneSseWithGetStreamableHttp.js.map +1 -1
  212. package/dist/esm/examples/server/toolWithSampleServer.js +7 -5
  213. package/dist/esm/examples/server/toolWithSampleServer.js.map +1 -1
  214. package/dist/esm/experimental/index.d.ts +13 -0
  215. package/dist/esm/experimental/index.d.ts.map +1 -0
  216. package/dist/esm/experimental/index.js +13 -0
  217. package/dist/esm/experimental/index.js.map +1 -0
  218. package/dist/esm/experimental/tasks/client.d.ts +121 -0
  219. package/dist/esm/experimental/tasks/client.d.ts.map +1 -0
  220. package/dist/esm/experimental/tasks/client.js +185 -0
  221. package/dist/esm/experimental/tasks/client.js.map +1 -0
  222. package/dist/esm/experimental/tasks/helpers.d.ts +47 -0
  223. package/dist/esm/experimental/tasks/helpers.d.ts.map +1 -0
  224. package/dist/esm/experimental/tasks/helpers.js +66 -0
  225. package/dist/esm/experimental/tasks/helpers.js.map +1 -0
  226. package/dist/esm/experimental/tasks/index.d.ts +16 -0
  227. package/dist/esm/experimental/tasks/index.d.ts.map +1 -0
  228. package/dist/esm/experimental/tasks/index.js +20 -0
  229. package/dist/esm/experimental/tasks/index.js.map +1 -0
  230. package/dist/esm/experimental/tasks/interfaces.d.ts +232 -0
  231. package/dist/esm/experimental/tasks/interfaces.d.ts.map +1 -0
  232. package/dist/esm/experimental/tasks/interfaces.js +16 -0
  233. package/dist/esm/experimental/tasks/interfaces.js.map +1 -0
  234. package/dist/esm/experimental/tasks/mcp-server.d.ts +77 -0
  235. package/dist/esm/experimental/tasks/mcp-server.d.ts.map +1 -0
  236. package/dist/esm/experimental/tasks/mcp-server.js +32 -0
  237. package/dist/esm/experimental/tasks/mcp-server.js.map +1 -0
  238. package/dist/esm/experimental/tasks/server.d.ts +83 -0
  239. package/dist/esm/experimental/tasks/server.d.ts.map +1 -0
  240. package/dist/esm/experimental/tasks/server.js +89 -0
  241. package/dist/esm/experimental/tasks/server.js.map +1 -0
  242. package/dist/esm/experimental/tasks/stores/in-memory.d.ts +94 -0
  243. package/dist/esm/experimental/tasks/stores/in-memory.d.ts.map +1 -0
  244. package/dist/esm/experimental/tasks/stores/in-memory.js +248 -0
  245. package/dist/esm/experimental/tasks/stores/in-memory.js.map +1 -0
  246. package/dist/esm/experimental/tasks/types.d.ts +10 -0
  247. package/dist/esm/experimental/tasks/types.d.ts.map +1 -0
  248. package/dist/esm/experimental/tasks/types.js +10 -0
  249. package/dist/esm/experimental/tasks/types.js.map +1 -0
  250. package/dist/esm/server/auth/errors.d.ts +7 -0
  251. package/dist/esm/server/auth/errors.d.ts.map +1 -1
  252. package/dist/esm/server/auth/errors.js +9 -1
  253. package/dist/esm/server/auth/errors.js.map +1 -1
  254. package/dist/esm/server/auth/handlers/token.d.ts.map +1 -1
  255. package/dist/esm/server/auth/handlers/token.js +2 -2
  256. package/dist/esm/server/auth/handlers/token.js.map +1 -1
  257. package/dist/esm/server/auth/middleware/clientAuth.d.ts.map +1 -1
  258. package/dist/esm/server/auth/middleware/clientAuth.js +0 -4
  259. package/dist/esm/server/auth/middleware/clientAuth.js.map +1 -1
  260. package/dist/esm/server/auth/providers/proxyProvider.d.ts.map +1 -1
  261. package/dist/esm/server/auth/providers/proxyProvider.js +8 -4
  262. package/dist/esm/server/auth/providers/proxyProvider.js.map +1 -1
  263. package/dist/esm/server/auth/router.d.ts.map +1 -1
  264. package/dist/esm/server/auth/router.js +7 -1
  265. package/dist/esm/server/auth/router.js.map +1 -1
  266. package/dist/esm/server/index.d.ts +91 -168
  267. package/dist/esm/server/index.d.ts.map +1 -1
  268. package/dist/esm/server/index.js +159 -1
  269. package/dist/esm/server/index.js.map +1 -1
  270. package/dist/esm/server/mcp.d.ts +41 -6
  271. package/dist/esm/server/mcp.d.ts.map +1 -1
  272. package/dist/esm/server/mcp.js +203 -48
  273. package/dist/esm/server/mcp.js.map +1 -1
  274. package/dist/esm/server/middleware/hostHeaderValidation.d.ts +32 -0
  275. package/dist/esm/server/middleware/hostHeaderValidation.d.ts.map +1 -0
  276. package/dist/esm/server/middleware/hostHeaderValidation.js +76 -0
  277. package/dist/esm/server/middleware/hostHeaderValidation.js.map +1 -0
  278. package/dist/esm/server/sse.d.ts +6 -0
  279. package/dist/esm/server/sse.d.ts.map +1 -1
  280. package/dist/esm/server/sse.js +2 -2
  281. package/dist/esm/server/sse.js.map +1 -1
  282. package/dist/esm/server/stdio.d.ts +1 -1
  283. package/dist/esm/server/stdio.js +1 -1
  284. package/dist/esm/server/streamableHttp.d.ts +11 -0
  285. package/dist/esm/server/streamableHttp.d.ts.map +1 -1
  286. package/dist/esm/server/streamableHttp.js +30 -7
  287. package/dist/esm/server/streamableHttp.js.map +1 -1
  288. package/dist/esm/server/zod-compat.d.ts +1 -1
  289. package/dist/esm/server/zod-compat.d.ts.map +1 -1
  290. package/dist/esm/server/zod-compat.js +2 -2
  291. package/dist/esm/server/zod-compat.js.map +1 -1
  292. package/dist/esm/shared/auth.d.ts +1 -1
  293. package/dist/esm/shared/auth.js +1 -1
  294. package/dist/esm/shared/auth.js.map +1 -1
  295. package/dist/esm/shared/protocol.d.ts +220 -3
  296. package/dist/esm/shared/protocol.d.ts.map +1 -1
  297. package/dist/esm/shared/protocol.js +700 -39
  298. package/dist/esm/shared/protocol.js.map +1 -1
  299. package/dist/esm/shared/responseMessage.d.ts +45 -0
  300. package/dist/esm/shared/responseMessage.d.ts.map +1 -0
  301. package/dist/esm/shared/responseMessage.js +19 -0
  302. package/dist/esm/shared/responseMessage.js.map +1 -0
  303. package/dist/esm/shared/transport.d.ts +1 -1
  304. package/dist/esm/types.d.ts +2369 -73
  305. package/dist/esm/types.d.ts.map +1 -1
  306. package/dist/esm/types.js +306 -15
  307. package/dist/esm/types.js.map +1 -1
  308. package/package.json +12 -1
  309. package/dist/cjs/shared/zodTestMatrix.d.ts +0 -16
  310. package/dist/cjs/shared/zodTestMatrix.d.ts.map +0 -1
  311. package/dist/cjs/shared/zodTestMatrix.js +0 -43
  312. package/dist/cjs/shared/zodTestMatrix.js.map +0 -1
  313. package/dist/esm/shared/zodTestMatrix.d.ts +0 -16
  314. package/dist/esm/shared/zodTestMatrix.d.ts.map +0 -1
  315. package/dist/esm/shared/zodTestMatrix.js +0 -17
  316. package/dist/esm/shared/zodTestMatrix.js.map +0 -1
package/README.md CHANGED
@@ -7,28 +7,7 @@
7
7
  - [Installation](#installation)
8
8
  - [Quick Start](#quick-start)
9
9
  - [Core Concepts](#core-concepts)
10
- - [Server](#server)
11
- - [Tools](#tools)
12
- - [Resources](#resources)
13
- - [Prompts](#prompts)
14
- - [Completions](#completions)
15
- - [Display Names and Metadata](#display-names-and-metadata)
16
- - [Sampling](#sampling)
17
- - [Running Your Server](#running-your-server)
18
- - [Streamable HTTP](#streamable-http)
19
- - [stdio](#stdio)
20
- - [Testing and Debugging](#testing-and-debugging)
21
10
  - [Examples](#examples)
22
- - [Echo Server](#echo-server)
23
- - [SQLite Explorer](#sqlite-explorer)
24
- - [Advanced Usage](#advanced-usage)
25
- - [Dynamic Servers](#dynamic-servers)
26
- - [Improving Network Efficiency with Notification Debouncing](#improving-network-efficiency-with-notification-debouncing)
27
- - [Low-Level Server](#low-level-server)
28
- - [Eliciting User Input](#eliciting-user-input)
29
- - [Writing MCP Clients](#writing-mcp-clients)
30
- - [Proxy Authorization Requests Upstream](#proxy-authorization-requests-upstream)
31
- - [Backwards Compatibility](#backwards-compatibility)
32
11
  - [Documentation](#documentation)
33
12
  - [Contributing](#contributing)
34
13
  - [License](#license)
@@ -38,7 +17,7 @@
38
17
  ## Overview
39
18
 
40
19
  The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This TypeScript SDK implements
41
- [the full MCP specification](https://modelcontextprotocol.io/specification/latest), making it easy to:
20
+ [the full MCP specification](https://modelcontextprotocol.io/specification/draft), making it easy to:
42
21
 
43
22
  - Create MCP servers that expose resources, prompts and tools
44
23
  - Build MCP clients that can connect to any MCP server
@@ -54,1534 +33,132 @@ This SDK has a **required peer dependency** on `zod` for schema validation. The
54
33
 
55
34
  ## Quick Start
56
35
 
57
- Let's create a simple MCP server that exposes a calculator tool and some data. Save the following as `server.ts`:
36
+ To see the SDK in action end-to-end, start from the runnable examples in `src/examples`:
58
37
 
59
- ```typescript
60
- import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
61
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
62
- import express from 'express';
63
- import * as z from 'zod/v4';
38
+ 1. **Install dependencies** (from the SDK repo root):
64
39
 
65
- // Create an MCP server
66
- const server = new McpServer({
67
- name: 'demo-server',
68
- version: '1.0.0'
69
- });
40
+ ```bash
41
+ npm install
42
+ ```
70
43
 
71
- // Add an addition tool
72
- server.registerTool(
73
- 'add',
74
- {
75
- title: 'Addition Tool',
76
- description: 'Add two numbers',
77
- inputSchema: { a: z.number(), b: z.number() },
78
- outputSchema: { result: z.number() }
79
- },
80
- async ({ a, b }) => {
81
- const output = { result: a + b };
82
- return {
83
- content: [{ type: 'text', text: JSON.stringify(output) }],
84
- structuredContent: output
85
- };
86
- }
87
- );
44
+ 2. **Run the example Streamable HTTP server**:
88
45
 
89
- // Add a dynamic greeting resource
90
- server.registerResource(
91
- 'greeting',
92
- new ResourceTemplate('greeting://{name}', { list: undefined }),
93
- {
94
- title: 'Greeting Resource', // Display name for UI
95
- description: 'Dynamic greeting generator'
96
- },
97
- async (uri, { name }) => ({
98
- contents: [
99
- {
100
- uri: uri.href,
101
- text: `Hello, ${name}!`
102
- }
103
- ]
104
- })
105
- );
46
+ ```bash
47
+ npx tsx src/examples/server/simpleStreamableHttp.ts
48
+ ```
106
49
 
107
- // Set up Express and HTTP transport
108
- const app = express();
109
- app.use(express.json());
50
+ 3. **Run the interactive client in another terminal**:
110
51
 
111
- app.post('/mcp', async (req, res) => {
112
- // Create a new transport for each request to prevent request ID collisions
113
- const transport = new StreamableHTTPServerTransport({
114
- sessionIdGenerator: undefined,
115
- enableJsonResponse: true
116
- });
52
+ ```bash
53
+ npx tsx src/examples/client/simpleStreamableHttp.ts
54
+ ```
117
55
 
118
- res.on('close', () => {
119
- transport.close();
120
- });
121
-
122
- await server.connect(transport);
123
- await transport.handleRequest(req, res, req.body);
124
- });
125
-
126
- const port = parseInt(process.env.PORT || '3000');
127
- app.listen(port, () => {
128
- console.log(`Demo MCP Server running on http://localhost:${port}/mcp`);
129
- }).on('error', error => {
130
- console.error('Server error:', error);
131
- process.exit(1);
132
- });
133
- ```
134
-
135
- Install the deps with `npm install @modelcontextprotocol/sdk express zod`, and run with `npx -y tsx server.ts`.
136
-
137
- You can connect to it using any MCP client that supports streamable http, such as:
138
-
139
- - [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector): `npx @modelcontextprotocol/inspector` and connect to the streamable HTTP URL `http://localhost:3000/mcp`
140
- - [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp): `claude mcp add --transport http my-server http://localhost:3000/mcp`
141
- - [VS Code](https://code.visualstudio.com/docs/copilot/customization/mcp-servers): `code --add-mcp "{\"name\":\"my-server\",\"type\":\"http\",\"url\":\"http://localhost:3000/mcp\"}"`
142
- - [Cursor](https://cursor.com/docs/context/mcp): Click [this deeplink](cursor://anysphere.cursor-deeplink/mcp/install?name=my-server&config=eyJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAvbWNwIn0%3D)
143
-
144
- Then try asking your agent to add two numbers using its new tool!
56
+ This pair of examples demonstrates tools, resources, prompts, sampling, elicitation, tasks and logging. For a guided walkthrough and variations (stateless servers, JSON-only responses, SSE compatibility, OAuth, etc.), see [docs/server.md](docs/server.md) and
57
+ [docs/client.md](docs/client.md).
145
58
 
146
59
  ## Core Concepts
147
60
 
148
- ### Server
149
-
150
- The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
151
-
152
- ```typescript
153
- const server = new McpServer({
154
- name: 'my-app',
155
- version: '1.0.0'
156
- });
157
- ```
158
-
159
- ### Tools
160
-
161
- [Tools](https://modelcontextprotocol.io/specification/latest/server/tools) let LLMs take actions through your server. Tools can perform computation, fetch data and have side effects. Tools should be designed to be model-controlled - i.e. AI models will decide which tools to call,
162
- and the arguments.
163
-
164
- ```typescript
165
- // Simple tool with parameters
166
- server.registerTool(
167
- 'calculate-bmi',
168
- {
169
- title: 'BMI Calculator',
170
- description: 'Calculate Body Mass Index',
171
- inputSchema: {
172
- weightKg: z.number(),
173
- heightM: z.number()
174
- },
175
- outputSchema: { bmi: z.number() }
176
- },
177
- async ({ weightKg, heightM }) => {
178
- const output = { bmi: weightKg / (heightM * heightM) };
179
- return {
180
- content: [
181
- {
182
- type: 'text',
183
- text: JSON.stringify(output)
184
- }
185
- ],
186
- structuredContent: output
187
- };
188
- }
189
- );
190
-
191
- // Async tool with external API call
192
- server.registerTool(
193
- 'fetch-weather',
194
- {
195
- title: 'Weather Fetcher',
196
- description: 'Get weather data for a city',
197
- inputSchema: { city: z.string() },
198
- outputSchema: { temperature: z.number(), conditions: z.string() }
199
- },
200
- async ({ city }) => {
201
- const response = await fetch(`https://api.weather.com/${city}`);
202
- const data = await response.json();
203
- const output = { temperature: data.temp, conditions: data.conditions };
204
- return {
205
- content: [{ type: 'text', text: JSON.stringify(output) }],
206
- structuredContent: output
207
- };
208
- }
209
- );
210
-
211
- // Tool that returns ResourceLinks
212
- server.registerTool(
213
- 'list-files',
214
- {
215
- title: 'List Files',
216
- description: 'List project files',
217
- inputSchema: { pattern: z.string() },
218
- outputSchema: {
219
- count: z.number(),
220
- files: z.array(z.object({ name: z.string(), uri: z.string() }))
221
- }
222
- },
223
- async ({ pattern }) => {
224
- const output = {
225
- count: 2,
226
- files: [
227
- { name: 'README.md', uri: 'file:///project/README.md' },
228
- { name: 'index.ts', uri: 'file:///project/src/index.ts' }
229
- ]
230
- };
231
- return {
232
- content: [
233
- { type: 'text', text: JSON.stringify(output) },
234
- // ResourceLinks let tools return references without file content
235
- {
236
- type: 'resource_link',
237
- uri: 'file:///project/README.md',
238
- name: 'README.md',
239
- mimeType: 'text/markdown',
240
- description: 'A README file'
241
- },
242
- {
243
- type: 'resource_link',
244
- uri: 'file:///project/src/index.ts',
245
- name: 'index.ts',
246
- mimeType: 'text/typescript',
247
- description: 'An index file'
248
- }
249
- ],
250
- structuredContent: output
251
- };
252
- }
253
- );
254
- ```
255
-
256
- #### ResourceLinks
257
-
258
- Tools can return `ResourceLink` objects to reference resources without embedding their full content. This can be helpful for performance when dealing with large files or many resources - clients can then selectively read only the resources they need using the provided URIs.
259
-
260
- ### Resources
261
-
262
- [Resources](https://modelcontextprotocol.io/specification/latest/server/resources) can also expose data to LLMs, but unlike tools shouldn't perform significant computation or have side effects.
263
-
264
- Resources are designed to be used in an application-driven way, meaning MCP client applications can decide how to expose them. For example, a client could expose a resource picker to the human, or could expose them to the model directly.
265
-
266
- ```typescript
267
- // Static resource
268
- server.registerResource(
269
- 'config',
270
- 'config://app',
271
- {
272
- title: 'Application Config',
273
- description: 'Application configuration data',
274
- mimeType: 'text/plain'
275
- },
276
- async uri => ({
277
- contents: [
278
- {
279
- uri: uri.href,
280
- text: 'App configuration here'
281
- }
282
- ]
283
- })
284
- );
285
-
286
- // Dynamic resource with parameters
287
- server.registerResource(
288
- 'user-profile',
289
- new ResourceTemplate('users://{userId}/profile', { list: undefined }),
290
- {
291
- title: 'User Profile',
292
- description: 'User profile information'
293
- },
294
- async (uri, { userId }) => ({
295
- contents: [
296
- {
297
- uri: uri.href,
298
- text: `Profile data for user ${userId}`
299
- }
300
- ]
301
- })
302
- );
303
-
304
- // Resource with context-aware completion
305
- server.registerResource(
306
- 'repository',
307
- new ResourceTemplate('github://repos/{owner}/{repo}', {
308
- list: undefined,
309
- complete: {
310
- // Provide intelligent completions based on previously resolved parameters
311
- repo: (value, context) => {
312
- if (context?.arguments?.['owner'] === 'org1') {
313
- return ['project1', 'project2', 'project3'].filter(r => r.startsWith(value));
314
- }
315
- return ['default-repo'].filter(r => r.startsWith(value));
316
- }
317
- }
318
- }),
319
- {
320
- title: 'GitHub Repository',
321
- description: 'Repository information'
322
- },
323
- async (uri, { owner, repo }) => ({
324
- contents: [
325
- {
326
- uri: uri.href,
327
- text: `Repository: ${owner}/${repo}`
328
- }
329
- ]
330
- })
331
- );
332
- ```
333
-
334
- ### Prompts
335
-
336
- [Prompts](https://modelcontextprotocol.io/specification/latest/server/prompts) are reusable templates that help humans prompt models to interact with your server. They're designed to be user-driven, and might appear as slash commands in a chat interface.
337
-
338
- ```typescript
339
- import { completable } from '@modelcontextprotocol/sdk/server/completable.js';
340
-
341
- server.registerPrompt(
342
- 'review-code',
343
- {
344
- title: 'Code Review',
345
- description: 'Review code for best practices and potential issues',
346
- argsSchema: { code: z.string() }
347
- },
348
- ({ code }) => ({
349
- messages: [
350
- {
351
- role: 'user',
352
- content: {
353
- type: 'text',
354
- text: `Please review this code:\n\n${code}`
355
- }
356
- }
357
- ]
358
- })
359
- );
360
-
361
- // Prompt with context-aware completion
362
- server.registerPrompt(
363
- 'team-greeting',
364
- {
365
- title: 'Team Greeting',
366
- description: 'Generate a greeting for team members',
367
- argsSchema: {
368
- department: completable(z.string(), value => {
369
- // Department suggestions
370
- return ['engineering', 'sales', 'marketing', 'support'].filter(d => d.startsWith(value));
371
- }),
372
- name: completable(z.string(), (value, context) => {
373
- // Name suggestions based on selected department
374
- const department = context?.arguments?.['department'];
375
- if (department === 'engineering') {
376
- return ['Alice', 'Bob', 'Charlie'].filter(n => n.startsWith(value));
377
- } else if (department === 'sales') {
378
- return ['David', 'Eve', 'Frank'].filter(n => n.startsWith(value));
379
- } else if (department === 'marketing') {
380
- return ['Grace', 'Henry', 'Iris'].filter(n => n.startsWith(value));
381
- }
382
- return ['Guest'].filter(n => n.startsWith(value));
383
- })
384
- }
385
- },
386
- ({ department, name }) => ({
387
- messages: [
388
- {
389
- role: 'assistant',
390
- content: {
391
- type: 'text',
392
- text: `Hello ${name}, welcome to the ${department} team!`
393
- }
394
- }
395
- ]
396
- })
397
- );
398
- ```
399
-
400
- ### Completions
401
-
402
- MCP supports argument completions to help users fill in prompt arguments and resource template parameters. See the examples above for [resource completions](#resources) and [prompt completions](#prompts).
403
-
404
- #### Client Usage
405
-
406
- ```typescript
407
- // Request completions for any argument
408
- const result = await client.complete({
409
- ref: {
410
- type: 'ref/prompt', // or "ref/resource"
411
- name: 'example' // or uri: "template://..."
412
- },
413
- argument: {
414
- name: 'argumentName',
415
- value: 'partial' // What the user has typed so far
416
- },
417
- context: {
418
- // Optional: Include previously resolved arguments
419
- arguments: {
420
- previousArg: 'value'
421
- }
422
- }
423
- });
424
- ```
425
-
426
- ### Display Names and Metadata
427
-
428
- All resources, tools, and prompts support an optional `title` field for better UI presentation. The `title` is used as a display name (e.g. 'Create a new issue'), while `name` remains the unique identifier (e.g. `create_issue`).
429
-
430
- **Note:** The `register*` methods (`registerTool`, `registerPrompt`, `registerResource`) are the recommended approach for new code. The older methods (`tool`, `prompt`, `resource`) remain available for backwards compatibility.
431
-
432
- #### Title Precedence for Tools
433
-
434
- For tools specifically, there are two ways to specify a title:
435
-
436
- - `title` field in the tool configuration
437
- - `annotations.title` field (when using the older `tool()` method with annotations)
438
-
439
- The precedence order is: `title` → `annotations.title` → `name`
440
-
441
- ```typescript
442
- // Using registerTool (recommended)
443
- server.registerTool(
444
- 'my_tool',
445
- {
446
- title: 'My Tool', // This title takes precedence
447
- annotations: {
448
- title: 'Annotation Title' // This is ignored if title is set
449
- }
450
- },
451
- handler
452
- );
453
-
454
- // Using tool with annotations (older API)
455
- server.tool(
456
- 'my_tool',
457
- 'description',
458
- {
459
- title: 'Annotation Title' // This is used as title
460
- },
461
- handler
462
- );
463
- ```
464
-
465
- When building clients, use the provided utility to get the appropriate display name:
466
-
467
- ```typescript
468
- import { getDisplayName } from '@modelcontextprotocol/sdk/shared/metadataUtils.js';
469
-
470
- // Automatically handles the precedence: title → annotations.title → name
471
- const displayName = getDisplayName(tool);
472
- ```
473
-
474
- ### Sampling
475
-
476
- MCP servers can request LLM completions from connected clients that support sampling.
477
-
478
- ```typescript
479
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
480
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
481
- import express from 'express';
482
- import * as z from 'zod/v4';
61
+ ### Servers and transports
483
62
 
484
- const mcpServer = new McpServer({
485
- name: 'tools-with-sample-server',
486
- version: '1.0.0'
487
- });
63
+ An MCP server is typically created with `McpServer` and connected to a transport such as Streamable HTTP or stdio. The SDK supports:
488
64
 
489
- // Tool that uses LLM sampling to summarize any text
490
- mcpServer.registerTool(
491
- 'summarize',
492
- {
493
- title: 'Text Summarizer',
494
- description: 'Summarize any text using an LLM',
495
- inputSchema: {
496
- text: z.string().describe('Text to summarize')
497
- },
498
- outputSchema: { summary: z.string() }
499
- },
500
- async ({ text }) => {
501
- // Call the LLM through MCP sampling
502
- const response = await mcpServer.server.createMessage({
503
- messages: [
504
- {
505
- role: 'user',
506
- content: {
507
- type: 'text',
508
- text: `Please summarize the following text concisely:\n\n${text}`
509
- }
510
- }
511
- ],
512
- maxTokens: 500
513
- });
65
+ - **Streamable HTTP** for remote servers (recommended).
66
+ - **HTTP + SSE** for backwards compatibility only.
67
+ - **stdio** for local, process-spawned integrations.
514
68
 
515
- const summary = response.content.type === 'text' ? response.content.text : 'Unable to generate summary';
516
- const output = { summary };
517
- return {
518
- content: [{ type: 'text', text: JSON.stringify(output) }],
519
- structuredContent: output
520
- };
521
- }
522
- );
69
+ Runnable server examples live under `src/examples/server` and are documented in [docs/server.md](docs/server.md).
523
70
 
524
- const app = express();
525
- app.use(express.json());
71
+ ### Tools, resources, prompts
526
72
 
527
- app.post('/mcp', async (req, res) => {
528
- const transport = new StreamableHTTPServerTransport({
529
- sessionIdGenerator: undefined,
530
- enableJsonResponse: true
531
- });
73
+ - **Tools** let LLMs ask your server to take actions (computation, side effects, network calls).
74
+ - **Resources** expose read-only data that clients can surface to users or models.
75
+ - **Prompts** are reusable templates that help users talk to models in a consistent way.
532
76
 
533
- res.on('close', () => {
534
- transport.close();
535
- });
77
+ The detailed APIs, including `ResourceTemplate`, completions, and display-name metadata, are covered in [docs/server.md](docs/server.md#tools-resources-and-prompts), with runnable implementations in [`simpleStreamableHttp.ts`](src/examples/server/simpleStreamableHttp.ts).
536
78
 
537
- await mcpServer.connect(transport);
538
- await transport.handleRequest(req, res, req.body);
539
- });
79
+ ### Capabilities: sampling, elicitation, and tasks
540
80
 
541
- const port = parseInt(process.env.PORT || '3000');
542
- app.listen(port, () => {
543
- console.log(`MCP Server running on http://localhost:${port}/mcp`);
544
- }).on('error', error => {
545
- console.error('Server error:', error);
546
- process.exit(1);
547
- });
548
- ```
549
-
550
- ## Running Your Server
551
-
552
- 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:
553
-
554
- ### Streamable HTTP
555
-
556
- For remote servers, use the Streamable HTTP transport.
557
-
558
- #### Without Session Management (Recommended)
559
-
560
- For most use cases where session management isn't needed:
81
+ The SDK includes higher-level capabilities for richer workflows:
561
82
 
562
- ```typescript
563
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
564
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
565
- import express from 'express';
566
- import * as z from 'zod/v4';
83
+ - **Sampling**: server-side tools can ask connected clients to run LLM completions.
84
+ - **Form elicitation**: tools can request non-sensitive input via structured forms.
85
+ - **URL elicitation**: servers can ask users to complete secure flows in a browser (e.g., API key entry, payments, OAuth).
86
+ - **Tasks (experimental)**: long-running tool calls can be turned into tasks that you poll or resume later.
567
87
 
568
- const app = express();
569
- app.use(express.json());
88
+ Conceptual overviews and links to runnable examples are in:
570
89
 
571
- // Create the MCP server once (can be reused across requests)
572
- const server = new McpServer({
573
- name: 'example-server',
574
- version: '1.0.0'
575
- });
576
-
577
- // Set up your tools, resources, and prompts
578
- server.registerTool(
579
- 'echo',
580
- {
581
- title: 'Echo Tool',
582
- description: 'Echoes back the provided message',
583
- inputSchema: { message: z.string() },
584
- outputSchema: { echo: z.string() }
585
- },
586
- async ({ message }) => {
587
- const output = { echo: `Tool echo: ${message}` };
588
- return {
589
- content: [{ type: 'text', text: JSON.stringify(output) }],
590
- structuredContent: output
591
- };
592
- }
593
- );
594
-
595
- app.post('/mcp', async (req, res) => {
596
- // In stateless mode, create a new transport for each request to prevent
597
- // request ID collisions. Different clients may use the same JSON-RPC request IDs,
598
- // which would cause responses to be routed to the wrong HTTP connections if
599
- // the transport state is shared.
600
-
601
- try {
602
- const transport = new StreamableHTTPServerTransport({
603
- sessionIdGenerator: undefined,
604
- enableJsonResponse: true
605
- });
606
-
607
- res.on('close', () => {
608
- transport.close();
609
- });
610
-
611
- await server.connect(transport);
612
- await transport.handleRequest(req, res, req.body);
613
- } catch (error) {
614
- console.error('Error handling MCP request:', error);
615
- if (!res.headersSent) {
616
- res.status(500).json({
617
- jsonrpc: '2.0',
618
- error: {
619
- code: -32603,
620
- message: 'Internal server error'
621
- },
622
- id: null
623
- });
624
- }
625
- }
626
- });
627
-
628
- const port = parseInt(process.env.PORT || '3000');
629
- app.listen(port, () => {
630
- console.log(`MCP Server running on http://localhost:${port}/mcp`);
631
- }).on('error', error => {
632
- console.error('Server error:', error);
633
- process.exit(1);
634
- });
635
- ```
90
+ - [docs/capabilities.md](docs/capabilities.md)
636
91
 
637
- #### With Session Management
92
+ Key example servers include:
638
93
 
639
- In some cases, servers need stateful sessions. This can be achieved by [session management](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#session-management) in the MCP protocol.
94
+ - [`toolWithSampleServer.ts`](src/examples/server/toolWithSampleServer.ts)
95
+ - [`elicitationFormExample.ts`](src/examples/server/elicitationFormExample.ts)
96
+ - [`elicitationUrlExample.ts`](src/examples/server/elicitationUrlExample.ts)
640
97
 
641
- ```typescript
642
- import express from 'express';
643
- import { randomUUID } from 'node:crypto';
644
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
645
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
646
- import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
98
+ ### Clients
647
99
 
648
- const app = express();
649
- app.use(express.json());
100
+ The high-level `Client` class connects to MCP servers over different transports and exposes helpers like `listTools`, `callTool`, `listResources`, `readResource`, `listPrompts`, and `getPrompt`.
650
101
 
651
- // Map to store transports by session ID
652
- const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
102
+ Runnable clients live under `src/examples/client` and are described in [docs/client.md](docs/client.md), including:
653
103
 
654
- // Handle POST requests for client-to-server communication
655
- app.post('/mcp', async (req, res) => {
656
- // Check for existing session ID
657
- const sessionId = req.headers['mcp-session-id'] as string | undefined;
658
- let transport: StreamableHTTPServerTransport;
104
+ - Interactive Streamable HTTP client ([`simpleStreamableHttp.ts`](src/examples/client/simpleStreamableHttp.ts))
105
+ - Streamable HTTP client with SSE fallback ([`streamableHttpWithSseFallbackClient.ts`](src/examples/client/streamableHttpWithSseFallbackClient.ts))
106
+ - OAuth-enabled clients and polling/parallel examples
659
107
 
660
- if (sessionId && transports[sessionId]) {
661
- // Reuse existing transport
662
- transport = transports[sessionId];
663
- } else if (!sessionId && isInitializeRequest(req.body)) {
664
- // New initialization request
665
- transport = new StreamableHTTPServerTransport({
666
- sessionIdGenerator: () => randomUUID(),
667
- onsessioninitialized: sessionId => {
668
- // Store the transport by session ID
669
- transports[sessionId] = transport;
670
- }
671
- // DNS rebinding protection is disabled by default for backwards compatibility. If you are running this server
672
- // locally, make sure to set:
673
- // enableDnsRebindingProtection: true,
674
- // allowedHosts: ['127.0.0.1'],
675
- });
108
+ ### Node.js Web Crypto (globalThis.crypto) compatibility
676
109
 
677
- // Clean up transport when closed
678
- transport.onclose = () => {
679
- if (transport.sessionId) {
680
- delete transports[transport.sessionId];
681
- }
682
- };
683
- const server = new McpServer({
684
- name: 'example-server',
685
- version: '1.0.0'
686
- });
110
+ Some parts of the SDK (for example, JWT-based client authentication in `auth-extensions.ts` via `jose`) rely on the Web Crypto API exposed as `globalThis.crypto`.
687
111
 
688
- // ... set up server resources, tools, and prompts ...
689
-
690
- // Connect to the MCP server
691
- await server.connect(transport);
692
- } else {
693
- // Invalid request
694
- res.status(400).json({
695
- jsonrpc: '2.0',
696
- error: {
697
- code: -32000,
698
- message: 'Bad Request: No valid session ID provided'
699
- },
700
- id: null
701
- });
702
- return;
703
- }
704
-
705
- // Handle the request
706
- await transport.handleRequest(req, res, req.body);
707
- });
708
-
709
- // Reusable handler for GET and DELETE requests
710
- const handleSessionRequest = async (req: express.Request, res: express.Response) => {
711
- const sessionId = req.headers['mcp-session-id'] as string | undefined;
712
- if (!sessionId || !transports[sessionId]) {
713
- res.status(400).send('Invalid or missing session ID');
714
- return;
715
- }
716
-
717
- const transport = transports[sessionId];
718
- await transport.handleRequest(req, res);
719
- };
720
-
721
- // Handle GET requests for server-to-client notifications via SSE
722
- app.get('/mcp', handleSessionRequest);
723
-
724
- // Handle DELETE requests for session termination
725
- app.delete('/mcp', handleSessionRequest);
726
-
727
- app.listen(3000);
728
- ```
729
-
730
- #### CORS Configuration for Browser-Based Clients
731
-
732
- If you'd like your server to be accessible by browser-based MCP clients, you'll need to configure CORS headers. The `Mcp-Session-Id` header must be exposed for browser clients to access it:
733
-
734
- ```typescript
735
- import cors from 'cors';
736
-
737
- // Add CORS middleware before your MCP routes
738
- app.use(
739
- cors({
740
- origin: '*', // Configure appropriately for production, for example:
741
- // origin: ['https://your-remote-domain.com', 'https://your-other-remote-domain.com'],
742
- exposedHeaders: ['Mcp-Session-Id'],
743
- allowedHeaders: ['Content-Type', 'mcp-session-id']
744
- })
745
- );
746
- ```
747
-
748
- This configuration is necessary because:
749
-
750
- - The MCP streamable HTTP transport uses the `Mcp-Session-Id` header for session management
751
- - Browsers restrict access to response headers unless explicitly exposed via CORS
752
- - Without this configuration, browser-based clients won't be able to read the session ID from initialization responses
753
-
754
- #### DNS Rebinding Protection
755
-
756
- The Streamable HTTP transport includes DNS rebinding protection to prevent security vulnerabilities. By default, this protection is **disabled** for backwards compatibility.
757
-
758
- **Important**: If you are running this server locally, enable DNS rebinding protection:
759
-
760
- ```typescript
761
- const transport = new StreamableHTTPServerTransport({
762
- sessionIdGenerator: () => randomUUID(),
763
- enableDnsRebindingProtection: true,
764
-
765
- allowedHosts: ['127.0.0.1', ...],
766
- allowedOrigins: ['https://yourdomain.com', 'https://www.yourdomain.com']
767
- });
768
- ```
769
-
770
- ### stdio
771
-
772
- For local integrations spawned by another process, you can use the stdio transport:
773
-
774
- ```typescript
775
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
776
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
777
-
778
- const server = new McpServer({
779
- name: 'example-server',
780
- version: '1.0.0'
781
- });
782
-
783
- // ... set up server resources, tools, and prompts ...
784
-
785
- const transport = new StdioServerTransport();
786
- await server.connect(transport);
787
- ```
788
-
789
- ### Testing and Debugging
790
-
791
- To test your server, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). See its README for more information.
112
+ See [docs/faq.md](docs/faq.md) for details on supported Node.js versions and how to polyfill `globalThis.crypto` when running on older Node.js runtimes.
792
113
 
793
114
  ## Examples
794
115
 
795
- ### Echo Server
116
+ The SDK ships runnable examples under `src/examples`. Use these tables to find the scenario you care about and jump straight to the corresponding code and docs.
796
117
 
797
- A simple server demonstrating resources, tools, and prompts:
118
+ ### Server examples
798
119
 
799
- ```typescript
800
- import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
801
- import * as z from 'zod/v4';
120
+ | Scenario | Description | Example file(s) | Related docs |
121
+ | --------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
122
+ | Streamable HTTP server (stateful) | Feature-rich server with tools, resources, prompts, logging, tasks, sampling, and optional OAuth. | [`simpleStreamableHttp.ts`](src/examples/server/simpleStreamableHttp.ts) | [`server.md`](docs/server.md), [`capabilities.md`](docs/capabilities.md) |
123
+ | Streamable HTTP server (stateless) | No session tracking; good for simple API-style servers. | [`simpleStatelessStreamableHttp.ts`](src/examples/server/simpleStatelessStreamableHttp.ts) | [`server.md`](docs/server.md) |
124
+ | JSON response mode (no SSE) | Streamable HTTP with JSON responses only and limited notifications. | [`jsonResponseStreamableHttp.ts`](src/examples/server/jsonResponseStreamableHttp.ts) | [`server.md`](docs/server.md) |
125
+ | Server notifications over Streamable HTTP | Demonstrates server-initiated notifications using SSE with Streamable HTTP. | [`standaloneSseWithGetStreamableHttp.ts`](src/examples/server/standaloneSseWithGetStreamableHttp.ts) | [`server.md`](docs/server.md) |
126
+ | Deprecated HTTP+SSE server | Legacy HTTP+SSE transport for backwards-compatibility testing. | [`simpleSseServer.ts`](src/examples/server/simpleSseServer.ts) | [`server.md`](docs/server.md) |
127
+ | Backwards-compatible server (Streamable HTTP + SSE) | Single server that supports both Streamable HTTP and legacy SSE clients. | [`sseAndStreamableHttpCompatibleServer.ts`](src/examples/server/sseAndStreamableHttpCompatibleServer.ts) | [`server.md`](docs/server.md) |
128
+ | Form elicitation server | Uses form elicitation to collect non-sensitive user input. | [`elicitationFormExample.ts`](src/examples/server/elicitationFormExample.ts) | [`capabilities.md`](docs/capabilities.md#elicitation) |
129
+ | URL elicitation server | Demonstrates URL-mode elicitation in an OAuth-protected server. | [`elicitationUrlExample.ts`](src/examples/server/elicitationUrlExample.ts) | [`capabilities.md`](docs/capabilities.md#elicitation) |
130
+ | Sampling and tasks server | Combines tools, logging, sampling, and experimental task-based execution. | [`toolWithSampleServer.ts`](src/examples/server/toolWithSampleServer.ts) | [`capabilities.md`](docs/capabilities.md) |
131
+ | OAuth demo authorization server | In-memory OAuth provider used with the example servers. | [`demoInMemoryOAuthProvider.ts`](src/examples/server/demoInMemoryOAuthProvider.ts) | [`server.md`](docs/server.md) |
802
132
 
803
- const server = new McpServer({
804
- name: 'echo-server',
805
- version: '1.0.0'
806
- });
133
+ ### Client examples
807
134
 
808
- server.registerTool(
809
- 'echo',
810
- {
811
- title: 'Echo Tool',
812
- description: 'Echoes back the provided message',
813
- inputSchema: { message: z.string() },
814
- outputSchema: { echo: z.string() }
815
- },
816
- async ({ message }) => {
817
- const output = { echo: `Tool echo: ${message}` };
818
- return {
819
- content: [{ type: 'text', text: JSON.stringify(output) }],
820
- structuredContent: output
821
- };
822
- }
823
- );
824
-
825
- server.registerResource(
826
- 'echo',
827
- new ResourceTemplate('echo://{message}', { list: undefined }),
828
- {
829
- title: 'Echo Resource',
830
- description: 'Echoes back messages as resources'
831
- },
832
- async (uri, { message }) => ({
833
- contents: [
834
- {
835
- uri: uri.href,
836
- text: `Resource echo: ${message}`
837
- }
838
- ]
839
- })
840
- );
841
-
842
- server.registerPrompt(
843
- 'echo',
844
- {
845
- title: 'Echo Prompt',
846
- description: 'Creates a prompt to process a message',
847
- argsSchema: { message: z.string() }
848
- },
849
- ({ message }) => ({
850
- messages: [
851
- {
852
- role: 'user',
853
- content: {
854
- type: 'text',
855
- text: `Please process this message: ${message}`
856
- }
857
- }
858
- ]
859
- })
860
- );
861
- ```
135
+ | Scenario | Description | Example file(s) | Related docs |
136
+ | --------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
137
+ | Interactive Streamable HTTP client | CLI client that exercises tools, resources, prompts, elicitation, and tasks. | [`simpleStreamableHttp.ts`](src/examples/client/simpleStreamableHttp.ts) | [`client.md`](docs/client.md) |
138
+ | Backwards-compatible client (Streamable HTTP → SSE) | Tries Streamable HTTP first, then falls back to SSE on 4xx responses. | [`streamableHttpWithSseFallbackClient.ts`](src/examples/client/streamableHttpWithSseFallbackClient.ts) | [`client.md`](docs/client.md), [`server.md`](docs/server.md) |
139
+ | SSE polling client | Polls a legacy SSE server and demonstrates notification handling. | [`ssePollingClient.ts`](src/examples/client/ssePollingClient.ts) | [`client.md`](docs/client.md) |
140
+ | Parallel tool calls client | Shows how to run multiple tool calls in parallel. | [`parallelToolCallsClient.ts`](src/examples/client/parallelToolCallsClient.ts) | [`client.md`](docs/client.md) |
141
+ | Multiple clients in parallel | Demonstrates connecting multiple clients concurrently to the same server. | [`multipleClientsParallel.ts`](src/examples/client/multipleClientsParallel.ts) | [`client.md`](docs/client.md) |
142
+ | OAuth clients | Examples of client_credentials (basic and private_key_jwt) and reusable providers. | [`simpleOAuthClient.ts`](src/examples/client/simpleOAuthClient.ts), [`simpleOAuthClientProvider.ts`](src/examples/client/simpleOAuthClientProvider.ts), [`simpleClientCredentials.ts`](src/examples/client/simpleClientCredentials.ts) | [`client.md`](docs/client.md) |
143
+ | URL elicitation client | Works with the URL elicitation server to drive secure browser flows. | [`elicitationUrlExample.ts`](src/examples/client/elicitationUrlExample.ts) | [`capabilities.md`](docs/capabilities.md#elicitation) |
862
144
 
863
- ### SQLite Explorer
145
+ Shared utilities:
864
146
 
865
- A more complex example showing database integration:
866
-
867
- ```typescript
868
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
869
- import sqlite3 from 'sqlite3';
870
- import { promisify } from 'util';
871
- import * as z from 'zod/v4';
872
-
873
- const server = new McpServer({
874
- name: 'sqlite-explorer',
875
- version: '1.0.0'
876
- });
877
-
878
- // Helper to create DB connection
879
- const getDb = () => {
880
- const db = new sqlite3.Database('database.db');
881
- return {
882
- all: promisify<string, any[]>(db.all.bind(db)),
883
- close: promisify(db.close.bind(db))
884
- };
885
- };
886
-
887
- server.registerResource(
888
- 'schema',
889
- 'schema://main',
890
- {
891
- title: 'Database Schema',
892
- description: 'SQLite database schema',
893
- mimeType: 'text/plain'
894
- },
895
- async uri => {
896
- const db = getDb();
897
- try {
898
- const tables = await db.all("SELECT sql FROM sqlite_master WHERE type='table'");
899
- return {
900
- contents: [
901
- {
902
- uri: uri.href,
903
- text: tables.map((t: { sql: string }) => t.sql).join('\n')
904
- }
905
- ]
906
- };
907
- } finally {
908
- await db.close();
909
- }
910
- }
911
- );
912
-
913
- server.registerTool(
914
- 'query',
915
- {
916
- title: 'SQL Query',
917
- description: 'Execute SQL queries on the database',
918
- inputSchema: { sql: z.string() },
919
- outputSchema: {
920
- rows: z.array(z.record(z.any())),
921
- rowCount: z.number()
922
- }
923
- },
924
- async ({ sql }) => {
925
- const db = getDb();
926
- try {
927
- const results = await db.all(sql);
928
- const output = { rows: results, rowCount: results.length };
929
- return {
930
- content: [
931
- {
932
- type: 'text',
933
- text: JSON.stringify(output, null, 2)
934
- }
935
- ],
936
- structuredContent: output
937
- };
938
- } catch (err: unknown) {
939
- const error = err as Error;
940
- return {
941
- content: [
942
- {
943
- type: 'text',
944
- text: `Error: ${error.message}`
945
- }
946
- ],
947
- isError: true
948
- };
949
- } finally {
950
- await db.close();
951
- }
952
- }
953
- );
954
- ```
955
-
956
- ## Advanced Usage
957
-
958
- ### Dynamic Servers
959
-
960
- 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:
961
-
962
- ```typescript
963
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
964
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
965
- import express from 'express';
966
- import * as z from 'zod/v4';
967
-
968
- const server = new McpServer({
969
- name: 'Dynamic Example',
970
- version: '1.0.0'
971
- });
972
-
973
- const listMessageTool = server.registerTool(
974
- 'listMessages',
975
- {
976
- title: 'List Messages',
977
- description: 'List messages in a channel',
978
- inputSchema: { channel: z.string() },
979
- outputSchema: { messages: z.array(z.string()) }
980
- },
981
- async ({ channel }) => {
982
- const messages = await listMessages(channel);
983
- const output = { messages };
984
- return {
985
- content: [{ type: 'text', text: JSON.stringify(output) }],
986
- structuredContent: output
987
- };
988
- }
989
- );
990
-
991
- const putMessageTool = server.registerTool(
992
- 'putMessage',
993
- {
994
- title: 'Put Message',
995
- description: 'Send a message to a channel',
996
- inputSchema: { channel: z.string(), message: z.string() },
997
- outputSchema: { success: z.boolean() }
998
- },
999
- async ({ channel, message }) => {
1000
- await putMessage(channel, message);
1001
- const output = { success: true };
1002
- return {
1003
- content: [{ type: 'text', text: JSON.stringify(output) }],
1004
- structuredContent: output
1005
- };
1006
- }
1007
- );
1008
- // Until we upgrade auth, `putMessage` is disabled (won't show up in listTools)
1009
- putMessageTool.disable();
1010
-
1011
- const upgradeAuthTool = server.registerTool(
1012
- 'upgradeAuth',
1013
- {
1014
- title: 'Upgrade Authorization',
1015
- description: 'Upgrade user authorization level',
1016
- inputSchema: { permission: z.enum(['write', 'admin']) },
1017
- outputSchema: {
1018
- success: z.boolean(),
1019
- newPermission: z.string()
1020
- }
1021
- },
1022
- // Any mutations here will automatically emit `listChanged` notifications
1023
- async ({ permission }) => {
1024
- const { ok, err, previous } = await upgradeAuthAndStoreToken(permission);
1025
- if (!ok) {
1026
- return {
1027
- content: [{ type: 'text', text: `Error: ${err}` }],
1028
- isError: true
1029
- };
1030
- }
1031
-
1032
- // If we previously had read-only access, 'putMessage' is now available
1033
- if (previous === 'read') {
1034
- putMessageTool.enable();
1035
- }
1036
-
1037
- if (permission === 'write') {
1038
- // If we've just upgraded to 'write' permissions, we can still call 'upgradeAuth'
1039
- // but can only upgrade to 'admin'.
1040
- upgradeAuthTool.update({
1041
- paramsSchema: { permission: z.enum(['admin']) } // change validation rules
1042
- });
1043
- } else {
1044
- // If we're now an admin, we no longer have anywhere to upgrade to, so fully remove that tool
1045
- upgradeAuthTool.remove();
1046
- }
1047
-
1048
- const output = { success: true, newPermission: permission };
1049
- return {
1050
- content: [{ type: 'text', text: JSON.stringify(output) }],
1051
- structuredContent: output
1052
- };
1053
- }
1054
- );
1055
-
1056
- // Connect with HTTP transport
1057
- const app = express();
1058
- app.use(express.json());
1059
-
1060
- app.post('/mcp', async (req, res) => {
1061
- const transport = new StreamableHTTPServerTransport({
1062
- sessionIdGenerator: undefined,
1063
- enableJsonResponse: true
1064
- });
1065
-
1066
- res.on('close', () => {
1067
- transport.close();
1068
- });
1069
-
1070
- await server.connect(transport);
1071
- await transport.handleRequest(req, res, req.body);
1072
- });
1073
-
1074
- const port = parseInt(process.env.PORT || '3000');
1075
- app.listen(port, () => {
1076
- console.log(`MCP Server running on http://localhost:${port}/mcp`);
1077
- });
1078
- ```
1079
-
1080
- ### Improving Network Efficiency with Notification Debouncing
1081
-
1082
- When performing bulk updates that trigger notifications (e.g., enabling or disabling multiple tools in a loop), the SDK can send a large number of messages in a short period. To improve performance and reduce network traffic, you can enable notification debouncing.
1083
-
1084
- 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.
1085
-
1086
- > [!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
1087
- > notifications will always be sent immediately.
1088
-
1089
- This is an opt-in feature configured during server initialization.
1090
-
1091
- ```typescript
1092
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1093
-
1094
- const server = new McpServer(
1095
- {
1096
- name: "efficient-server",
1097
- version: "1.0.0"
1098
- },
1099
- {
1100
- // Enable notification debouncing for specific methods
1101
- debouncedNotificationMethods: [
1102
- 'notifications/tools/list_changed',
1103
- 'notifications/resources/list_changed',
1104
- 'notifications/prompts/list_changed'
1105
- ]
1106
- }
1107
- );
1108
-
1109
- // Now, any rapid changes to tools, resources, or prompts will result
1110
- // in a single, consolidated notification for each type.
1111
- server.registerTool("tool1", ...).disable();
1112
- server.registerTool("tool2", ...).disable();
1113
- server.registerTool("tool3", ...).disable();
1114
- // Only one 'notifications/tools/list_changed' is sent.
1115
- ```
1116
-
1117
- ### Low-Level Server
1118
-
1119
- For more control, you can use the low-level Server class directly:
1120
-
1121
- ```typescript
1122
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
1123
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
1124
- import { ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
1125
-
1126
- const server = new Server(
1127
- {
1128
- name: 'example-server',
1129
- version: '1.0.0'
1130
- },
1131
- {
1132
- capabilities: {
1133
- prompts: {}
1134
- }
1135
- }
1136
- );
1137
-
1138
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
1139
- return {
1140
- prompts: [
1141
- {
1142
- name: 'example-prompt',
1143
- description: 'An example prompt template',
1144
- arguments: [
1145
- {
1146
- name: 'arg1',
1147
- description: 'Example argument',
1148
- required: true
1149
- }
1150
- ]
1151
- }
1152
- ]
1153
- };
1154
- });
1155
-
1156
- server.setRequestHandler(GetPromptRequestSchema, async request => {
1157
- if (request.params.name !== 'example-prompt') {
1158
- throw new Error('Unknown prompt');
1159
- }
1160
- return {
1161
- description: 'Example prompt',
1162
- messages: [
1163
- {
1164
- role: 'user',
1165
- content: {
1166
- type: 'text',
1167
- text: 'Example prompt text'
1168
- }
1169
- }
1170
- ]
1171
- };
1172
- });
1173
-
1174
- const transport = new StdioServerTransport();
1175
- await server.connect(transport);
1176
- ```
1177
-
1178
- ### Eliciting User Input
1179
-
1180
- MCP servers can request non-sensitive information from users through the form elicitation capability. This is useful for interactive workflows where the server needs user input or confirmation:
1181
-
1182
- ```typescript
1183
- // Server-side: Restaurant booking tool that asks for alternatives
1184
- server.registerTool(
1185
- 'book-restaurant',
1186
- {
1187
- title: 'Book Restaurant',
1188
- description: 'Book a table at a restaurant',
1189
- inputSchema: {
1190
- restaurant: z.string(),
1191
- date: z.string(),
1192
- partySize: z.number()
1193
- },
1194
- outputSchema: {
1195
- success: z.boolean(),
1196
- booking: z
1197
- .object({
1198
- restaurant: z.string(),
1199
- date: z.string(),
1200
- partySize: z.number()
1201
- })
1202
- .optional(),
1203
- alternatives: z.array(z.string()).optional()
1204
- }
1205
- },
1206
- async ({ restaurant, date, partySize }) => {
1207
- // Check availability
1208
- const available = await checkAvailability(restaurant, date, partySize);
1209
-
1210
- if (!available) {
1211
- // Ask user if they want to try alternative dates
1212
- const result = await server.server.elicitInput({
1213
- mode: 'form',
1214
- message: `No tables available at ${restaurant} on ${date}. Would you like to check alternative dates?`,
1215
- requestedSchema: {
1216
- type: 'object',
1217
- properties: {
1218
- checkAlternatives: {
1219
- type: 'boolean',
1220
- title: 'Check alternative dates',
1221
- description: 'Would you like me to check other dates?'
1222
- },
1223
- flexibleDates: {
1224
- type: 'string',
1225
- title: 'Date flexibility',
1226
- description: 'How flexible are your dates?',
1227
- enum: ['next_day', 'same_week', 'next_week'],
1228
- enumNames: ['Next day', 'Same week', 'Next week']
1229
- }
1230
- },
1231
- required: ['checkAlternatives']
1232
- }
1233
- });
1234
-
1235
- if (result.action === 'accept' && result.content?.checkAlternatives) {
1236
- const alternatives = await findAlternatives(restaurant, date, partySize, result.content.flexibleDates as string);
1237
- const output = { success: false, alternatives };
1238
- return {
1239
- content: [
1240
- {
1241
- type: 'text',
1242
- text: JSON.stringify(output)
1243
- }
1244
- ],
1245
- structuredContent: output
1246
- };
1247
- }
1248
-
1249
- const output = { success: false };
1250
- return {
1251
- content: [
1252
- {
1253
- type: 'text',
1254
- text: JSON.stringify(output)
1255
- }
1256
- ],
1257
- structuredContent: output
1258
- };
1259
- }
1260
-
1261
- // Book the table
1262
- await makeBooking(restaurant, date, partySize);
1263
- const output = {
1264
- success: true,
1265
- booking: { restaurant, date, partySize }
1266
- };
1267
- return {
1268
- content: [
1269
- {
1270
- type: 'text',
1271
- text: JSON.stringify(output)
1272
- }
1273
- ],
1274
- structuredContent: output
1275
- };
1276
- }
1277
- );
1278
- ```
1279
-
1280
- On the client side, handle form elicitation requests:
1281
-
1282
- ```typescript
1283
- // This is a placeholder - implement based on your UI framework
1284
- async function getInputFromUser(
1285
- message: string,
1286
- schema: any
1287
- ): Promise<{
1288
- action: 'accept' | 'decline' | 'cancel';
1289
- data?: Record<string, any>;
1290
- }> {
1291
- // This should be implemented depending on the app
1292
- throw new Error('getInputFromUser must be implemented for your platform');
1293
- }
1294
-
1295
- client.setRequestHandler(ElicitRequestSchema, async request => {
1296
- const userResponse = await getInputFromUser(request.params.message, request.params.requestedSchema);
1297
-
1298
- return {
1299
- action: userResponse.action,
1300
- content: userResponse.action === 'accept' ? userResponse.data : undefined
1301
- };
1302
- });
1303
- ```
1304
-
1305
- When calling `server.elicitInput`, prefer to explicitly set `mode: 'form'` for new code. Omitting the mode continues to work for backwards compatibility and defaults to form elicitation.
1306
-
1307
- Elicitation is a client capability. Clients must declare the `elicitation` capability during initialization:
1308
-
1309
- ```typescript
1310
- const client = new Client(
1311
- {
1312
- name: 'example-client',
1313
- version: '1.0.0'
1314
- },
1315
- {
1316
- capabilities: {
1317
- elicitation: {
1318
- form: {}
1319
- }
1320
- }
1321
- }
1322
- );
1323
- ```
1324
-
1325
- **Note**: Form elicitation **must** only be used to gather non-sensitive information. For sensitive information such as API keys or secrets, use URL elicitation instead.
1326
-
1327
- ### Eliciting URL Actions
1328
-
1329
- MCP servers can prompt the user to perform a URL-based action through URL elicitation. This is useful for securely gathering sensitive information such as API keys or secrets, or for redirecting users to secure web-based flows.
1330
-
1331
- ```typescript
1332
- // Server-side: Prompt the user to navigate to a URL
1333
- const result = await server.server.elicitInput({
1334
- mode: 'url',
1335
- message: 'Please enter your API key',
1336
- elicitationId: '550e8400-e29b-41d4-a716-446655440000',
1337
- url: 'http://localhost:3000/api-key'
1338
- });
1339
-
1340
- // Alternative, return an error from within a tool:
1341
- throw new UrlElicitationRequiredError([
1342
- {
1343
- mode: 'url',
1344
- message: 'This tool requires a payment confirmation. Open the link to confirm payment!',
1345
- url: `http://localhost:${MCP_PORT}/confirm-payment?session=${sessionId}&elicitation=${elicitationId}&cartId=${encodeURIComponent(cartId)}`,
1346
- elicitationId: '550e8400-e29b-41d4-a716-446655440000'
1347
- }
1348
- ]);
1349
- ```
1350
-
1351
- On the client side, handle URL elicitation requests:
1352
-
1353
- ```typescript
1354
- client.setRequestHandler(ElicitRequestSchema, async request => {
1355
- if (request.params.mode !== 'url') {
1356
- throw new McpError(ErrorCode.InvalidParams, `Unsupported elicitation mode: ${request.params.mode}`);
1357
- }
1358
-
1359
- // At a minimum, implement a UI that:
1360
- // - Display the full URL and server reason to prevent phishing
1361
- // - Explicitly ask the user for consent, with clear decline/cancel options
1362
- // - Open the URL in the system (not embedded) browser
1363
- // Optionally, listen for a `nofifications/elicitation/complete` message from the server
1364
- });
1365
- ```
1366
-
1367
- Elicitation is a client capability. Clients must declare the `elicitation` capability during initialization:
1368
-
1369
- ```typescript
1370
- const client = new Client(
1371
- {
1372
- name: 'example-client',
1373
- version: '1.0.0'
1374
- },
1375
- {
1376
- capabilities: {
1377
- elicitation: {
1378
- url: {}
1379
- }
1380
- }
1381
- }
1382
- );
1383
- ```
1384
-
1385
- ### Writing MCP Clients
1386
-
1387
- The SDK provides a high-level client interface:
1388
-
1389
- ```typescript
1390
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
1391
- import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
1392
-
1393
- const transport = new StdioClientTransport({
1394
- command: 'node',
1395
- args: ['server.js']
1396
- });
1397
-
1398
- const client = new Client({
1399
- name: 'example-client',
1400
- version: '1.0.0'
1401
- });
1402
-
1403
- await client.connect(transport);
1404
-
1405
- // List prompts
1406
- const prompts = await client.listPrompts();
1407
-
1408
- // Get a prompt
1409
- const prompt = await client.getPrompt({
1410
- name: 'example-prompt',
1411
- arguments: {
1412
- arg1: 'value'
1413
- }
1414
- });
1415
-
1416
- // List resources
1417
- const resources = await client.listResources();
1418
-
1419
- // Read a resource
1420
- const resource = await client.readResource({
1421
- uri: 'file:///example.txt'
1422
- });
1423
-
1424
- // Call a tool
1425
- const result = await client.callTool({
1426
- name: 'example-tool',
1427
- arguments: {
1428
- arg1: 'value'
1429
- }
1430
- });
1431
- ```
1432
-
1433
- ### Proxy Authorization Requests Upstream
1434
-
1435
- You can proxy OAuth requests to an external authorization provider:
1436
-
1437
- ```typescript
1438
- import express from 'express';
1439
- import { ProxyOAuthServerProvider } from '@modelcontextprotocol/sdk/server/auth/providers/proxyProvider.js';
1440
- import { mcpAuthRouter } from '@modelcontextprotocol/sdk/server/auth/router.js';
1441
-
1442
- const app = express();
1443
-
1444
- const proxyProvider = new ProxyOAuthServerProvider({
1445
- endpoints: {
1446
- authorizationUrl: 'https://auth.external.com/oauth2/v1/authorize',
1447
- tokenUrl: 'https://auth.external.com/oauth2/v1/token',
1448
- revocationUrl: 'https://auth.external.com/oauth2/v1/revoke'
1449
- },
1450
- verifyAccessToken: async token => {
1451
- return {
1452
- token,
1453
- clientId: '123',
1454
- scopes: ['openid', 'email', 'profile']
1455
- };
1456
- },
1457
- getClient: async client_id => {
1458
- return {
1459
- client_id,
1460
- redirect_uris: ['http://localhost:3000/callback']
1461
- };
1462
- }
1463
- });
1464
-
1465
- app.use(
1466
- mcpAuthRouter({
1467
- provider: proxyProvider,
1468
- issuerUrl: new URL('http://auth.external.com'),
1469
- baseUrl: new URL('http://mcp.example.com'),
1470
- serviceDocumentationUrl: new URL('https://docs.example.com/')
1471
- })
1472
- );
1473
- ```
1474
-
1475
- This setup allows you to:
1476
-
1477
- - Forward OAuth requests to an external provider
1478
- - Add custom token validation logic
1479
- - Manage client registrations
1480
- - Provide custom documentation URLs
1481
- - Maintain control over the OAuth flow while delegating to an external provider
1482
-
1483
- ### Backwards Compatibility
1484
-
1485
- Clients and servers with StreamableHttp transport can maintain [backwards compatibility](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#backwards-compatibility) with the deprecated HTTP+SSE transport (from protocol version 2024-11-05) as follows
1486
-
1487
- #### Client-Side Compatibility
1488
-
1489
- For clients that need to work with both Streamable HTTP and older SSE servers:
1490
-
1491
- ```typescript
1492
- import { Client } from '@modelcontextprotocol/sdk/client/index.js';
1493
- import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
1494
- import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
1495
- let client: Client | undefined = undefined;
1496
- const baseUrl = new URL(url);
1497
- try {
1498
- client = new Client({
1499
- name: 'streamable-http-client',
1500
- version: '1.0.0'
1501
- });
1502
- const transport = new StreamableHTTPClientTransport(new URL(baseUrl));
1503
- await client.connect(transport);
1504
- console.log('Connected using Streamable HTTP transport');
1505
- } catch (error) {
1506
- // If that fails with a 4xx error, try the older SSE transport
1507
- console.log('Streamable HTTP connection failed, falling back to SSE transport');
1508
- client = new Client({
1509
- name: 'sse-client',
1510
- version: '1.0.0'
1511
- });
1512
- const sseTransport = new SSEClientTransport(baseUrl);
1513
- await client.connect(sseTransport);
1514
- console.log('Connected using SSE transport');
1515
- }
1516
- ```
1517
-
1518
- #### Server-Side Compatibility
1519
-
1520
- For servers that need to support both Streamable HTTP and older clients:
1521
-
1522
- ```typescript
1523
- import express from 'express';
1524
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1525
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
1526
- import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
1527
-
1528
- const server = new McpServer({
1529
- name: 'backwards-compatible-server',
1530
- version: '1.0.0'
1531
- });
1532
-
1533
- // ... set up server resources, tools, and prompts ...
1534
-
1535
- const app = express();
1536
- app.use(express.json());
1537
-
1538
- // Store transports for each session type
1539
- const transports = {
1540
- streamable: {} as Record<string, StreamableHTTPServerTransport>,
1541
- sse: {} as Record<string, SSEServerTransport>
1542
- };
1543
-
1544
- // Modern Streamable HTTP endpoint
1545
- app.all('/mcp', async (req, res) => {
1546
- // Handle Streamable HTTP transport for modern clients
1547
- // Implementation as shown in the "With Session Management" example
1548
- // ...
1549
- });
1550
-
1551
- // Legacy SSE endpoint for older clients
1552
- app.get('/sse', async (req, res) => {
1553
- // Create SSE transport for legacy clients
1554
- const transport = new SSEServerTransport('/messages', res);
1555
- transports.sse[transport.sessionId] = transport;
1556
-
1557
- res.on('close', () => {
1558
- delete transports.sse[transport.sessionId];
1559
- });
1560
-
1561
- await server.connect(transport);
1562
- });
1563
-
1564
- // Legacy message endpoint for older clients
1565
- app.post('/messages', async (req, res) => {
1566
- const sessionId = req.query.sessionId as string;
1567
- const transport = transports.sse[sessionId];
1568
- if (transport) {
1569
- await transport.handlePostMessage(req, res, req.body);
1570
- } else {
1571
- res.status(400).send('No transport found for sessionId');
1572
- }
1573
- });
1574
-
1575
- app.listen(3000);
1576
- ```
147
+ - In-memory event store for resumability: [`inMemoryEventStore.ts`](src/examples/shared/inMemoryEventStore.ts) (see [`server.md`](docs/server.md)).
1577
148
 
1578
- **Note**: The SSE transport is now deprecated in favor of Streamable HTTP. New implementations should use Streamable HTTP, and existing SSE implementations should plan to migrate.
149
+ For more details on how to run these examples (including recommended commands and deployment diagrams), see `src/examples/README.md`.
1579
150
 
1580
151
  ## Documentation
1581
152
 
1582
- - [Model Context Protocol documentation](https://modelcontextprotocol.io)
1583
- - [MCP Specification](https://spec.modelcontextprotocol.io)
1584
- - [Example Servers](https://github.com/modelcontextprotocol/servers)
153
+ - Local SDK docs:
154
+ - [docs/server.md](docs/server.md) – building and running MCP servers, transports, tools/resources/prompts, CORS, DNS rebinding, and multi-node deployment.
155
+ - [docs/client.md](docs/client.md) – using the high-level client, transports, backwards compatibility, and OAuth helpers.
156
+ - [docs/capabilities.md](docs/capabilities.md) – sampling, elicitation (form and URL), and experimental task-based execution.
157
+ - [docs/faq.md](docs/faq.md) – environment and troubleshooting FAQs (including Node.js Web Crypto support).
158
+ - External references:
159
+ - [Model Context Protocol documentation](https://modelcontextprotocol.io)
160
+ - [MCP Specification](https://spec.modelcontextprotocol.io)
161
+ - [Example Servers](https://github.com/modelcontextprotocol/servers)
1585
162
 
1586
163
  ## Contributing
1587
164