@eclipse-glsp/server-mcp 2.7.0-next.9

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 (303) hide show
  1. package/LICENSE +642 -0
  2. package/README.md +57 -0
  3. package/lib/index.d.ts +23 -0
  4. package/lib/index.d.ts.map +1 -0
  5. package/lib/index.js +41 -0
  6. package/lib/index.js.map +1 -0
  7. package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.d.ts +43 -0
  8. package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.d.ts.map +1 -0
  9. package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.js +96 -0
  10. package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.js.map +1 -0
  11. package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.d.ts +43 -0
  12. package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.d.ts.map +1 -0
  13. package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.js +95 -0
  14. package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.js.map +1 -0
  15. package/lib/prompts/index.d.ts +18 -0
  16. package/lib/prompts/index.d.ts.map +1 -0
  17. package/lib/prompts/index.js +34 -0
  18. package/lib/prompts/index.js.map +1 -0
  19. package/lib/resources/handlers/diagram-png-mcp-resource-handler.d.ts +81 -0
  20. package/lib/resources/handlers/diagram-png-mcp-resource-handler.d.ts.map +1 -0
  21. package/lib/resources/handlers/diagram-png-mcp-resource-handler.js +174 -0
  22. package/lib/resources/handlers/diagram-png-mcp-resource-handler.js.map +1 -0
  23. package/lib/resources/handlers/diagram-svg-mcp-resource-handler.d.ts +52 -0
  24. package/lib/resources/handlers/diagram-svg-mcp-resource-handler.d.ts.map +1 -0
  25. package/lib/resources/handlers/diagram-svg-mcp-resource-handler.js +96 -0
  26. package/lib/resources/handlers/diagram-svg-mcp-resource-handler.js.map +1 -0
  27. package/lib/resources/index.d.ts +20 -0
  28. package/lib/resources/index.d.ts.map +1 -0
  29. package/lib/resources/index.js +36 -0
  30. package/lib/resources/index.js.map +1 -0
  31. package/lib/resources/services/element-types-provider.d.ts +65 -0
  32. package/lib/resources/services/element-types-provider.d.ts.map +1 -0
  33. package/lib/resources/services/element-types-provider.js +81 -0
  34. package/lib/resources/services/element-types-provider.js.map +1 -0
  35. package/lib/resources/services/mcp-model-serializer.d.ts +78 -0
  36. package/lib/resources/services/mcp-model-serializer.d.ts.map +1 -0
  37. package/lib/resources/services/mcp-model-serializer.js +188 -0
  38. package/lib/resources/services/mcp-model-serializer.js.map +1 -0
  39. package/lib/server/glsp-mcp-server.d.ts +82 -0
  40. package/lib/server/glsp-mcp-server.d.ts.map +1 -0
  41. package/lib/server/glsp-mcp-server.js +140 -0
  42. package/lib/server/glsp-mcp-server.js.map +1 -0
  43. package/lib/server/index.d.ts +37 -0
  44. package/lib/server/index.d.ts.map +1 -0
  45. package/lib/server/index.js +57 -0
  46. package/lib/server/index.js.map +1 -0
  47. package/lib/server/lru-event-store.d.ts +53 -0
  48. package/lib/server/lru-event-store.d.ts.map +1 -0
  49. package/lib/server/lru-event-store.js +100 -0
  50. package/lib/server/lru-event-store.js.map +1 -0
  51. package/lib/server/mcp-diagram-handler-dispatcher.d.ts +144 -0
  52. package/lib/server/mcp-diagram-handler-dispatcher.d.ts.map +1 -0
  53. package/lib/server/mcp-diagram-handler-dispatcher.js +382 -0
  54. package/lib/server/mcp-diagram-handler-dispatcher.js.map +1 -0
  55. package/lib/server/mcp-diagram-module.d.ts +123 -0
  56. package/lib/server/mcp-diagram-module.d.ts.map +1 -0
  57. package/lib/server/mcp-diagram-module.js +186 -0
  58. package/lib/server/mcp-diagram-module.js.map +1 -0
  59. package/lib/server/mcp-diagram-prompt-handler-registry.d.ts +33 -0
  60. package/lib/server/mcp-diagram-prompt-handler-registry.d.ts.map +1 -0
  61. package/lib/server/mcp-diagram-prompt-handler-registry.js +76 -0
  62. package/lib/server/mcp-diagram-prompt-handler-registry.js.map +1 -0
  63. package/lib/server/mcp-diagram-resource-handler-registry.d.ts +35 -0
  64. package/lib/server/mcp-diagram-resource-handler-registry.d.ts.map +1 -0
  65. package/lib/server/mcp-diagram-resource-handler-registry.js +94 -0
  66. package/lib/server/mcp-diagram-resource-handler-registry.js.map +1 -0
  67. package/lib/server/mcp-diagram-tool-handler-registry.d.ts +57 -0
  68. package/lib/server/mcp-diagram-tool-handler-registry.d.ts.map +1 -0
  69. package/lib/server/mcp-diagram-tool-handler-registry.js +111 -0
  70. package/lib/server/mcp-diagram-tool-handler-registry.js.map +1 -0
  71. package/lib/server/mcp-handler-shared.d.ts +142 -0
  72. package/lib/server/mcp-handler-shared.d.ts.map +1 -0
  73. package/lib/server/mcp-handler-shared.js +199 -0
  74. package/lib/server/mcp-handler-shared.js.map +1 -0
  75. package/lib/server/mcp-http-transport.d.ts +93 -0
  76. package/lib/server/mcp-http-transport.d.ts.map +1 -0
  77. package/lib/server/mcp-http-transport.js +350 -0
  78. package/lib/server/mcp-http-transport.js.map +1 -0
  79. package/lib/server/mcp-id-alias-service.d.ts +70 -0
  80. package/lib/server/mcp-id-alias-service.d.ts.map +1 -0
  81. package/lib/server/mcp-id-alias-service.js +85 -0
  82. package/lib/server/mcp-id-alias-service.js.map +1 -0
  83. package/lib/server/mcp-input-schemas.d.ts +73 -0
  84. package/lib/server/mcp-input-schemas.d.ts.map +1 -0
  85. package/lib/server/mcp-input-schemas.js +67 -0
  86. package/lib/server/mcp-input-schemas.js.map +1 -0
  87. package/lib/server/mcp-label-provider.d.ts +45 -0
  88. package/lib/server/mcp-label-provider.d.ts.map +1 -0
  89. package/lib/server/mcp-label-provider.js +42 -0
  90. package/lib/server/mcp-label-provider.js.map +1 -0
  91. package/lib/server/mcp-log-level-registry.d.ts +54 -0
  92. package/lib/server/mcp-log-level-registry.d.ts.map +1 -0
  93. package/lib/server/mcp-log-level-registry.js +80 -0
  94. package/lib/server/mcp-log-level-registry.js.map +1 -0
  95. package/lib/server/mcp-logger.d.ts +59 -0
  96. package/lib/server/mcp-logger.d.ts.map +1 -0
  97. package/lib/server/mcp-logger.js +104 -0
  98. package/lib/server/mcp-logger.js.map +1 -0
  99. package/lib/server/mcp-mime-types.d.ts +28 -0
  100. package/lib/server/mcp-mime-types.d.ts.map +1 -0
  101. package/lib/server/mcp-mime-types.js +18 -0
  102. package/lib/server/mcp-mime-types.js.map +1 -0
  103. package/lib/server/mcp-options.d.ts +39 -0
  104. package/lib/server/mcp-options.d.ts.map +1 -0
  105. package/lib/server/mcp-options.js +53 -0
  106. package/lib/server/mcp-options.js.map +1 -0
  107. package/lib/server/mcp-progress-reporter.d.ts +48 -0
  108. package/lib/server/mcp-progress-reporter.d.ts.map +1 -0
  109. package/lib/server/mcp-progress-reporter.js +66 -0
  110. package/lib/server/mcp-progress-reporter.js.map +1 -0
  111. package/lib/server/mcp-prompt-handler.d.ts +120 -0
  112. package/lib/server/mcp-prompt-handler.d.ts.map +1 -0
  113. package/lib/server/mcp-prompt-handler.js +131 -0
  114. package/lib/server/mcp-prompt-handler.js.map +1 -0
  115. package/lib/server/mcp-request-context.d.ts +37 -0
  116. package/lib/server/mcp-request-context.d.ts.map +1 -0
  117. package/lib/server/mcp-request-context.js +37 -0
  118. package/lib/server/mcp-request-context.js.map +1 -0
  119. package/lib/server/mcp-resource-handler.d.ts +212 -0
  120. package/lib/server/mcp-resource-handler.d.ts.map +1 -0
  121. package/lib/server/mcp-resource-handler.js +298 -0
  122. package/lib/server/mcp-resource-handler.js.map +1 -0
  123. package/lib/server/mcp-server-launcher.d.ts +143 -0
  124. package/lib/server/mcp-server-launcher.d.ts.map +1 -0
  125. package/lib/server/mcp-server-launcher.js +355 -0
  126. package/lib/server/mcp-server-launcher.js.map +1 -0
  127. package/lib/server/mcp-server-module.d.ts +143 -0
  128. package/lib/server/mcp-server-module.d.ts.map +1 -0
  129. package/lib/server/mcp-server-module.js +249 -0
  130. package/lib/server/mcp-server-module.js.map +1 -0
  131. package/lib/server/mcp-session.d.ts +44 -0
  132. package/lib/server/mcp-session.d.ts.map +1 -0
  133. package/lib/server/mcp-session.js +18 -0
  134. package/lib/server/mcp-session.js.map +1 -0
  135. package/lib/server/mcp-tool-handler.d.ts +259 -0
  136. package/lib/server/mcp-tool-handler.d.ts.map +1 -0
  137. package/lib/server/mcp-tool-handler.js +355 -0
  138. package/lib/server/mcp-tool-handler.js.map +1 -0
  139. package/lib/tools/handlers/count-elements-mcp-tool-handler.d.ts +46 -0
  140. package/lib/tools/handlers/count-elements-mcp-tool-handler.d.ts.map +1 -0
  141. package/lib/tools/handlers/count-elements-mcp-tool-handler.js +76 -0
  142. package/lib/tools/handlers/count-elements-mcp-tool-handler.js.map +1 -0
  143. package/lib/tools/handlers/create-edges-mcp-tool-handler.d.ts +112 -0
  144. package/lib/tools/handlers/create-edges-mcp-tool-handler.d.ts.map +1 -0
  145. package/lib/tools/handlers/create-edges-mcp-tool-handler.js +190 -0
  146. package/lib/tools/handlers/create-edges-mcp-tool-handler.js.map +1 -0
  147. package/lib/tools/handlers/create-nodes-mcp-tool-handler.d.ts +81 -0
  148. package/lib/tools/handlers/create-nodes-mcp-tool-handler.d.ts.map +1 -0
  149. package/lib/tools/handlers/create-nodes-mcp-tool-handler.js +123 -0
  150. package/lib/tools/handlers/create-nodes-mcp-tool-handler.js.map +1 -0
  151. package/lib/tools/handlers/delete-elements-mcp-tool-handler.d.ts +52 -0
  152. package/lib/tools/handlers/delete-elements-mcp-tool-handler.d.ts.map +1 -0
  153. package/lib/tools/handlers/delete-elements-mcp-tool-handler.js +73 -0
  154. package/lib/tools/handlers/delete-elements-mcp-tool-handler.js.map +1 -0
  155. package/lib/tools/handlers/diagram-model-mcp-tool-handler.d.ts +59 -0
  156. package/lib/tools/handlers/diagram-model-mcp-tool-handler.d.ts.map +1 -0
  157. package/lib/tools/handlers/diagram-model-mcp-tool-handler.js +78 -0
  158. package/lib/tools/handlers/diagram-model-mcp-tool-handler.js.map +1 -0
  159. package/lib/tools/handlers/element-types-mcp-tool-handler.d.ts +97 -0
  160. package/lib/tools/handlers/element-types-mcp-tool-handler.d.ts.map +1 -0
  161. package/lib/tools/handlers/element-types-mcp-tool-handler.js +155 -0
  162. package/lib/tools/handlers/element-types-mcp-tool-handler.js.map +1 -0
  163. package/lib/tools/handlers/get-selection-mcp-tool-handler.d.ts +43 -0
  164. package/lib/tools/handlers/get-selection-mcp-tool-handler.d.ts.map +1 -0
  165. package/lib/tools/handlers/get-selection-mcp-tool-handler.js +68 -0
  166. package/lib/tools/handlers/get-selection-mcp-tool-handler.js.map +1 -0
  167. package/lib/tools/handlers/layout-mcp-tool-handler.d.ts +43 -0
  168. package/lib/tools/handlers/layout-mcp-tool-handler.d.ts.map +1 -0
  169. package/lib/tools/handlers/layout-mcp-tool-handler.js +71 -0
  170. package/lib/tools/handlers/layout-mcp-tool-handler.js.map +1 -0
  171. package/lib/tools/handlers/modify-edges-mcp-tool-handler.d.ts +78 -0
  172. package/lib/tools/handlers/modify-edges-mcp-tool-handler.d.ts.map +1 -0
  173. package/lib/tools/handlers/modify-edges-mcp-tool-handler.js +136 -0
  174. package/lib/tools/handlers/modify-edges-mcp-tool-handler.js.map +1 -0
  175. package/lib/tools/handlers/modify-nodes-mcp-tool-handler.d.ts +92 -0
  176. package/lib/tools/handlers/modify-nodes-mcp-tool-handler.d.ts.map +1 -0
  177. package/lib/tools/handlers/modify-nodes-mcp-tool-handler.js +125 -0
  178. package/lib/tools/handlers/modify-nodes-mcp-tool-handler.js.map +1 -0
  179. package/lib/tools/handlers/query-elements-mcp-tool-handler.d.ts +102 -0
  180. package/lib/tools/handlers/query-elements-mcp-tool-handler.d.ts.map +1 -0
  181. package/lib/tools/handlers/query-elements-mcp-tool-handler.js +158 -0
  182. package/lib/tools/handlers/query-elements-mcp-tool-handler.js.map +1 -0
  183. package/lib/tools/handlers/redo-mcp-tool-handler.d.ts +45 -0
  184. package/lib/tools/handlers/redo-mcp-tool-handler.d.ts.map +1 -0
  185. package/lib/tools/handlers/redo-mcp-tool-handler.js +73 -0
  186. package/lib/tools/handlers/redo-mcp-tool-handler.js.map +1 -0
  187. package/lib/tools/handlers/save-model-mcp-tool-handler.d.ts +55 -0
  188. package/lib/tools/handlers/save-model-mcp-tool-handler.d.ts.map +1 -0
  189. package/lib/tools/handlers/save-model-mcp-tool-handler.js +91 -0
  190. package/lib/tools/handlers/save-model-mcp-tool-handler.js.map +1 -0
  191. package/lib/tools/handlers/session-info-mcp-tool-handler.d.ts +65 -0
  192. package/lib/tools/handlers/session-info-mcp-tool-handler.d.ts.map +1 -0
  193. package/lib/tools/handlers/session-info-mcp-tool-handler.js +108 -0
  194. package/lib/tools/handlers/session-info-mcp-tool-handler.js.map +1 -0
  195. package/lib/tools/handlers/set-selection-mcp-tool-handler.d.ts +60 -0
  196. package/lib/tools/handlers/set-selection-mcp-tool-handler.d.ts.map +1 -0
  197. package/lib/tools/handlers/set-selection-mcp-tool-handler.js +103 -0
  198. package/lib/tools/handlers/set-selection-mcp-tool-handler.js.map +1 -0
  199. package/lib/tools/handlers/set-view-mcp-tool-handler.d.ts +110 -0
  200. package/lib/tools/handlers/set-view-mcp-tool-handler.d.ts.map +1 -0
  201. package/lib/tools/handlers/set-view-mcp-tool-handler.js +142 -0
  202. package/lib/tools/handlers/set-view-mcp-tool-handler.js.map +1 -0
  203. package/lib/tools/handlers/undo-mcp-tool-handler.d.ts +45 -0
  204. package/lib/tools/handlers/undo-mcp-tool-handler.d.ts.map +1 -0
  205. package/lib/tools/handlers/undo-mcp-tool-handler.js +74 -0
  206. package/lib/tools/handlers/undo-mcp-tool-handler.js.map +1 -0
  207. package/lib/tools/handlers/validate-diagram-mcp-tool-handler.d.ts +66 -0
  208. package/lib/tools/handlers/validate-diagram-mcp-tool-handler.d.ts.map +1 -0
  209. package/lib/tools/handlers/validate-diagram-mcp-tool-handler.js +0 -0
  210. package/lib/tools/handlers/validate-diagram-mcp-tool-handler.js.map +1 -0
  211. package/lib/tools/index.d.ts +34 -0
  212. package/lib/tools/index.d.ts.map +1 -0
  213. package/lib/tools/index.js +50 -0
  214. package/lib/tools/index.js.map +1 -0
  215. package/lib/util/index.d.ts +18 -0
  216. package/lib/util/index.d.ts.map +1 -0
  217. package/lib/util/index.js +34 -0
  218. package/lib/util/index.js.map +1 -0
  219. package/lib/util/markdown-util.d.ts +20 -0
  220. package/lib/util/markdown-util.d.ts.map +1 -0
  221. package/lib/util/markdown-util.js +45 -0
  222. package/lib/util/markdown-util.js.map +1 -0
  223. package/lib/util/mcp-util.d.ts +22 -0
  224. package/lib/util/mcp-util.d.ts.map +1 -0
  225. package/lib/util/mcp-util.js +29 -0
  226. package/lib/util/mcp-util.js.map +1 -0
  227. package/package.json +63 -0
  228. package/src/index.ts +24 -0
  229. package/src/prompts/handlers/describe-diagram-mcp-prompt-handler.ts +89 -0
  230. package/src/prompts/handlers/suggest-improvements-mcp-prompt-handler.ts +86 -0
  231. package/src/prompts/index.ts +18 -0
  232. package/src/resources/handlers/diagram-png-mcp-resource-handler.ts +181 -0
  233. package/src/resources/handlers/diagram-svg-mcp-resource-handler.ts +89 -0
  234. package/src/resources/index.ts +20 -0
  235. package/src/resources/services/element-types-provider.ts +105 -0
  236. package/src/resources/services/mcp-model-serializer.ts +211 -0
  237. package/src/server/glsp-mcp-server.spec.ts +73 -0
  238. package/src/server/glsp-mcp-server.ts +196 -0
  239. package/src/server/index.ts +42 -0
  240. package/src/server/lru-event-store.spec.ts +121 -0
  241. package/src/server/lru-event-store.ts +112 -0
  242. package/src/server/mcp-diagram-handler-dispatcher.spec.ts +231 -0
  243. package/src/server/mcp-diagram-handler-dispatcher.ts +459 -0
  244. package/src/server/mcp-diagram-module.ts +248 -0
  245. package/src/server/mcp-diagram-prompt-handler-registry.ts +59 -0
  246. package/src/server/mcp-diagram-resource-handler-registry.ts +73 -0
  247. package/src/server/mcp-diagram-tool-handler-registry.ts +97 -0
  248. package/src/server/mcp-handler-shared.spec.ts +53 -0
  249. package/src/server/mcp-handler-shared.ts +247 -0
  250. package/src/server/mcp-http-transport-e2e.spec.ts +151 -0
  251. package/src/server/mcp-http-transport.spec.ts +385 -0
  252. package/src/server/mcp-http-transport.ts +368 -0
  253. package/src/server/mcp-id-alias-service.spec.ts +106 -0
  254. package/src/server/mcp-id-alias-service.ts +104 -0
  255. package/src/server/mcp-input-schemas.ts +82 -0
  256. package/src/server/mcp-label-provider.ts +52 -0
  257. package/src/server/mcp-log-level-registry.spec.ts +75 -0
  258. package/src/server/mcp-log-level-registry.ts +90 -0
  259. package/src/server/mcp-logger.spec.ts +227 -0
  260. package/src/server/mcp-logger.ts +91 -0
  261. package/src/server/mcp-mime-types.ts +31 -0
  262. package/src/server/mcp-options.ts +43 -0
  263. package/src/server/mcp-progress-reporter.spec.ts +93 -0
  264. package/src/server/mcp-progress-reporter.ts +67 -0
  265. package/src/server/mcp-prompt-handler.ts +157 -0
  266. package/src/server/mcp-request-context.ts +39 -0
  267. package/src/server/mcp-resource-handler.ts +389 -0
  268. package/src/server/mcp-server-launcher.spec.ts +173 -0
  269. package/src/server/mcp-server-launcher.ts +369 -0
  270. package/src/server/mcp-server-module.ts +287 -0
  271. package/src/server/mcp-session.ts +45 -0
  272. package/src/server/mcp-tool-handler.spec.ts +182 -0
  273. package/src/server/mcp-tool-handler.ts +431 -0
  274. package/src/server/raw-http.spec.ts +59 -0
  275. package/src/tools/handlers/count-elements-mcp-tool-handler.spec.ts +99 -0
  276. package/src/tools/handlers/count-elements-mcp-tool-handler.ts +66 -0
  277. package/src/tools/handlers/create-edges-mcp-tool-handler.spec.ts +196 -0
  278. package/src/tools/handlers/create-edges-mcp-tool-handler.ts +205 -0
  279. package/src/tools/handlers/create-nodes-mcp-tool-handler.spec.ts +197 -0
  280. package/src/tools/handlers/create-nodes-mcp-tool-handler.ts +131 -0
  281. package/src/tools/handlers/delete-elements-mcp-tool-handler.ts +73 -0
  282. package/src/tools/handlers/diagram-model-mcp-tool-handler.ts +66 -0
  283. package/src/tools/handlers/element-types-mcp-tool-handler.ts +151 -0
  284. package/src/tools/handlers/get-selection-mcp-tool-handler.ts +54 -0
  285. package/src/tools/handlers/layout-mcp-tool-handler.ts +56 -0
  286. package/src/tools/handlers/modify-edges-mcp-tool-handler.ts +148 -0
  287. package/src/tools/handlers/modify-nodes-mcp-tool-handler.ts +140 -0
  288. package/src/tools/handlers/query-elements-mcp-tool-handler.spec.ts +210 -0
  289. package/src/tools/handlers/query-elements-mcp-tool-handler.ts +161 -0
  290. package/src/tools/handlers/redo-mcp-tool-handler.ts +62 -0
  291. package/src/tools/handlers/save-model-mcp-tool-handler.ts +71 -0
  292. package/src/tools/handlers/session-info-mcp-tool-handler.spec.ts +152 -0
  293. package/src/tools/handlers/session-info-mcp-tool-handler.ts +97 -0
  294. package/src/tools/handlers/set-selection-mcp-tool-handler.spec.ts +118 -0
  295. package/src/tools/handlers/set-selection-mcp-tool-handler.ts +90 -0
  296. package/src/tools/handlers/set-view-mcp-tool-handler.ts +162 -0
  297. package/src/tools/handlers/undo-mcp-tool-handler.ts +61 -0
  298. package/src/tools/handlers/validate-diagram-mcp-tool-handler.ts +0 -0
  299. package/src/tools/index.ts +34 -0
  300. package/src/tools/tool-annotations.spec.ts +141 -0
  301. package/src/util/index.ts +18 -0
  302. package/src/util/markdown-util.ts +44 -0
  303. package/src/util/mcp-util.ts +25 -0
