@modelcontextprotocol/sdk 1.22.0 → 1.23.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 (258) hide show
  1. package/README.md +92 -11
  2. package/dist/cjs/client/auth.d.ts +11 -1
  3. package/dist/cjs/client/auth.d.ts.map +1 -1
  4. package/dist/cjs/client/auth.js +71 -19
  5. package/dist/cjs/client/auth.js.map +1 -1
  6. package/dist/cjs/client/index.d.ts +122 -662
  7. package/dist/cjs/client/index.d.ts.map +1 -1
  8. package/dist/cjs/client/index.js +72 -15
  9. package/dist/cjs/client/index.js.map +1 -1
  10. package/dist/cjs/client/sse.d.ts +1 -0
  11. package/dist/cjs/client/sse.d.ts.map +1 -1
  12. package/dist/cjs/client/sse.js +5 -3
  13. package/dist/cjs/client/sse.js.map +1 -1
  14. package/dist/cjs/client/streamableHttp.d.ts +14 -2
  15. package/dist/cjs/client/streamableHttp.d.ts.map +1 -1
  16. package/dist/cjs/client/streamableHttp.js +79 -19
  17. package/dist/cjs/client/streamableHttp.js.map +1 -1
  18. package/dist/cjs/examples/client/elicitationUrlExample.d.ts +2 -0
  19. package/dist/cjs/examples/client/elicitationUrlExample.d.ts.map +1 -0
  20. package/dist/cjs/examples/client/elicitationUrlExample.js +693 -0
  21. package/dist/cjs/examples/client/elicitationUrlExample.js.map +1 -0
  22. package/dist/cjs/examples/client/simpleOAuthClient.js +13 -52
  23. package/dist/cjs/examples/client/simpleOAuthClient.js.map +1 -1
  24. package/dist/cjs/examples/client/simpleOAuthClientProvider.d.ts +26 -0
  25. package/dist/cjs/examples/client/simpleOAuthClientProvider.d.ts.map +1 -0
  26. package/dist/cjs/examples/client/simpleOAuthClientProvider.js +51 -0
  27. package/dist/cjs/examples/client/simpleOAuthClientProvider.js.map +1 -0
  28. package/dist/cjs/examples/client/simpleStreamableHttp.js +10 -5
  29. package/dist/cjs/examples/client/simpleStreamableHttp.js.map +1 -1
  30. package/dist/cjs/examples/client/ssePollingClient.d.ts +2 -0
  31. package/dist/cjs/examples/client/ssePollingClient.d.ts.map +1 -0
  32. package/dist/cjs/examples/client/ssePollingClient.js +95 -0
  33. package/dist/cjs/examples/client/ssePollingClient.js.map +1 -0
  34. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.d.ts +4 -4
  35. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.d.ts.map +1 -1
  36. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.js +16 -0
  37. package/dist/cjs/examples/server/demoInMemoryOAuthProvider.js.map +1 -1
  38. package/dist/cjs/examples/server/elicitationFormExample.d.ts +2 -0
  39. package/dist/cjs/examples/server/elicitationFormExample.d.ts.map +1 -0
  40. package/dist/cjs/examples/server/{elicitationExample.js → elicitationFormExample.js} +14 -8
  41. package/dist/cjs/examples/server/elicitationFormExample.js.map +1 -0
  42. package/dist/cjs/examples/server/elicitationUrlExample.d.ts +2 -0
  43. package/dist/cjs/examples/server/elicitationUrlExample.d.ts.map +1 -0
  44. package/dist/cjs/examples/server/elicitationUrlExample.js +655 -0
  45. package/dist/cjs/examples/server/elicitationUrlExample.js.map +1 -0
  46. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js +26 -3
  47. package/dist/cjs/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  48. package/dist/cjs/examples/server/mcpServerOutputSchema.js +34 -11
  49. package/dist/cjs/examples/server/mcpServerOutputSchema.js.map +1 -1
  50. package/dist/cjs/examples/server/simpleSseServer.js +26 -3
  51. package/dist/cjs/examples/server/simpleSseServer.js.map +1 -1
  52. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js +27 -4
  53. package/dist/cjs/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  54. package/dist/cjs/examples/server/simpleStreamableHttp.js +34 -10
  55. package/dist/cjs/examples/server/simpleStreamableHttp.js.map +1 -1
  56. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js +26 -3
  57. package/dist/cjs/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  58. package/dist/cjs/examples/server/ssePollingExample.d.ts +2 -0
  59. package/dist/cjs/examples/server/ssePollingExample.d.ts.map +1 -0
  60. package/dist/cjs/examples/server/ssePollingExample.js +116 -0
  61. package/dist/cjs/examples/server/ssePollingExample.js.map +1 -0
  62. package/dist/cjs/examples/server/toolWithSampleServer.js +30 -8
  63. package/dist/cjs/examples/server/toolWithSampleServer.js.map +1 -1
  64. package/dist/cjs/server/auth/handlers/authorize.js +34 -11
  65. package/dist/cjs/server/auth/handlers/authorize.js.map +1 -1
  66. package/dist/cjs/server/auth/handlers/token.js +35 -12
  67. package/dist/cjs/server/auth/handlers/token.js.map +1 -1
  68. package/dist/cjs/server/auth/middleware/bearerAuth.d.ts.map +1 -1
  69. package/dist/cjs/server/auth/middleware/bearerAuth.js +13 -8
  70. package/dist/cjs/server/auth/middleware/bearerAuth.js.map +1 -1
  71. package/dist/cjs/server/auth/middleware/clientAuth.js +27 -4
  72. package/dist/cjs/server/auth/middleware/clientAuth.js.map +1 -1
  73. package/dist/cjs/server/auth/router.js +1 -1
  74. package/dist/cjs/server/auth/router.js.map +1 -1
  75. package/dist/cjs/server/completable.d.ts +30 -16
  76. package/dist/cjs/server/completable.d.ts.map +1 -1
  77. package/dist/cjs/server/completable.js +38 -55
  78. package/dist/cjs/server/completable.js.map +1 -1
  79. package/dist/cjs/server/index.d.ts +176 -50
  80. package/dist/cjs/server/index.d.ts.map +1 -1
  81. package/dist/cjs/server/index.js +99 -13
  82. package/dist/cjs/server/index.js.map +1 -1
  83. package/dist/cjs/server/mcp.d.ts +14 -16
  84. package/dist/cjs/server/mcp.d.ts.map +1 -1
  85. package/dist/cjs/server/mcp.js +83 -40
  86. package/dist/cjs/server/mcp.js.map +1 -1
  87. package/dist/cjs/server/streamableHttp.d.ts +27 -0
  88. package/dist/cjs/server/streamableHttp.d.ts.map +1 -1
  89. package/dist/cjs/server/streamableHttp.js +70 -5
  90. package/dist/cjs/server/streamableHttp.js.map +1 -1
  91. package/dist/cjs/server/zod-compat.d.ts +82 -0
  92. package/dist/cjs/server/zod-compat.d.ts.map +1 -0
  93. package/dist/cjs/server/zod-compat.js +252 -0
  94. package/dist/cjs/server/zod-compat.js.map +1 -0
  95. package/dist/cjs/server/zod-json-schema-compat.d.ts +12 -0
  96. package/dist/cjs/server/zod-json-schema-compat.d.ts.map +1 -0
  97. package/dist/cjs/server/zod-json-schema-compat.js +80 -0
  98. package/dist/cjs/server/zod-json-schema-compat.js.map +1 -0
  99. package/dist/cjs/shared/auth.d.ts +116 -502
  100. package/dist/cjs/shared/auth.d.ts.map +1 -1
  101. package/dist/cjs/shared/auth.js +133 -112
  102. package/dist/cjs/shared/auth.js.map +1 -1
  103. package/dist/cjs/shared/protocol.d.ts +5 -9
  104. package/dist/cjs/shared/protocol.d.ts.map +1 -1
  105. package/dist/cjs/shared/protocol.js +24 -10
  106. package/dist/cjs/shared/protocol.js.map +1 -1
  107. package/dist/cjs/shared/transport.d.ts +14 -0
  108. package/dist/cjs/shared/transport.d.ts.map +1 -1
  109. package/dist/cjs/shared/transport.js +40 -0
  110. package/dist/cjs/shared/transport.js.map +1 -1
  111. package/dist/cjs/shared/zodTestMatrix.d.ts +16 -0
  112. package/dist/cjs/shared/zodTestMatrix.d.ts.map +1 -0
  113. package/dist/cjs/shared/zodTestMatrix.js +43 -0
  114. package/dist/cjs/shared/zodTestMatrix.js.map +1 -0
  115. package/dist/cjs/spec.types.d.ts +393 -70
  116. package/dist/cjs/spec.types.d.ts.map +1 -1
  117. package/dist/cjs/spec.types.js +5 -7
  118. package/dist/cjs/spec.types.js.map +1 -1
  119. package/dist/cjs/types.d.ts +3580 -23866
  120. package/dist/cjs/types.d.ts.map +1 -1
  121. package/dist/cjs/types.js +574 -340
  122. package/dist/cjs/types.js.map +1 -1
  123. package/dist/cjs/validation/cfworker-provider.d.ts +0 -1
  124. package/dist/cjs/validation/cfworker-provider.d.ts.map +1 -1
  125. package/dist/cjs/validation/cfworker-provider.js +0 -1
  126. package/dist/cjs/validation/cfworker-provider.js.map +1 -1
  127. package/dist/esm/client/auth.d.ts +11 -1
  128. package/dist/esm/client/auth.d.ts.map +1 -1
  129. package/dist/esm/client/auth.js +71 -20
  130. package/dist/esm/client/auth.js.map +1 -1
  131. package/dist/esm/client/index.d.ts +122 -662
  132. package/dist/esm/client/index.d.ts.map +1 -1
  133. package/dist/esm/client/index.js +71 -15
  134. package/dist/esm/client/index.js.map +1 -1
  135. package/dist/esm/client/sse.d.ts +1 -0
  136. package/dist/esm/client/sse.d.ts.map +1 -1
  137. package/dist/esm/client/sse.js +5 -3
  138. package/dist/esm/client/sse.js.map +1 -1
  139. package/dist/esm/client/streamableHttp.d.ts +14 -2
  140. package/dist/esm/client/streamableHttp.d.ts.map +1 -1
  141. package/dist/esm/client/streamableHttp.js +79 -19
  142. package/dist/esm/client/streamableHttp.js.map +1 -1
  143. package/dist/esm/examples/client/elicitationUrlExample.d.ts +2 -0
  144. package/dist/esm/examples/client/elicitationUrlExample.d.ts.map +1 -0
  145. package/dist/esm/examples/client/elicitationUrlExample.js +691 -0
  146. package/dist/esm/examples/client/elicitationUrlExample.js.map +1 -0
  147. package/dist/esm/examples/client/simpleOAuthClient.js +12 -51
  148. package/dist/esm/examples/client/simpleOAuthClient.js.map +1 -1
  149. package/dist/esm/examples/client/simpleOAuthClientProvider.d.ts +26 -0
  150. package/dist/esm/examples/client/simpleOAuthClientProvider.d.ts.map +1 -0
  151. package/dist/esm/examples/client/simpleOAuthClientProvider.js +47 -0
  152. package/dist/esm/examples/client/simpleOAuthClientProvider.js.map +1 -0
  153. package/dist/esm/examples/client/simpleStreamableHttp.js +11 -6
  154. package/dist/esm/examples/client/simpleStreamableHttp.js.map +1 -1
  155. package/dist/esm/examples/client/ssePollingClient.d.ts +2 -0
  156. package/dist/esm/examples/client/ssePollingClient.d.ts.map +1 -0
  157. package/dist/esm/examples/client/ssePollingClient.js +93 -0
  158. package/dist/esm/examples/client/ssePollingClient.js.map +1 -0
  159. package/dist/esm/examples/server/demoInMemoryOAuthProvider.d.ts +4 -4
  160. package/dist/esm/examples/server/demoInMemoryOAuthProvider.d.ts.map +1 -1
  161. package/dist/esm/examples/server/demoInMemoryOAuthProvider.js +16 -0
  162. package/dist/esm/examples/server/demoInMemoryOAuthProvider.js.map +1 -1
  163. package/dist/esm/examples/server/elicitationFormExample.d.ts +2 -0
  164. package/dist/esm/examples/server/elicitationFormExample.d.ts.map +1 -0
  165. package/dist/esm/examples/server/{elicitationExample.js → elicitationFormExample.js} +14 -8
  166. package/dist/esm/examples/server/elicitationFormExample.js.map +1 -0
  167. package/dist/esm/examples/server/elicitationUrlExample.d.ts +2 -0
  168. package/dist/esm/examples/server/elicitationUrlExample.d.ts.map +1 -0
  169. package/dist/esm/examples/server/elicitationUrlExample.js +650 -0
  170. package/dist/esm/examples/server/elicitationUrlExample.js.map +1 -0
  171. package/dist/esm/examples/server/jsonResponseStreamableHttp.js +1 -1
  172. package/dist/esm/examples/server/jsonResponseStreamableHttp.js.map +1 -1
  173. package/dist/esm/examples/server/mcpServerOutputSchema.js +1 -1
  174. package/dist/esm/examples/server/mcpServerOutputSchema.js.map +1 -1
  175. package/dist/esm/examples/server/simpleSseServer.js +1 -1
  176. package/dist/esm/examples/server/simpleSseServer.js.map +1 -1
  177. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js +1 -1
  178. package/dist/esm/examples/server/simpleStatelessStreamableHttp.js.map +1 -1
  179. package/dist/esm/examples/server/simpleStreamableHttp.js +4 -3
  180. package/dist/esm/examples/server/simpleStreamableHttp.js.map +1 -1
  181. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js +1 -1
  182. package/dist/esm/examples/server/sseAndStreamableHttpCompatibleServer.js.map +1 -1
  183. package/dist/esm/examples/server/ssePollingExample.d.ts +2 -0
  184. package/dist/esm/examples/server/ssePollingExample.d.ts.map +1 -0
  185. package/dist/esm/examples/server/ssePollingExample.js +111 -0
  186. package/dist/esm/examples/server/ssePollingExample.js.map +1 -0
  187. package/dist/esm/examples/server/toolWithSampleServer.js +6 -7
  188. package/dist/esm/examples/server/toolWithSampleServer.js.map +1 -1
  189. package/dist/esm/server/auth/handlers/authorize.js +1 -1
  190. package/dist/esm/server/auth/handlers/authorize.js.map +1 -1
  191. package/dist/esm/server/auth/handlers/token.js +1 -1
  192. package/dist/esm/server/auth/handlers/token.js.map +1 -1
  193. package/dist/esm/server/auth/middleware/bearerAuth.d.ts.map +1 -1
  194. package/dist/esm/server/auth/middleware/bearerAuth.js +13 -8
  195. package/dist/esm/server/auth/middleware/bearerAuth.js.map +1 -1
  196. package/dist/esm/server/auth/middleware/clientAuth.js +1 -1
  197. package/dist/esm/server/auth/middleware/clientAuth.js.map +1 -1
  198. package/dist/esm/server/auth/router.js +1 -1
  199. package/dist/esm/server/auth/router.js.map +1 -1
  200. package/dist/esm/server/completable.d.ts +30 -16
  201. package/dist/esm/server/completable.d.ts.map +1 -1
  202. package/dist/esm/server/completable.js +34 -53
  203. package/dist/esm/server/completable.js.map +1 -1
  204. package/dist/esm/server/index.d.ts +176 -50
  205. package/dist/esm/server/index.d.ts.map +1 -1
  206. package/dist/esm/server/index.js +99 -13
  207. package/dist/esm/server/index.js.map +1 -1
  208. package/dist/esm/server/mcp.d.ts +14 -16
  209. package/dist/esm/server/mcp.d.ts.map +1 -1
  210. package/dist/esm/server/mcp.js +84 -41
  211. package/dist/esm/server/mcp.js.map +1 -1
  212. package/dist/esm/server/streamableHttp.d.ts +27 -0
  213. package/dist/esm/server/streamableHttp.d.ts.map +1 -1
  214. package/dist/esm/server/streamableHttp.js +70 -5
  215. package/dist/esm/server/streamableHttp.js.map +1 -1
  216. package/dist/esm/server/zod-compat.d.ts +82 -0
  217. package/dist/esm/server/zod-compat.d.ts.map +1 -0
  218. package/dist/esm/server/zod-compat.js +217 -0
  219. package/dist/esm/server/zod-compat.js.map +1 -0
  220. package/dist/esm/server/zod-json-schema-compat.d.ts +12 -0
  221. package/dist/esm/server/zod-json-schema-compat.d.ts.map +1 -0
  222. package/dist/esm/server/zod-json-schema-compat.js +52 -0
  223. package/dist/esm/server/zod-json-schema-compat.js.map +1 -0
  224. package/dist/esm/shared/auth.d.ts +116 -502
  225. package/dist/esm/shared/auth.d.ts.map +1 -1
  226. package/dist/esm/shared/auth.js +17 -19
  227. package/dist/esm/shared/auth.js.map +1 -1
  228. package/dist/esm/shared/protocol.d.ts +5 -9
  229. package/dist/esm/shared/protocol.d.ts.map +1 -1
  230. package/dist/esm/shared/protocol.js +24 -10
  231. package/dist/esm/shared/protocol.js.map +1 -1
  232. package/dist/esm/shared/transport.d.ts +14 -0
  233. package/dist/esm/shared/transport.d.ts.map +1 -1
  234. package/dist/esm/shared/transport.js +38 -1
  235. package/dist/esm/shared/transport.js.map +1 -1
  236. package/dist/esm/shared/zodTestMatrix.d.ts +16 -0
  237. package/dist/esm/shared/zodTestMatrix.d.ts.map +1 -0
  238. package/dist/esm/shared/zodTestMatrix.js +17 -0
  239. package/dist/esm/shared/zodTestMatrix.js.map +1 -0
  240. package/dist/esm/spec.types.d.ts +393 -70
  241. package/dist/esm/spec.types.d.ts.map +1 -1
  242. package/dist/esm/spec.types.js +4 -6
  243. package/dist/esm/spec.types.js.map +1 -1
  244. package/dist/esm/types.d.ts +3580 -23866
  245. package/dist/esm/types.d.ts.map +1 -1
  246. package/dist/esm/types.js +282 -72
  247. package/dist/esm/types.js.map +1 -1
  248. package/dist/esm/validation/cfworker-provider.d.ts +0 -1
  249. package/dist/esm/validation/cfworker-provider.d.ts.map +1 -1
  250. package/dist/esm/validation/cfworker-provider.js +0 -1
  251. package/dist/esm/validation/cfworker-provider.js.map +1 -1
  252. package/package.json +13 -12
  253. package/dist/cjs/examples/server/elicitationExample.d.ts +0 -2
  254. package/dist/cjs/examples/server/elicitationExample.d.ts.map +0 -1
  255. package/dist/cjs/examples/server/elicitationExample.js.map +0 -1
  256. package/dist/esm/examples/server/elicitationExample.d.ts +0 -2
  257. package/dist/esm/examples/server/elicitationExample.d.ts.map +0 -1
  258. package/dist/esm/examples/server/elicitationExample.js.map +0 -1