@@ -0,0 +1,368 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2025-2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { Deferred, Disposable, Emitter, Logger } from '@eclipse-glsp/server';
18
+ import { createMcpExpressApp } from '@modelcontextprotocol/sdk/server/express.js';
19
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
20
+ import { SUPPORTED_PROTOCOL_VERSIONS, isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
21
+ import type { Express } from 'express';
22
+ import * as express from 'express';
23
+ import * as http from 'http';
24
+ import { inject, injectable } from 'inversify';
25
+ import { AddressInfo } from 'net';
26
+ import { randomUUID } from 'node:crypto';
27
+ import { LruEventStore } from './lru-event-store';
28
+ import { McpServerOptions } from './mcp-options';
29
+ import type { FullMcpServerConfiguration } from './mcp-server-launcher';
30
+ import { McpSession, McpSessionId, WithSessionId } from './mcp-session';
31
+
32
+ /**
33
+ * Where this transport can be reached. Network transports populate `url`;
34
+ * future in-process or stdio transports would leave it undefined.
35
+ */
36
+ export interface TransportEndpoint {
37
+ url?: string;
38
+ headers?: Record<string, string>;
39
+ }
40
+
41
+ @injectable()
42
+ export class McpHttpTransport implements Disposable {
43
+ protected _app?: Express;
44
+ protected _server?: http.Server;
45
+ protected _addressInfo = new Deferred<AddressInfo>();
46
+
47
+ protected sessions = new Map<string, StreamableHTTPServerTransport>();
48
+ protected onSessionInitializedEmitter = new Emitter<McpSession>();
49
+ onSessionInitialized = this.onSessionInitializedEmitter.event;
50
+ protected onSessionClosedEmitter = new Emitter<McpSessionId>();
51
+ onSessionClosed = this.onSessionClosedEmitter.event;
52
+
53
+ @inject(McpServerOptions) protected serverOptions: McpServerOptions;
54
+
55
+ constructor(@inject(Logger) protected logger: Logger) {}
56
+
57
+ get app(): Express | undefined {
58
+ return this._app;
59
+ }
60
+
61
+ get server(): http.Server | undefined {
62
+ return this._server;
63
+ }
64
+
65
+ getAddress(): Promise<AddressInfo> {
66
+ return this._addressInfo.promise;
67
+ }
68
+
69
+ async start(config: FullMcpServerConfiguration): Promise<TransportEndpoint> {
70
+ const { route, host, port } = config;
71
+ // `createMcpExpressApp` gives us (a) a base Express app, (b) `express.json()` body
72
+ // parsing — load-bearing; without it `req.body` is undefined and `isInitializeRequest`
73
+ // can't tell init from non-init — and (c) DNS-rebinding host-header validation for
74
+ // the configured allowlist. We forward our `allowedHosts` so the SDK's validator and
75
+ // any explicit policy share one source of truth.
76
+ this._app = createMcpExpressApp({ host, allowedHosts: this.serverOptions.values.allowedHosts });
77
+ // Allow subclasses to install Express middleware (auth, CORS, rate-limiting,
78
+ // request logging) before the MCP routes are registered. Default: origin allowlist.
79
+ this.configureExpressApp(this._app);
80
+ // MCP-Protocol-Version validation runs after subclass middleware so adopter-installed
81
+ // gates (auth, CORS) get first cut, but before the SDK route handlers so an unsupported
82
+ // header rejects with HTTP 400 cleanly per spec.
83
+ this._app.use(route, this.validateProtocolVersionHeader.bind(this));
84
+ this._app.post(route, this.handlePostRequest.bind(this));
85
+ this._app.get(route, this.handleGetRequest.bind(this));
86
+ this._app.delete(route, this.handleDeleteRequest.bind(this));
87
+ this._server = this._app.listen(port, host);
88
+ // Disable the per-request timeout so long-lived SSE GET streams aren't killed during
89
+ // chat idle periods. From Node's perspective an SSE response is a single in-progress
90
+ // request that lasts as long as the client stays connected, so the default 5-minute
91
+ // `requestTimeout` (Node 18.1+) terminates the socket whenever no events flow for
92
+ // ≥5 min — the client surfaces this as `TypeError: terminated`. We rely on the MCP
93
+ // session-id handshake + `onclose` to detect gone clients.
94
+ this._server.requestTimeout = 0;
95
+ this._server.on('listening', () => this.listening());
96
+ // Pre-listen errors (typically `EADDRINUSE`) fire on the http.Server. Without a
97
+ // listener the deferred address never resolves and `start()` hangs; with it we
98
+ // surface an actionable message naming the offending port + the override path.
99
+ this._server.on('error', err => this.handleListenError(err, host, port));
100
+ const addressInfo = await this.getAddress();
101
+ return { url: this.toServerUrl(addressInfo, route) };
102
+ }
103
+
104
+ /**
105
+ * Translate a pre-listen failure into an actionable error and reject the address-info
106
+ * deferred so `start()` propagates it to the caller. `EADDRINUSE` gets a tailored hint
107
+ * about overriding via `mcpServer.port`; other codes pass through unchanged.
108
+ */
109
+ protected handleListenError(err: NodeJS.ErrnoException, host: string, port: number): void {
110
+ if (err.code === 'EADDRINUSE') {
111
+ const portLabel = port === 0 ? 'requested address' : `${host}:${port}`;
112
+ this._addressInfo.reject(
113
+ new Error(
114
+ `MCP server cannot bind ${portLabel}: address already in use. ` +
115
+ 'Pass a different `mcpServer.port` in the GLSP `initialize` call, or omit the port to get a random one.'
116
+ )
117
+ );
118
+ return;
119
+ }
120
+ this._addressInfo.reject(err);
121
+ }
122
+
123
+ /**
124
+ * Hook for subclasses to register middleware on the Express app before the MCP routes
125
+ * are mounted. Called once during {@link start}, after the app is created and before
126
+ * `POST` / `GET` / `DELETE` handlers are added.
127
+ *
128
+ * Default behavior: install an Origin allowlist if one is configured. Host-header
129
+ * validation is already wired by the SDK's `createMcpExpressApp` (using the same
130
+ * `allowedHosts` we forward in {@link start}); we don't duplicate it here. Subclasses
131
+ * that override SHOULD `super.configureExpressApp(app)` to keep the origin gate in place;
132
+ * pre-existing security middleware can run before or after by calling super at the
133
+ * appropriate point.
134
+ */
135
+ protected configureExpressApp(app: Express): void {
136
+ const allowedOrigins = this.serverOptions.values.allowedOrigins;
137
+ if (!allowedOrigins) {
138
+ return;
139
+ }
140
+ app.use((req, res, next) => {
141
+ const origin = req.headers.origin;
142
+ if (origin && !allowedOrigins.includes(origin)) {
143
+ res.status(403).json({ error: `Forbidden: Origin '${origin}' not allowed` });
144
+ return;
145
+ }
146
+ next();
147
+ });
148
+ }
149
+
150
+ /**
151
+ * Validate the `MCP-Protocol-Version` header per the Streamable HTTP transport spec.
152
+ * Initialize POSTs negotiate the version in the body — the header isn't expected there.
153
+ * For every other request: absent header → pass through (the spec mandates the server
154
+ * default to `2025-03-26`); present-but-unsupported → respond `400` with a JSON-RPC error
155
+ * envelope so the client knows which versions to retry with.
156
+ */
157
+ protected validateProtocolVersionHeader(req: express.Request, res: express.Response, next: express.NextFunction): void {
158
+ if (req.method === 'POST' && isInitializeRequest(req.body)) {
159
+ return next();
160
+ }
161
+ const headerValue = req.headers['mcp-protocol-version'];
162
+ const version = Array.isArray(headerValue) ? headerValue[0] : headerValue;
163
+ if (version === undefined) {
164
+ return next();
165
+ }
166
+ if (!SUPPORTED_PROTOCOL_VERSIONS.includes(version)) {
167
+ res.status(400).json({
168
+ jsonrpc: '2.0',
169
+ error: {
170
+ code: -32000,
171
+ message:
172
+ `Unsupported MCP-Protocol-Version: '${version}'. ` +
173
+ `Supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(', ')}.`
174
+ },
175
+ id: JSON_RPC_NULL_ID
176
+ });
177
+ return;
178
+ }
179
+ next();
180
+ }
181
+
182
+ protected toServerUrl({ address, family, port }: AddressInfo, route: string, protocol = 'http'): string {
183
+ const host = address === '::' || address === '0.0.0.0' ? 'localhost' : family === 'IPv6' ? `[${address}]` : address;
184
+ return `${protocol}://${host}:${port}${route}`;
185
+ }
186
+
187
+ protected listening(): void {
188
+ const addressInfo = this.server?.address();
189
+ if (!addressInfo) {
190
+ this.logger.error('Could not resolve MCP Server address info. Shutting down.');
191
+ this._server?.close();
192
+ return;
193
+ } else if (typeof addressInfo === 'string') {
194
+ this.logger.error(`MCP Server is unexpectedly listening to pipe or domain socket "${addressInfo}". Shutting down.`);
195
+ this._server?.close();
196
+ return;
197
+ }
198
+ this._addressInfo.resolve(addressInfo);
199
+ }
200
+
201
+ protected async handlePostRequest(req: express.Request, res: express.Response): Promise<void> {
202
+ const client = this.getOrCreateClient(req, res);
203
+ if (!client) {
204
+ return;
205
+ }
206
+ this.logger.debug(`Handling POST request for session ${client.sessionId}`);
207
+ try {
208
+ await client.handleRequest(req, res, req.body);
209
+ } catch (err: unknown) {
210
+ this.logger.error('Error handling MCP request:', err);
211
+ if (!res.headersSent) {
212
+ res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: 'Internal server error' }, id: JSON_RPC_NULL_ID });
213
+ }
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Handle GET requests for SSE streams (using built-in support from StreamableHTTP)
219
+ */
220
+ protected async handleGetRequest(req: express.Request, res: express.Response): Promise<void> {
221
+ const client = this.getClient(req, res);
222
+ if (!client) {
223
+ return;
224
+ }
225
+
226
+ // Check for Last-Event-ID header for resumability
227
+ const lastEventId = req.headers['last-event-id'] as string | undefined;
228
+ if (lastEventId) {
229
+ this.logger.info(`Client reconnecting with Last-Event-ID: ${lastEventId}`);
230
+ } else {
231
+ this.logger.info(`Establishing new SSE stream for session ${client.sessionId}`);
232
+ }
233
+ await client.handleRequest(req, res);
234
+ }
235
+
236
+ /**
237
+ * Handle DELETE requests for session termination (according to MCP spec).
238
+ */
239
+ protected async handleDeleteRequest(req: express.Request, res: express.Response): Promise<void> {
240
+ const client = this.getClient(req, res);
241
+ if (!client) {
242
+ return;
243
+ }
244
+
245
+ this.logger.info(`Received session termination request for session ${client.sessionId}`);
246
+ try {
247
+ // SDK transport closes the session as part of handleRequest.
248
+ await client.handleRequest(req, res);
249
+ } catch (err: unknown) {
250
+ this.logger.error('Error handling session termination:', err);
251
+ if (!res.headersSent) {
252
+ res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: 'Internal server error' }, id: JSON_RPC_NULL_ID });
253
+ }
254
+ }
255
+ }
256
+
257
+ protected getOrCreateClient(req: express.Request, res: express.Response): StreamableHTTPServerTransport | undefined {
258
+ // A brand-new session is born on an initialize POST that doesn't assert a session id.
259
+ // Every other case falls through to `getClient`, which enforces the spec-mandated
260
+ // 400/404 errors — including the case where an initialize POST carries an unknown
261
+ // session id (§ #3 — must not silently mint a replacement).
262
+ if (!getSessionIdHeader(req) && isInitializeRequest(req.body)) {
263
+ return this.createClient();
264
+ }
265
+ return this.getClient(req, res);
266
+ }
267
+
268
+ protected getClient(req: express.Request, res: express.Response): StreamableHTTPServerTransport | undefined {
269
+ const sessionId = getSessionIdHeader(req);
270
+ if (!sessionId) {
271
+ // MCP Streamable HTTP § Session Management #2: a non-initialize request without
272
+ // a session id MUST be rejected with HTTP 400.
273
+ res.status(400).json({
274
+ jsonrpc: '2.0',
275
+ error: { code: -32000, message: 'Bad Request: No valid session ID provided' },
276
+ id: JSON_RPC_NULL_ID
277
+ });
278
+ return undefined;
279
+ }
280
+ const client = this.sessions.get(sessionId);
281
+ if (!client) {
282
+ // MCP Streamable HTTP § Session Management #3: requests bearing an unknown or
283
+ // terminated session id MUST be answered with HTTP 404 so the client knows to
284
+ // re-initialize.
285
+ res.status(404).json({
286
+ jsonrpc: '2.0',
287
+ error: { code: -32001, message: 'Session not found' },
288
+ id: JSON_RPC_NULL_ID
289
+ });
290
+ return undefined;
291
+ }
292
+ return client;
293
+ }
294
+
295
+ protected createClient(): StreamableHTTPServerTransport {
296
+ const client = new StreamableHTTPServerTransport({
297
+ sessionIdGenerator: () => randomUUID(),
298
+ // Bounded LRU store so resumability via `Last-Event-ID` works without leaking
299
+ // memory in long-running deployments. Cap configurable via `eventStoreLimit`.
300
+ eventStore: new LruEventStore(this.serverOptions.values.eventStoreLimit, this.logger),
301
+ onsessioninitialized: sessionId => {
302
+ // Store the transport by session ID when session is initialized
303
+ // This avoids race conditions where requests might come in before the session is stored
304
+ this.logger.info(`Session initialized with ID: ${sessionId}`);
305
+ this.sessions.set(sessionId, client);
306
+ this.onSessionInitializedEmitter.fire(client as WithSessionId<StreamableHTTPServerTransport>);
307
+ }
308
+ });
309
+ client.onclose = () => this.closeClient(client.sessionId);
310
+ // Surface transport errors to the GLSP logger. SDK 1.27.1 routes previously-swallowed
311
+ // errors here; without an explicit handler they go undiagnosed.
312
+ client.onerror = err => this.logger.error(`MCP transport error (session ${client.sessionId ?? '<pre-init>'}):`, err);
313
+ return client;
314
+ }
315
+
316
+ protected closeClient(sessionId?: string): void {
317
+ if (!sessionId) {
318
+ return;
319
+ }
320
+ const client = this.sessions.get(sessionId);
321
+ if (client) {
322
+ this.sessions.delete(sessionId);
323
+ client.close();
324
+ this.logger.info(`Closed and removed client with session ID ${sessionId}`);
325
+ this.onSessionClosedEmitter.fire(sessionId);
326
+ }
327
+ }
328
+
329
+ dispose(): void {
330
+ // Close session transports first so their SSE responses end cleanly. `http.Server.close()`
331
+ // only stops accepting new connections — existing sockets stay open until they drain — so
332
+ // closing the server first would leave streams hanging until the per-session `client.close()`
333
+ // catches up.
334
+ // `Transport.close()` is async (returns Promise<void>) but `Disposable.dispose()` is sync,
335
+ // so we attach a catch handler to keep stray rejections out of the unhandled-rejection log.
336
+ Array.from(this.sessions.values()).forEach(client =>
337
+ client.close().catch(err => this.logger.warn(`Error closing MCP session ${client.sessionId}: ${err}`))
338
+ );
339
+ this.sessions.clear();
340
+ this._server?.close();
341
+ // Reset transient state so a subsequent `start()` call boots cleanly. Required because
342
+ // the transport is bound `inSingletonScope()` — without the reset, dispose-then-restart
343
+ // (e.g., GLSP server shutdown followed by a fresh `initializeServer`) would reuse the
344
+ // dead `_addressInfo` deferred and the closed Express app.
345
+ this._app = undefined;
346
+ this._server = undefined;
347
+ this._addressInfo = new Deferred<AddressInfo>();
348
+ this.logger.info('Server shutdown complete');
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Read the `mcp-session-id` header. Node's `IncomingHttpHeaders` types unknown headers as
354
+ * `string | string[] | undefined`; if a misbehaving client sends the header twice we pick
355
+ * the first value rather than coercing the array to `"a,b"` and silently failing the lookup.
356
+ */
357
+ function getSessionIdHeader(req: express.Request): string | undefined {
358
+ const value = req.headers['mcp-session-id'];
359
+ return Array.isArray(value) ? value[0] : value;
360
+ }
361
+
362
+ /**
363
+ * JSON-RPC 2.0 § 5 mandates `null` for error responses where the request id cannot be
364
+ * determined (e.g., parse errors, batch-level rejection, missing session id). Centralised so
365
+ * the unavoidable `null` literal lives behind one eslint exception instead of many.
366
+ */
367
+ // eslint-disable-next-line no-null/no-null
368
+ const JSON_RPC_NULL_ID = null;
@@ -0,0 +1,106 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { expect } from 'chai';
18
+ import { DefaultMcpIdAliasService, NullMcpIdAliasService } from './mcp-id-alias-service';
19
+
20
+ describe('DefaultMcpIdAliasService', () => {
21
+ it('returns the same alias on repeated calls with the same id (round-trip stability)', () => {
22
+ const service = new DefaultMcpIdAliasService();
23
+
24
+ const aliasA = service.alias('uuid-a');
25
+ const aliasA2 = service.alias('uuid-a');
26
+ const aliasB = service.alias('uuid-b');
27
+
28
+ expect(aliasA).to.equal(aliasA2);
29
+ expect(aliasA).to.not.equal(aliasB);
30
+ // Aliases are integer strings, starting at "1".
31
+ expect(aliasA).to.match(/^\d+$/);
32
+ expect(aliasB).to.match(/^\d+$/);
33
+ });
34
+
35
+ it('lookup(alias) returns the original id (round-trip)', () => {
36
+ const service = new DefaultMcpIdAliasService();
37
+
38
+ const alias = service.alias('uuid-foo');
39
+ expect(service.lookup(alias)).to.equal('uuid-foo');
40
+ });
41
+
42
+ it('lookup(unknown) returns the input verbatim (best-effort fallback)', () => {
43
+ const service = new DefaultMcpIdAliasService();
44
+
45
+ // Unknown ids may come from manual user input, copy-paste, or earlier server-side
46
+ // state. The service passes them through; downstream existence checks decide.
47
+ expect(service.lookup('never-issued')).to.equal('never-issued');
48
+ });
49
+
50
+ it('skips alias candidates that collide with a known real id (no shadowing)', () => {
51
+ // Regression: pre-fix, alias() always handed out sequential integers starting at "1".
52
+ // A model element whose actual id was "1" would then be shadowed — `lookup("1")`
53
+ // resolved to the *aliased* real id rather than passing through to the real "1".
54
+ // The service now records every real id seen via alias() and skips counter values
55
+ // that would collide.
56
+ const service = new DefaultMcpIdAliasService();
57
+ const aliasOf1 = service.alias('1');
58
+ const aliasOfX = service.alias('uuid-other');
59
+
60
+ expect(aliasOf1).to.not.equal('1');
61
+ expect(aliasOfX).to.not.equal('1');
62
+ expect(service.lookup('1')).to.equal('1');
63
+ expect(service.lookup(aliasOf1)).to.equal('1');
64
+ expect(service.lookup(aliasOfX)).to.equal('uuid-other');
65
+
66
+ // Multiple pre-known real ids: every issued alias is outside the known-real set.
67
+ const service2 = new DefaultMcpIdAliasService();
68
+ const knownReals = ['1', '2', '3'];
69
+ knownReals.forEach(id => service2.alias(id));
70
+ const fresh = service2.alias('uuid-fresh');
71
+ expect(knownReals).to.not.include(fresh);
72
+ });
73
+
74
+ it('keeps independent counters and maps across separate instances (per-session isolation)', () => {
75
+ // Adopters get one instance per GLSP session; aliases must not bleed between sessions.
76
+ const sessionA = new DefaultMcpIdAliasService();
77
+ const sessionB = new DefaultMcpIdAliasService();
78
+
79
+ const aliasA1 = sessionA.alias('uuid-x');
80
+ const aliasA2 = sessionA.alias('uuid-y');
81
+ const aliasB1 = sessionB.alias('uuid-z');
82
+
83
+ // Counters are independent: B's first alias is "1", same as A's first.
84
+ expect(aliasA1).to.equal('1');
85
+ expect(aliasA2).to.equal('2');
86
+ expect(aliasB1).to.equal('1');
87
+
88
+ // Bleed-isolation: alias "1" in B resolves to uuid-z, NOT to uuid-x (A's "1").
89
+ expect(sessionA.lookup('1')).to.equal('uuid-x');
90
+ expect(sessionB.lookup('1')).to.equal('uuid-z');
91
+
92
+ // Unknown ids in either session fall through to the input verbatim.
93
+ expect(sessionA.lookup('3')).to.equal('3');
94
+ expect(sessionB.lookup('2')).to.equal('2');
95
+ });
96
+ });
97
+
98
+ describe('NullMcpIdAliasService', () => {
99
+ it('alias and lookup return the argument unchanged', () => {
100
+ const service = new NullMcpIdAliasService();
101
+
102
+ expect(service.alias('uuid-foo')).to.equal('uuid-foo');
103
+ expect(service.lookup('uuid-foo')).to.equal('uuid-foo');
104
+ expect(service.lookup('never-seen')).to.equal('never-seen');
105
+ });
106
+ });
@@ -0,0 +1,104 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import { injectable } from 'inversify';
18
+
19
+ export const McpIdAliasService = Symbol('McpIdAliasService');
20
+
21
+ /**
22
+ * Maps real GLSP element ids to a shorter, more LLM-friendly form on the wire. Tool/resource
23
+ * handlers `alias` real ids before emitting them and `lookup` incoming aliases before passing
24
+ * them to the model.
25
+ *
26
+ * Bound per GLSP client session — alias state is shared across MCP clients connected to the
27
+ * same GLSP session (id↔alias round-tripping must be consistent across clients). Adopters
28
+ * who want raw ids on the wire bind {@link NullMcpIdAliasService} via
29
+ * {@link DefaultMcpDiagramModule.bindIdAliasService}.
30
+ *
31
+ * @experimental
32
+ */
33
+ export interface McpIdAliasService {
34
+ /**
35
+ * Returns the alias for the given real id, allocating one on first call. Stable across
36
+ * subsequent calls within the same session.
37
+ */
38
+ alias(realId: string): string;
39
+ /**
40
+ * Resolves an alias back to its real id. Falls back to the input verbatim when no mapping
41
+ * exists, so callers can pass either an alias or a real id without branching: aliased ids
42
+ * round-trip; real ids (manual user input, copy-paste, ids surfaced from earlier
43
+ * server-side state) pass through. Downstream existence checks
44
+ * (`modelState.index.find`, the operation handler) decide validity.
45
+ */
46
+ lookup(aliasOrRealId: string): string;
47
+ }
48
+
49
+ /**
50
+ * Default {@link McpIdAliasService} — sequential integer aliases per session.
51
+ *
52
+ * Collision avoidance: every real id passed to {@link alias} is also recorded in a known-real
53
+ * set. When minting, candidate alias strings that collide with a known real id are skipped, so
54
+ * a model element whose actual id is e.g. `"1"` cannot be shadowed by an alias mapped to a
55
+ * different real id. This is conditional on the existing convention that every real id
56
+ * surfaced to the LLM flows through `alias()` at least once before the LLM can refer to it —
57
+ * adopter-written handlers that bypass `alias()` re-open the corner case.
58
+ */
59
+ @injectable()
60
+ export class DefaultMcpIdAliasService implements McpIdAliasService {
61
+ protected idToAlias = new Map<string, string>();
62
+ protected aliasToId = new Map<string, string>();
63
+ protected realIds = new Set<string>();
64
+ protected counter = 1;
65
+
66
+ alias(realId: string): string {
67
+ this.realIds.add(realId);
68
+ const existingAlias = this.idToAlias.get(realId);
69
+ if (existingAlias) {
70
+ return existingAlias;
71
+ }
72
+
73
+ let candidate = this.counter.toString();
74
+ while (this.realIds.has(candidate)) {
75
+ this.counter += 1;
76
+ candidate = this.counter.toString();
77
+ }
78
+ this.counter += 1;
79
+
80
+ this.idToAlias.set(realId, candidate);
81
+ this.aliasToId.set(candidate, realId);
82
+
83
+ return candidate;
84
+ }
85
+
86
+ lookup(aliasOrRealId: string): string {
87
+ return this.aliasToId.get(aliasOrRealId) ?? aliasOrRealId;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Null-object {@link McpIdAliasService} — passes ids through unchanged. Bind this in
93
+ * {@link DefaultMcpDiagramModule.bindIdAliasService} to expose raw GLSP ids on the wire.
94
+ */
95
+ @injectable()
96
+ export class NullMcpIdAliasService implements McpIdAliasService {
97
+ alias(realId: string): string {
98
+ return realId;
99
+ }
100
+
101
+ lookup(aliasOrRealId: string): string {
102
+ return aliasOrRealId;
103
+ }
104
+ }
@@ -0,0 +1,82 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2026 EclipseSource and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ import * as z from 'zod/v4';
18
+
19
+ /**
20
+ * Common Zod input-schema fragments shared across MCP tool / resource / prompt handlers.
21
+ * Adopters compose these via `z.object({ ... })` or `McpDiagramScopedInputSchema.extend(...)`
22
+ * — Zod's modifiers (`.describe`, `.optional`, `.min`, ...) return new schemas without mutating
23
+ * the exports, so the shared fragments can be safely adapted at the call site.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { McpDiagramScopedInputSchema, elementIds } from '@eclipse-glsp/server-mcp';
28
+ *
29
+ * // Use as-is — the tool's `description` field already conveys the action context:
30
+ * const inputSchema = McpDiagramScopedInputSchema.extend({ elementIds });
31
+ *
32
+ * // Override `describe` only when there's genuinely new info (defaults, conditional applicability):
33
+ * const inputSchema = McpDiagramScopedInputSchema.extend({
34
+ * elementIds: elementIds.optional().describe('If not provided, validates entire model.')
35
+ * });
36
+ * ```
37
+ */
38
+
39
+ /** GLSP client session id (open diagram). Resolved by the launcher dispatcher via `ClientSessionManager`. */
40
+ export const sessionId = z.string().describe('GLSP client session id (open diagram).');
41
+
42
+ /** Single element id — alias or real; handlers translate via `resolveIds` on the diagram base. */
43
+ export const elementId = z.string();
44
+
45
+ /** One or more element ids. Empty arrays are rejected. */
46
+ export const elementIds = z.array(z.string()).min(1);
47
+
48
+ /** Cartesian position used by node-creation / -modification tools. */
49
+ export const position = z
50
+ .object({
51
+ x: z.number().describe('X coordinate in diagram space'),
52
+ y: z.number().describe('Y coordinate in diagram space')
53
+ })
54
+ .strict();
55
+
56
+ /**
57
+ * Base schema for diagram-scope tool / prompt / resource-tool-alternative input. Adopter
58
+ * schemas extend this via {@link z.ZodObject.extend} and add their tool-specific fields.
59
+ */
60
+ export const McpDiagramScopedInputSchema = z.object({ sessionId });
61
+
62
+ /**
63
+ * Compact identity echoed by mutating tools (create / modify / delete) so the LLM has enough
64
+ * context to refer to the element by label or type in user-facing prose without a follow-up
65
+ * `query-elements`. The `id` is the alias.
66
+ */
67
+ export const ElementIdentitySchema = z.object({
68
+ id: z.string().describe('Aliased element id.'),
69
+ elementTypeId: z.string().describe('Element type id (e.g. `node:foo`, `edge`).'),
70
+ label: z.string().optional().describe('Primary label text, when the element has one.')
71
+ });
72
+
73
+ /** Inferred shape of {@link ElementIdentitySchema} — see its docstring for usage. */
74
+ export type ElementIdentity = z.infer<typeof ElementIdentitySchema>;
75
+
76
+ /**
77
+ * Inferred shape of {@link McpDiagramScopedInputSchema} — `{ sessionId: string }`. Any
78
+ * adopter input schema that extends `McpDiagramScopedInputSchema` infers a type structurally
79
+ * assignable to this; used as the upper bound on diagram-scope handler generics
80
+ * (`<T extends McpDiagramScopedInput = McpDiagramScopedInput>`).
81
+ */
82
+ export type McpDiagramScopedInput = z.infer<typeof McpDiagramScopedInputSchema>;