@@ -0,0 +1,693 @@
1
+ "use strict";
2
+ // Run with: npx tsx src/examples/client/elicitationUrlExample.ts
3
+ //
4
+ // This example demonstrates how to use URL elicitation to securely
5
+ // collect user input in a remote (HTTP) server.
6
+ // URL elicitation allows servers to prompt the end-user to open a URL in their browser
7
+ // to collect sensitive information.
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const index_js_1 = require("../../client/index.js");
10
+ const streamableHttp_js_1 = require("../../client/streamableHttp.js");
11
+ const node_readline_1 = require("node:readline");
12
+ const types_js_1 = require("../../types.js");
13
+ const metadataUtils_js_1 = require("../../shared/metadataUtils.js");
14
+ const node_child_process_1 = require("node:child_process");
15
+ const simpleOAuthClientProvider_js_1 = require("./simpleOAuthClientProvider.js");
16
+ const auth_js_1 = require("../../client/auth.js");
17
+ const node_http_1 = require("node:http");
18
+ // Set up OAuth (required for this example)
19
+ const OAUTH_CALLBACK_PORT = 8090; // Use different port than auth server (3001)
20
+ const OAUTH_CALLBACK_URL = `http://localhost:${OAUTH_CALLBACK_PORT}/callback`;
21
+ let oauthProvider = undefined;
22
+ console.log('Getting OAuth token...');
23
+ const clientMetadata = {
24
+ client_name: 'Elicitation MCP Client',
25
+ redirect_uris: [OAUTH_CALLBACK_URL],
26
+ grant_types: ['authorization_code', 'refresh_token'],
27
+ response_types: ['code'],
28
+ token_endpoint_auth_method: 'client_secret_post',
29
+ scope: 'mcp:tools'
30
+ };
31
+ oauthProvider = new simpleOAuthClientProvider_js_1.InMemoryOAuthClientProvider(OAUTH_CALLBACK_URL, clientMetadata, (redirectUrl) => {
32
+ console.log(`🌐 Opening browser for OAuth redirect: ${redirectUrl.toString()}`);
33
+ openBrowser(redirectUrl.toString());
34
+ });
35
+ // Create readline interface for user input
36
+ const readline = (0, node_readline_1.createInterface)({
37
+ input: process.stdin,
38
+ output: process.stdout
39
+ });
40
+ let abortCommand = new AbortController();
41
+ // Global client and transport for interactive commands
42
+ let client = null;
43
+ let transport = null;
44
+ let serverUrl = 'http://localhost:3000/mcp';
45
+ let sessionId = undefined;
46
+ let isProcessingCommand = false;
47
+ let isProcessingElicitations = false;
48
+ const elicitationQueue = [];
49
+ let elicitationQueueSignal = null;
50
+ let elicitationsCompleteSignal = null;
51
+ // Map to track pending URL elicitations waiting for completion notifications
52
+ const pendingURLElicitations = new Map();
53
+ async function main() {
54
+ console.log('MCP Interactive Client');
55
+ console.log('=====================');
56
+ // Connect to server immediately with default settings
57
+ await connect();
58
+ // Start the elicitation loop in the background
59
+ elicitationLoop().catch(error => {
60
+ console.error('Unexpected error in elicitation loop:', error);
61
+ process.exit(1);
62
+ });
63
+ // Short delay allowing the server to send any SSE elicitations on connection
64
+ await new Promise(resolve => setTimeout(resolve, 200));
65
+ // Wait until we are done processing any initial elicitations
66
+ await waitForElicitationsToComplete();
67
+ // Print help and start the command loop
68
+ printHelp();
69
+ await commandLoop();
70
+ }
71
+ async function waitForElicitationsToComplete() {
72
+ // Wait until the queue is empty and nothing is being processed
73
+ while (elicitationQueue.length > 0 || isProcessingElicitations) {
74
+ await new Promise(resolve => setTimeout(resolve, 100));
75
+ }
76
+ }
77
+ function printHelp() {
78
+ console.log('\nAvailable commands:');
79
+ console.log(' connect [url] - Connect to MCP server (default: http://localhost:3000/mcp)');
80
+ console.log(' disconnect - Disconnect from server');
81
+ console.log(' terminate-session - Terminate the current session');
82
+ console.log(' reconnect - Reconnect to the server');
83
+ console.log(' list-tools - List available tools');
84
+ console.log(' call-tool <name> [args] - Call a tool with optional JSON arguments');
85
+ console.log(' payment-confirm - Test URL elicitation via error response with payment-confirm tool');
86
+ console.log(' third-party-auth - Test tool that requires third-party OAuth credentials');
87
+ console.log(' help - Show this help');
88
+ console.log(' quit - Exit the program');
89
+ }
90
+ async function commandLoop() {
91
+ await new Promise(resolve => {
92
+ if (!isProcessingElicitations) {
93
+ resolve();
94
+ }
95
+ else {
96
+ elicitationsCompleteSignal = resolve;
97
+ }
98
+ });
99
+ readline.question('\n> ', { signal: abortCommand.signal }, async (input) => {
100
+ var _a;
101
+ isProcessingCommand = true;
102
+ const args = input.trim().split(/\s+/);
103
+ const command = (_a = args[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
104
+ try {
105
+ switch (command) {
106
+ case 'connect':
107
+ await connect(args[1]);
108
+ break;
109
+ case 'disconnect':
110
+ await disconnect();
111
+ break;
112
+ case 'terminate-session':
113
+ await terminateSession();
114
+ break;
115
+ case 'reconnect':
116
+ await reconnect();
117
+ break;
118
+ case 'list-tools':
119
+ await listTools();
120
+ break;
121
+ case 'call-tool':
122
+ if (args.length < 2) {
123
+ console.log('Usage: call-tool <name> [args]');
124
+ }
125
+ else {
126
+ const toolName = args[1];
127
+ let toolArgs = {};
128
+ if (args.length > 2) {
129
+ try {
130
+ toolArgs = JSON.parse(args.slice(2).join(' '));
131
+ }
132
+ catch (_b) {
133
+ console.log('Invalid JSON arguments. Using empty args.');
134
+ }
135
+ }
136
+ await callTool(toolName, toolArgs);
137
+ }
138
+ break;
139
+ case 'payment-confirm':
140
+ await callPaymentConfirmTool();
141
+ break;
142
+ case 'third-party-auth':
143
+ await callThirdPartyAuthTool();
144
+ break;
145
+ case 'help':
146
+ printHelp();
147
+ break;
148
+ case 'quit':
149
+ case 'exit':
150
+ await cleanup();
151
+ return;
152
+ default:
153
+ if (command) {
154
+ console.log(`Unknown command: ${command}`);
155
+ }
156
+ break;
157
+ }
158
+ }
159
+ catch (error) {
160
+ console.error(`Error executing command: ${error}`);
161
+ }
162
+ finally {
163
+ isProcessingCommand = false;
164
+ }
165
+ // Process another command after we've processed the this one
166
+ await commandLoop();
167
+ });
168
+ }
169
+ async function elicitationLoop() {
170
+ while (true) {
171
+ // Wait until we have elicitations to process
172
+ await new Promise(resolve => {
173
+ if (elicitationQueue.length > 0) {
174
+ resolve();
175
+ }
176
+ else {
177
+ elicitationQueueSignal = resolve;
178
+ }
179
+ });
180
+ isProcessingElicitations = true;
181
+ abortCommand.abort(); // Abort the command loop if it's running
182
+ // Process all queued elicitations
183
+ while (elicitationQueue.length > 0) {
184
+ const queued = elicitationQueue.shift();
185
+ console.log(`šŸ“¤ Processing queued elicitation (${elicitationQueue.length} remaining)`);
186
+ try {
187
+ const result = await handleElicitationRequest(queued.request);
188
+ queued.resolve(result);
189
+ }
190
+ catch (error) {
191
+ queued.reject(error instanceof Error ? error : new Error(String(error)));
192
+ }
193
+ }
194
+ console.log('āœ… All queued elicitations processed. Resuming command loop...\n');
195
+ isProcessingElicitations = false;
196
+ // Reset the abort controller for the next command loop
197
+ abortCommand = new AbortController();
198
+ // Resume the command loop
199
+ if (elicitationsCompleteSignal) {
200
+ elicitationsCompleteSignal();
201
+ elicitationsCompleteSignal = null;
202
+ }
203
+ }
204
+ }
205
+ async function openBrowser(url) {
206
+ const command = `open "${url}"`;
207
+ (0, node_child_process_1.exec)(command, error => {
208
+ if (error) {
209
+ console.error(`Failed to open browser: ${error.message}`);
210
+ console.log(`Please manually open: ${url}`);
211
+ }
212
+ });
213
+ }
214
+ /**
215
+ * Enqueues an elicitation request and returns the result.
216
+ *
217
+ * This function is used so that our CLI (which can only handle one input request at a time)
218
+ * can handle elicitation requests and the command loop.
219
+ *
220
+ * @param request - The elicitation request to be handled
221
+ * @returns The elicitation result
222
+ */
223
+ async function elicitationRequestHandler(request) {
224
+ // If we are processing a command, handle this elicitation immediately
225
+ if (isProcessingCommand) {
226
+ console.log('šŸ“‹ Processing elicitation immediately (during command execution)');
227
+ return await handleElicitationRequest(request);
228
+ }
229
+ // Otherwise, queue the request to be handled by the elicitation loop
230
+ console.log(`šŸ“„ Queueing elicitation request (queue size will be: ${elicitationQueue.length + 1})`);
231
+ return new Promise((resolve, reject) => {
232
+ elicitationQueue.push({
233
+ request,
234
+ resolve,
235
+ reject
236
+ });
237
+ // Signal the elicitation loop that there's work to do
238
+ if (elicitationQueueSignal) {
239
+ elicitationQueueSignal();
240
+ elicitationQueueSignal = null;
241
+ }
242
+ });
243
+ }
244
+ /**
245
+ * Handles an elicitation request.
246
+ *
247
+ * This function is used to handle the elicitation request and return the result.
248
+ *
249
+ * @param request - The elicitation request to be handled
250
+ * @returns The elicitation result
251
+ */
252
+ async function handleElicitationRequest(request) {
253
+ const mode = request.params.mode;
254
+ console.log('\nšŸ”” Elicitation Request Received:');
255
+ console.log(`Mode: ${mode}`);
256
+ if (mode === 'url') {
257
+ return {
258
+ action: await handleURLElicitation(request.params)
259
+ };
260
+ }
261
+ else {
262
+ // Should not happen because the client declares its capabilities to the server,
263
+ // but being defensive is a good practice:
264
+ throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Unsupported elicitation mode: ${mode}`);
265
+ }
266
+ }
267
+ /**
268
+ * Handles a URL elicitation by opening the URL in the browser.
269
+ *
270
+ * Note: This is a shared code for both request handlers and error handlers.
271
+ * As a result of sharing schema, there is no big forking of logic for the client.
272
+ *
273
+ * @param params - The URL elicitation request parameters
274
+ * @returns The action to take (accept, cancel, or decline)
275
+ */
276
+ async function handleURLElicitation(params) {
277
+ const url = params.url;
278
+ const elicitationId = params.elicitationId;
279
+ const message = params.message;
280
+ console.log(`šŸ†” Elicitation ID: ${elicitationId}`); // Print for illustration
281
+ // Parse URL to show domain for security
282
+ let domain = 'unknown domain';
283
+ try {
284
+ const parsedUrl = new URL(url);
285
+ domain = parsedUrl.hostname;
286
+ }
287
+ catch (_a) {
288
+ console.error('Invalid URL provided by server');
289
+ return 'decline';
290
+ }
291
+ // Example security warning to help prevent phishing attacks
292
+ console.log('\nāš ļø \x1b[33mSECURITY WARNING\x1b[0m āš ļø');
293
+ console.log('\x1b[33mThe server is requesting you to open an external URL.\x1b[0m');
294
+ console.log('\x1b[33mOnly proceed if you trust this server and understand why it needs this.\x1b[0m\n');
295
+ console.log(`🌐 Target domain: \x1b[36m${domain}\x1b[0m`);
296
+ console.log(`šŸ”— Full URL: \x1b[36m${url}\x1b[0m`);
297
+ console.log(`\nā„¹ļø Server's reason:\n\n\x1b[36m${message}\x1b[0m\n`);
298
+ // 1. Ask for user consent to open the URL
299
+ const consent = await new Promise(resolve => {
300
+ readline.question('\nDo you want to open this URL in your browser? (y/n): ', input => {
301
+ resolve(input.trim().toLowerCase());
302
+ });
303
+ });
304
+ // 2. If user did not consent, return appropriate result
305
+ if (consent === 'no' || consent === 'n') {
306
+ console.log('āŒ URL navigation declined.');
307
+ return 'decline';
308
+ }
309
+ else if (consent !== 'yes' && consent !== 'y') {
310
+ console.log('🚫 Invalid response. Cancelling elicitation.');
311
+ return 'cancel';
312
+ }
313
+ // 3. Wait for completion notification in the background
314
+ const completionPromise = new Promise((resolve, reject) => {
315
+ const timeout = setTimeout(() => {
316
+ pendingURLElicitations.delete(elicitationId);
317
+ console.log(`\x1b[31māŒ Elicitation ${elicitationId} timed out waiting for completion.\x1b[0m`);
318
+ reject(new Error('Elicitation completion timeout'));
319
+ }, 5 * 60 * 1000); // 5 minute timeout
320
+ pendingURLElicitations.set(elicitationId, {
321
+ resolve: () => {
322
+ clearTimeout(timeout);
323
+ resolve();
324
+ },
325
+ reject,
326
+ timeout
327
+ });
328
+ });
329
+ completionPromise.catch(error => {
330
+ console.error('Background completion wait failed:', error);
331
+ });
332
+ // 4. Open the URL in the browser
333
+ console.log(`\nšŸš€ Opening browser to: ${url}`);
334
+ await openBrowser(url);
335
+ console.log('\nā³ Waiting for you to complete the interaction in your browser...');
336
+ console.log(' The server will send a notification once you complete the action.');
337
+ // 5. Acknowledge the user accepted the elicitation
338
+ return 'accept';
339
+ }
340
+ /**
341
+ * Example OAuth callback handler - in production, use a more robust approach
342
+ * for handling callbacks and storing tokens
343
+ */
344
+ /**
345
+ * Starts a temporary HTTP server to receive the OAuth callback
346
+ */
347
+ async function waitForOAuthCallback() {
348
+ return new Promise((resolve, reject) => {
349
+ const server = (0, node_http_1.createServer)((req, res) => {
350
+ // Ignore favicon requests
351
+ if (req.url === '/favicon.ico') {
352
+ res.writeHead(404);
353
+ res.end();
354
+ return;
355
+ }
356
+ console.log(`šŸ“„ Received callback: ${req.url}`);
357
+ const parsedUrl = new URL(req.url || '', 'http://localhost');
358
+ const code = parsedUrl.searchParams.get('code');
359
+ const error = parsedUrl.searchParams.get('error');
360
+ if (code) {
361
+ console.log(`āœ… Authorization code received: ${code === null || code === void 0 ? void 0 : code.substring(0, 10)}...`);
362
+ res.writeHead(200, { 'Content-Type': 'text/html' });
363
+ res.end(`
364
+ <html>
365
+ <body>
366
+ <h1>Authorization Successful!</h1>
367
+ <p>This simulates successful authorization of the MCP client, which now has an access token for the MCP server.</p>
368
+ <p>This window will close automatically in 10 seconds.</p>
369
+ <script>setTimeout(() => window.close(), 10000);</script>
370
+ </body>
371
+ </html>
372
+ `);
373
+ resolve(code);
374
+ setTimeout(() => server.close(), 15000);
375
+ }
376
+ else if (error) {
377
+ console.log(`āŒ Authorization error: ${error}`);
378
+ res.writeHead(400, { 'Content-Type': 'text/html' });
379
+ res.end(`
380
+ <html>
381
+ <body>
382
+ <h1>Authorization Failed</h1>
383
+ <p>Error: ${error}</p>
384
+ </body>
385
+ </html>
386
+ `);
387
+ reject(new Error(`OAuth authorization failed: ${error}`));
388
+ }
389
+ else {
390
+ console.log(`āŒ No authorization code or error in callback`);
391
+ res.writeHead(400);
392
+ res.end('Bad request');
393
+ reject(new Error('No authorization code provided'));
394
+ }
395
+ });
396
+ server.listen(OAUTH_CALLBACK_PORT, () => {
397
+ console.log(`OAuth callback server started on http://localhost:${OAUTH_CALLBACK_PORT}`);
398
+ });
399
+ });
400
+ }
401
+ /**
402
+ * Attempts to connect to the MCP server with OAuth authentication.
403
+ * Handles OAuth flow recursively if authorization is required.
404
+ */
405
+ async function attemptConnection(oauthProvider) {
406
+ console.log('🚢 Creating transport with OAuth provider...');
407
+ const baseUrl = new URL(serverUrl);
408
+ transport = new streamableHttp_js_1.StreamableHTTPClientTransport(baseUrl, {
409
+ sessionId: sessionId,
410
+ authProvider: oauthProvider
411
+ });
412
+ console.log('🚢 Transport created');
413
+ try {
414
+ console.log('šŸ”Œ Attempting connection (this will trigger OAuth redirect if needed)...');
415
+ await client.connect(transport);
416
+ sessionId = transport.sessionId;
417
+ console.log('Transport created with session ID:', sessionId);
418
+ console.log('āœ… Connected successfully');
419
+ }
420
+ catch (error) {
421
+ if (error instanceof auth_js_1.UnauthorizedError) {
422
+ console.log('šŸ” OAuth required - waiting for authorization...');
423
+ const callbackPromise = waitForOAuthCallback();
424
+ const authCode = await callbackPromise;
425
+ await transport.finishAuth(authCode);
426
+ console.log('šŸ” Authorization code received:', authCode);
427
+ console.log('šŸ”Œ Reconnecting with authenticated transport...');
428
+ // Recursively retry connection after OAuth completion
429
+ await attemptConnection(oauthProvider);
430
+ }
431
+ else {
432
+ console.error('āŒ Connection failed with non-auth error:', error);
433
+ throw error;
434
+ }
435
+ }
436
+ }
437
+ async function connect(url) {
438
+ if (client) {
439
+ console.log('Already connected. Disconnect first.');
440
+ return;
441
+ }
442
+ if (url) {
443
+ serverUrl = url;
444
+ }
445
+ console.log(`šŸ”— Attempting to connect to ${serverUrl}...`);
446
+ // Create a new client with elicitation capability
447
+ console.log('šŸ‘¤ Creating MCP client...');
448
+ client = new index_js_1.Client({
449
+ name: 'example-client',
450
+ version: '1.0.0'
451
+ }, {
452
+ capabilities: {
453
+ elicitation: {
454
+ // Only URL elicitation is supported in this demo
455
+ // (see server/elicitationExample.ts for a demo of form mode elicitation)
456
+ url: {}
457
+ }
458
+ }
459
+ });
460
+ console.log('šŸ‘¤ Client created');
461
+ // Set up elicitation request handler with proper validation
462
+ client.setRequestHandler(types_js_1.ElicitRequestSchema, elicitationRequestHandler);
463
+ // Set up notification handler for elicitation completion
464
+ client.setNotificationHandler(types_js_1.ElicitationCompleteNotificationSchema, notification => {
465
+ const { elicitationId } = notification.params;
466
+ const pending = pendingURLElicitations.get(elicitationId);
467
+ if (pending) {
468
+ clearTimeout(pending.timeout);
469
+ pendingURLElicitations.delete(elicitationId);
470
+ console.log(`\x1b[32māœ… Elicitation ${elicitationId} completed!\x1b[0m`);
471
+ pending.resolve();
472
+ }
473
+ else {
474
+ // Shouldn't happen - discard it!
475
+ console.warn(`Received completion notification for unknown elicitation: ${elicitationId}`);
476
+ }
477
+ });
478
+ try {
479
+ console.log('šŸ” Starting OAuth flow...');
480
+ await attemptConnection(oauthProvider);
481
+ console.log('Connected to MCP server');
482
+ // Set up error handler after connection is established so we don't double log errors
483
+ client.onerror = error => {
484
+ console.error('\x1b[31mClient error:', error, '\x1b[0m');
485
+ };
486
+ }
487
+ catch (error) {
488
+ console.error('Failed to connect:', error);
489
+ client = null;
490
+ transport = null;
491
+ return;
492
+ }
493
+ }
494
+ async function disconnect() {
495
+ if (!client || !transport) {
496
+ console.log('Not connected.');
497
+ return;
498
+ }
499
+ try {
500
+ await transport.close();
501
+ console.log('Disconnected from MCP server');
502
+ client = null;
503
+ transport = null;
504
+ }
505
+ catch (error) {
506
+ console.error('Error disconnecting:', error);
507
+ }
508
+ }
509
+ async function terminateSession() {
510
+ if (!client || !transport) {
511
+ console.log('Not connected.');
512
+ return;
513
+ }
514
+ try {
515
+ console.log('Terminating session with ID:', transport.sessionId);
516
+ await transport.terminateSession();
517
+ console.log('Session terminated successfully');
518
+ // Check if sessionId was cleared after termination
519
+ if (!transport.sessionId) {
520
+ console.log('Session ID has been cleared');
521
+ sessionId = undefined;
522
+ // Also close the transport and clear client objects
523
+ await transport.close();
524
+ console.log('Transport closed after session termination');
525
+ client = null;
526
+ transport = null;
527
+ }
528
+ else {
529
+ console.log('Server responded with 405 Method Not Allowed (session termination not supported)');
530
+ console.log('Session ID is still active:', transport.sessionId);
531
+ }
532
+ }
533
+ catch (error) {
534
+ console.error('Error terminating session:', error);
535
+ }
536
+ }
537
+ async function reconnect() {
538
+ if (client) {
539
+ await disconnect();
540
+ }
541
+ await connect();
542
+ }
543
+ async function listTools() {
544
+ if (!client) {
545
+ console.log('Not connected to server.');
546
+ return;
547
+ }
548
+ try {
549
+ const toolsRequest = {
550
+ method: 'tools/list',
551
+ params: {}
552
+ };
553
+ const toolsResult = await client.request(toolsRequest, types_js_1.ListToolsResultSchema);
554
+ console.log('Available tools:');
555
+ if (toolsResult.tools.length === 0) {
556
+ console.log(' No tools available');
557
+ }
558
+ else {
559
+ for (const tool of toolsResult.tools) {
560
+ console.log(` - id: ${tool.name}, name: ${(0, metadataUtils_js_1.getDisplayName)(tool)}, description: ${tool.description}`);
561
+ }
562
+ }
563
+ }
564
+ catch (error) {
565
+ console.log(`Tools not supported by this server (${error})`);
566
+ }
567
+ }
568
+ async function callTool(name, args) {
569
+ if (!client) {
570
+ console.log('Not connected to server.');
571
+ return;
572
+ }
573
+ try {
574
+ const request = {
575
+ method: 'tools/call',
576
+ params: {
577
+ name,
578
+ arguments: args
579
+ }
580
+ };
581
+ console.log(`Calling tool '${name}' with args:`, args);
582
+ const result = await client.request(request, types_js_1.CallToolResultSchema);
583
+ console.log('Tool result:');
584
+ const resourceLinks = [];
585
+ result.content.forEach(item => {
586
+ if (item.type === 'text') {
587
+ console.log(` ${item.text}`);
588
+ }
589
+ else if (item.type === 'resource_link') {
590
+ const resourceLink = item;
591
+ resourceLinks.push(resourceLink);
592
+ console.log(` šŸ“ Resource Link: ${resourceLink.name}`);
593
+ console.log(` URI: ${resourceLink.uri}`);
594
+ if (resourceLink.mimeType) {
595
+ console.log(` Type: ${resourceLink.mimeType}`);
596
+ }
597
+ if (resourceLink.description) {
598
+ console.log(` Description: ${resourceLink.description}`);
599
+ }
600
+ }
601
+ else if (item.type === 'resource') {
602
+ console.log(` [Embedded Resource: ${item.resource.uri}]`);
603
+ }
604
+ else if (item.type === 'image') {
605
+ console.log(` [Image: ${item.mimeType}]`);
606
+ }
607
+ else if (item.type === 'audio') {
608
+ console.log(` [Audio: ${item.mimeType}]`);
609
+ }
610
+ else {
611
+ console.log(` [Unknown content type]:`, item);
612
+ }
613
+ });
614
+ // Offer to read resource links
615
+ if (resourceLinks.length > 0) {
616
+ console.log(`\nFound ${resourceLinks.length} resource link(s). Use 'read-resource <uri>' to read their content.`);
617
+ }
618
+ }
619
+ catch (error) {
620
+ if (error instanceof types_js_1.UrlElicitationRequiredError) {
621
+ console.log('\nšŸ”” Elicitation Required Error Received:');
622
+ console.log(`Message: ${error.message}`);
623
+ for (const e of error.elicitations) {
624
+ await handleURLElicitation(e); // For the error handler, we discard the action result because we don't respond to an error response
625
+ }
626
+ return;
627
+ }
628
+ console.log(`Error calling tool ${name}: ${error}`);
629
+ }
630
+ }
631
+ async function cleanup() {
632
+ if (client && transport) {
633
+ try {
634
+ // First try to terminate the session gracefully
635
+ if (transport.sessionId) {
636
+ try {
637
+ console.log('Terminating session before exit...');
638
+ await transport.terminateSession();
639
+ console.log('Session terminated successfully');
640
+ }
641
+ catch (error) {
642
+ console.error('Error terminating session:', error);
643
+ }
644
+ }
645
+ // Then close the transport
646
+ await transport.close();
647
+ }
648
+ catch (error) {
649
+ console.error('Error closing transport:', error);
650
+ }
651
+ }
652
+ process.stdin.setRawMode(false);
653
+ readline.close();
654
+ console.log('\nGoodbye!');
655
+ process.exit(0);
656
+ }
657
+ async function callPaymentConfirmTool() {
658
+ console.log('Calling payment-confirm tool...');
659
+ await callTool('payment-confirm', { cartId: 'cart_123' });
660
+ }
661
+ async function callThirdPartyAuthTool() {
662
+ console.log('Calling third-party-auth tool...');
663
+ await callTool('third-party-auth', { param1: 'test' });
664
+ }
665
+ // Set up raw mode for keyboard input to capture Escape key
666
+ process.stdin.setRawMode(true);
667
+ process.stdin.on('data', async (data) => {
668
+ // Check for Escape key (27)
669
+ if (data.length === 1 && data[0] === 27) {
670
+ console.log('\nESC key pressed. Disconnecting from server...');
671
+ // Abort current operation and disconnect from server
672
+ if (client && transport) {
673
+ await disconnect();
674
+ console.log('Disconnected. Press Enter to continue.');
675
+ }
676
+ else {
677
+ console.log('Not connected to server.');
678
+ }
679
+ // Re-display the prompt
680
+ process.stdout.write('> ');
681
+ }
682
+ });
683
+ // Handle Ctrl+C
684
+ process.on('SIGINT', async () => {
685
+ console.log('\nReceived SIGINT. Cleaning up...');
686
+ await cleanup();
687
+ });
688
+ // Start the interactive client
689
+ main().catch((error) => {
690
+ console.error('Error running MCP client:', error);
691
+ process.exit(1);
692
+ });
693
+ //# sourceMappingURL=elicitationUrlExample.js.map