@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.
- package/LICENSE +642 -0
- package/README.md +57 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +41 -0
- package/lib/index.js.map +1 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.d.ts +43 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.d.ts.map +1 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.js +96 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.js.map +1 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.d.ts +43 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.d.ts.map +1 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.js +95 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.js.map +1 -0
- package/lib/prompts/index.d.ts +18 -0
- package/lib/prompts/index.d.ts.map +1 -0
- package/lib/prompts/index.js +34 -0
- package/lib/prompts/index.js.map +1 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.d.ts +81 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.d.ts.map +1 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.js +174 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.js.map +1 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.d.ts +52 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.d.ts.map +1 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.js +96 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.js.map +1 -0
- package/lib/resources/index.d.ts +20 -0
- package/lib/resources/index.d.ts.map +1 -0
- package/lib/resources/index.js +36 -0
- package/lib/resources/index.js.map +1 -0
- package/lib/resources/services/element-types-provider.d.ts +65 -0
- package/lib/resources/services/element-types-provider.d.ts.map +1 -0
- package/lib/resources/services/element-types-provider.js +81 -0
- package/lib/resources/services/element-types-provider.js.map +1 -0
- package/lib/resources/services/mcp-model-serializer.d.ts +78 -0
- package/lib/resources/services/mcp-model-serializer.d.ts.map +1 -0
- package/lib/resources/services/mcp-model-serializer.js +188 -0
- package/lib/resources/services/mcp-model-serializer.js.map +1 -0
- package/lib/server/glsp-mcp-server.d.ts +82 -0
- package/lib/server/glsp-mcp-server.d.ts.map +1 -0
- package/lib/server/glsp-mcp-server.js +140 -0
- package/lib/server/glsp-mcp-server.js.map +1 -0
- package/lib/server/index.d.ts +37 -0
- package/lib/server/index.d.ts.map +1 -0
- package/lib/server/index.js +57 -0
- package/lib/server/index.js.map +1 -0
- package/lib/server/lru-event-store.d.ts +53 -0
- package/lib/server/lru-event-store.d.ts.map +1 -0
- package/lib/server/lru-event-store.js +100 -0
- package/lib/server/lru-event-store.js.map +1 -0
- package/lib/server/mcp-diagram-handler-dispatcher.d.ts +144 -0
- package/lib/server/mcp-diagram-handler-dispatcher.d.ts.map +1 -0
- package/lib/server/mcp-diagram-handler-dispatcher.js +382 -0
- package/lib/server/mcp-diagram-handler-dispatcher.js.map +1 -0
- package/lib/server/mcp-diagram-module.d.ts +123 -0
- package/lib/server/mcp-diagram-module.d.ts.map +1 -0
- package/lib/server/mcp-diagram-module.js +186 -0
- package/lib/server/mcp-diagram-module.js.map +1 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.d.ts +33 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.d.ts.map +1 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.js +76 -0
- package/lib/server/mcp-diagram-prompt-handler-registry.js.map +1 -0
- package/lib/server/mcp-diagram-resource-handler-registry.d.ts +35 -0
- package/lib/server/mcp-diagram-resource-handler-registry.d.ts.map +1 -0
- package/lib/server/mcp-diagram-resource-handler-registry.js +94 -0
- package/lib/server/mcp-diagram-resource-handler-registry.js.map +1 -0
- package/lib/server/mcp-diagram-tool-handler-registry.d.ts +57 -0
- package/lib/server/mcp-diagram-tool-handler-registry.d.ts.map +1 -0
- package/lib/server/mcp-diagram-tool-handler-registry.js +111 -0
- package/lib/server/mcp-diagram-tool-handler-registry.js.map +1 -0
- package/lib/server/mcp-handler-shared.d.ts +142 -0
- package/lib/server/mcp-handler-shared.d.ts.map +1 -0
- package/lib/server/mcp-handler-shared.js +199 -0
- package/lib/server/mcp-handler-shared.js.map +1 -0
- package/lib/server/mcp-http-transport.d.ts +93 -0
- package/lib/server/mcp-http-transport.d.ts.map +1 -0
- package/lib/server/mcp-http-transport.js +350 -0
- package/lib/server/mcp-http-transport.js.map +1 -0
- package/lib/server/mcp-id-alias-service.d.ts +70 -0
- package/lib/server/mcp-id-alias-service.d.ts.map +1 -0
- package/lib/server/mcp-id-alias-service.js +85 -0
- package/lib/server/mcp-id-alias-service.js.map +1 -0
- package/lib/server/mcp-input-schemas.d.ts +73 -0
- package/lib/server/mcp-input-schemas.d.ts.map +1 -0
- package/lib/server/mcp-input-schemas.js +67 -0
- package/lib/server/mcp-input-schemas.js.map +1 -0
- package/lib/server/mcp-label-provider.d.ts +45 -0
- package/lib/server/mcp-label-provider.d.ts.map +1 -0
- package/lib/server/mcp-label-provider.js +42 -0
- package/lib/server/mcp-label-provider.js.map +1 -0
- package/lib/server/mcp-log-level-registry.d.ts +54 -0
- package/lib/server/mcp-log-level-registry.d.ts.map +1 -0
- package/lib/server/mcp-log-level-registry.js +80 -0
- package/lib/server/mcp-log-level-registry.js.map +1 -0
- package/lib/server/mcp-logger.d.ts +59 -0
- package/lib/server/mcp-logger.d.ts.map +1 -0
- package/lib/server/mcp-logger.js +104 -0
- package/lib/server/mcp-logger.js.map +1 -0
- package/lib/server/mcp-mime-types.d.ts +28 -0
- package/lib/server/mcp-mime-types.d.ts.map +1 -0
- package/lib/server/mcp-mime-types.js +18 -0
- package/lib/server/mcp-mime-types.js.map +1 -0
- package/lib/server/mcp-options.d.ts +39 -0
- package/lib/server/mcp-options.d.ts.map +1 -0
- package/lib/server/mcp-options.js +53 -0
- package/lib/server/mcp-options.js.map +1 -0
- package/lib/server/mcp-progress-reporter.d.ts +48 -0
- package/lib/server/mcp-progress-reporter.d.ts.map +1 -0
- package/lib/server/mcp-progress-reporter.js +66 -0
- package/lib/server/mcp-progress-reporter.js.map +1 -0
- package/lib/server/mcp-prompt-handler.d.ts +120 -0
- package/lib/server/mcp-prompt-handler.d.ts.map +1 -0
- package/lib/server/mcp-prompt-handler.js +131 -0
- package/lib/server/mcp-prompt-handler.js.map +1 -0
- package/lib/server/mcp-request-context.d.ts +37 -0
- package/lib/server/mcp-request-context.d.ts.map +1 -0
- package/lib/server/mcp-request-context.js +37 -0
- package/lib/server/mcp-request-context.js.map +1 -0
- package/lib/server/mcp-resource-handler.d.ts +212 -0
- package/lib/server/mcp-resource-handler.d.ts.map +1 -0
- package/lib/server/mcp-resource-handler.js +298 -0
- package/lib/server/mcp-resource-handler.js.map +1 -0
- package/lib/server/mcp-server-launcher.d.ts +143 -0
- package/lib/server/mcp-server-launcher.d.ts.map +1 -0
- package/lib/server/mcp-server-launcher.js +355 -0
- package/lib/server/mcp-server-launcher.js.map +1 -0
- package/lib/server/mcp-server-module.d.ts +143 -0
- package/lib/server/mcp-server-module.d.ts.map +1 -0
- package/lib/server/mcp-server-module.js +249 -0
- package/lib/server/mcp-server-module.js.map +1 -0
- package/lib/server/mcp-session.d.ts +44 -0
- package/lib/server/mcp-session.d.ts.map +1 -0
- package/lib/server/mcp-session.js +18 -0
- package/lib/server/mcp-session.js.map +1 -0
- package/lib/server/mcp-tool-handler.d.ts +259 -0
- package/lib/server/mcp-tool-handler.d.ts.map +1 -0
- package/lib/server/mcp-tool-handler.js +355 -0
- package/lib/server/mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.d.ts +46 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.js +76 -0
- package/lib/tools/handlers/count-elements-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.d.ts +112 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.js +190 -0
- package/lib/tools/handlers/create-edges-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.d.ts +81 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.js +123 -0
- package/lib/tools/handlers/create-nodes-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.d.ts +52 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.js +73 -0
- package/lib/tools/handlers/delete-elements-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.d.ts +59 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.js +78 -0
- package/lib/tools/handlers/diagram-model-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.d.ts +97 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.js +155 -0
- package/lib/tools/handlers/element-types-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.d.ts +43 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.js +68 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.d.ts +43 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.js +71 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.d.ts +78 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.js +136 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.d.ts +92 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.js +125 -0
- package/lib/tools/handlers/modify-nodes-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.d.ts +102 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.js +158 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.d.ts +45 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.js +73 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.d.ts +55 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.js +91 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.d.ts +65 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.js +108 -0
- package/lib/tools/handlers/session-info-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.d.ts +60 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.js +103 -0
- package/lib/tools/handlers/set-selection-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.d.ts +110 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.js +142 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.d.ts +45 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.js +74 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.d.ts +66 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.js +0 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.js.map +1 -0
- package/lib/tools/index.d.ts +34 -0
- package/lib/tools/index.d.ts.map +1 -0
- package/lib/tools/index.js +50 -0
- package/lib/tools/index.js.map +1 -0
- package/lib/util/index.d.ts +18 -0
- package/lib/util/index.d.ts.map +1 -0
- package/lib/util/index.js +34 -0
- package/lib/util/index.js.map +1 -0
- package/lib/util/markdown-util.d.ts +20 -0
- package/lib/util/markdown-util.d.ts.map +1 -0
- package/lib/util/markdown-util.js +45 -0
- package/lib/util/markdown-util.js.map +1 -0
- package/lib/util/mcp-util.d.ts +22 -0
- package/lib/util/mcp-util.d.ts.map +1 -0
- package/lib/util/mcp-util.js +29 -0
- package/lib/util/mcp-util.js.map +1 -0
- package/package.json +63 -0
- package/src/index.ts +24 -0
- package/src/prompts/handlers/describe-diagram-mcp-prompt-handler.ts +89 -0
- package/src/prompts/handlers/suggest-improvements-mcp-prompt-handler.ts +86 -0
- package/src/prompts/index.ts +18 -0
- package/src/resources/handlers/diagram-png-mcp-resource-handler.ts +181 -0
- package/src/resources/handlers/diagram-svg-mcp-resource-handler.ts +89 -0
- package/src/resources/index.ts +20 -0
- package/src/resources/services/element-types-provider.ts +105 -0
- package/src/resources/services/mcp-model-serializer.ts +211 -0
- package/src/server/glsp-mcp-server.spec.ts +73 -0
- package/src/server/glsp-mcp-server.ts +196 -0
- package/src/server/index.ts +42 -0
- package/src/server/lru-event-store.spec.ts +121 -0
- package/src/server/lru-event-store.ts +112 -0
- package/src/server/mcp-diagram-handler-dispatcher.spec.ts +231 -0
- package/src/server/mcp-diagram-handler-dispatcher.ts +459 -0
- package/src/server/mcp-diagram-module.ts +248 -0
- package/src/server/mcp-diagram-prompt-handler-registry.ts +59 -0
- package/src/server/mcp-diagram-resource-handler-registry.ts +73 -0
- package/src/server/mcp-diagram-tool-handler-registry.ts +97 -0
- package/src/server/mcp-handler-shared.spec.ts +53 -0
- package/src/server/mcp-handler-shared.ts +247 -0
- package/src/server/mcp-http-transport-e2e.spec.ts +151 -0
- package/src/server/mcp-http-transport.spec.ts +385 -0
- package/src/server/mcp-http-transport.ts +368 -0
- package/src/server/mcp-id-alias-service.spec.ts +106 -0
- package/src/server/mcp-id-alias-service.ts +104 -0
- package/src/server/mcp-input-schemas.ts +82 -0
- package/src/server/mcp-label-provider.ts +52 -0
- package/src/server/mcp-log-level-registry.spec.ts +75 -0
- package/src/server/mcp-log-level-registry.ts +90 -0
- package/src/server/mcp-logger.spec.ts +227 -0
- package/src/server/mcp-logger.ts +91 -0
- package/src/server/mcp-mime-types.ts +31 -0
- package/src/server/mcp-options.ts +43 -0
- package/src/server/mcp-progress-reporter.spec.ts +93 -0
- package/src/server/mcp-progress-reporter.ts +67 -0
- package/src/server/mcp-prompt-handler.ts +157 -0
- package/src/server/mcp-request-context.ts +39 -0
- package/src/server/mcp-resource-handler.ts +389 -0
- package/src/server/mcp-server-launcher.spec.ts +173 -0
- package/src/server/mcp-server-launcher.ts +369 -0
- package/src/server/mcp-server-module.ts +287 -0
- package/src/server/mcp-session.ts +45 -0
- package/src/server/mcp-tool-handler.spec.ts +182 -0
- package/src/server/mcp-tool-handler.ts +431 -0
- package/src/server/raw-http.spec.ts +59 -0
- package/src/tools/handlers/count-elements-mcp-tool-handler.spec.ts +99 -0
- package/src/tools/handlers/count-elements-mcp-tool-handler.ts +66 -0
- package/src/tools/handlers/create-edges-mcp-tool-handler.spec.ts +196 -0
- package/src/tools/handlers/create-edges-mcp-tool-handler.ts +205 -0
- package/src/tools/handlers/create-nodes-mcp-tool-handler.spec.ts +197 -0
- package/src/tools/handlers/create-nodes-mcp-tool-handler.ts +131 -0
- package/src/tools/handlers/delete-elements-mcp-tool-handler.ts +73 -0
- package/src/tools/handlers/diagram-model-mcp-tool-handler.ts +66 -0
- package/src/tools/handlers/element-types-mcp-tool-handler.ts +151 -0
- package/src/tools/handlers/get-selection-mcp-tool-handler.ts +54 -0
- package/src/tools/handlers/layout-mcp-tool-handler.ts +56 -0
- package/src/tools/handlers/modify-edges-mcp-tool-handler.ts +148 -0
- package/src/tools/handlers/modify-nodes-mcp-tool-handler.ts +140 -0
- package/src/tools/handlers/query-elements-mcp-tool-handler.spec.ts +210 -0
- package/src/tools/handlers/query-elements-mcp-tool-handler.ts +161 -0
- package/src/tools/handlers/redo-mcp-tool-handler.ts +62 -0
- package/src/tools/handlers/save-model-mcp-tool-handler.ts +71 -0
- package/src/tools/handlers/session-info-mcp-tool-handler.spec.ts +152 -0
- package/src/tools/handlers/session-info-mcp-tool-handler.ts +97 -0
- package/src/tools/handlers/set-selection-mcp-tool-handler.spec.ts +118 -0
- package/src/tools/handlers/set-selection-mcp-tool-handler.ts +90 -0
- package/src/tools/handlers/set-view-mcp-tool-handler.ts +162 -0
- package/src/tools/handlers/undo-mcp-tool-handler.ts +61 -0
- package/src/tools/handlers/validate-diagram-mcp-tool-handler.ts +0 -0
- package/src/tools/index.ts +34 -0
- package/src/tools/tool-annotations.spec.ts +141 -0
- package/src/util/index.ts +18 -0
- package/src/util/markdown-util.ts +44 -0
- package/src/util/mcp-util.ts +25 -0
|
@@ -0,0 +1,369 @@
|
|
|
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 {
|
|
18
|
+
ClientSessionListener,
|
|
19
|
+
ClientSessionManager,
|
|
20
|
+
Disposable,
|
|
21
|
+
DisposableCollection,
|
|
22
|
+
GLSPServer,
|
|
23
|
+
GLSPServerInitializer,
|
|
24
|
+
GLSPServerListener,
|
|
25
|
+
InitializeParameters,
|
|
26
|
+
InitializeResult,
|
|
27
|
+
Logger,
|
|
28
|
+
McpInitializeParameters,
|
|
29
|
+
McpInitializeResult,
|
|
30
|
+
McpServerConfiguration,
|
|
31
|
+
McpServerInitOptions
|
|
32
|
+
} from '@eclipse-glsp/server';
|
|
33
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
34
|
+
import { ServerCapabilities, SetLevelRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
35
|
+
import { inject, injectable, multiInject, optional } from 'inversify';
|
|
36
|
+
import { version as packageVersion } from '../../package.json';
|
|
37
|
+
import { GLSPMcpServer, GLSPMcpServerFactory } from './glsp-mcp-server';
|
|
38
|
+
import { McpDiagramHandlerDispatcher } from './mcp-diagram-handler-dispatcher';
|
|
39
|
+
import { McpHttpTransport } from './mcp-http-transport';
|
|
40
|
+
import { McpLogLevelRegistry } from './mcp-log-level-registry';
|
|
41
|
+
import { McpServerDefaults, McpServerOptions } from './mcp-options';
|
|
42
|
+
import { McpPromptHandler } from './mcp-prompt-handler';
|
|
43
|
+
import { McpResourceHandler } from './mcp-resource-handler';
|
|
44
|
+
import { McpSession } from './mcp-session';
|
|
45
|
+
import { McpToolHandler } from './mcp-tool-handler';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Stdout tag used to announce the started MCP server so IDE integrations can pick up the URL
|
|
49
|
+
* automatically. The full line is `MCP_SERVER_READY_MSG + JSON.stringify({name, url, route})`,
|
|
50
|
+
* mirroring how the GLSP server itself announces its port via `START_UP_COMPLETE_MSG`.
|
|
51
|
+
*/
|
|
52
|
+
export const MCP_SERVER_READY_MSG = '[GLSP-MCP-Server]:Ready. ';
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Server version reported in MCP `initialize` handshake responses (the SDK's `serverInfo.version`
|
|
56
|
+
* field). Sourced from the package's own `package.json` so adopters and clients can tell builds
|
|
57
|
+
* apart without the server author having to remember to bump a literal.
|
|
58
|
+
*/
|
|
59
|
+
export const SERVER_VERSION: string = packageVersion;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Launcher's internal handoff shape: everything from the public {@link McpServerConfiguration}
|
|
63
|
+
* with all fields resolved, plus `host`. `host` is deliberately *not* in the public protocol's
|
|
64
|
+
* init schema — it lives on `McpServerDeployOptions` (deploy-only) rather than
|
|
65
|
+
* `McpServerInitOptions` (init-controllable). The launcher reads it from the adopter-supplied
|
|
66
|
+
* defaults via `McpServerOptions.values.host` (whose ship default lives in
|
|
67
|
+
* `DefaultMcpServerModule.DEFAULT_OPTIONS`). The init/deploy split limits blast radius:
|
|
68
|
+
* MCP clients can negotiate behavioral fields like `port` over the wire, but security-sensitive
|
|
69
|
+
* fields like the bind interface are settable only by the adopter at process start.
|
|
70
|
+
*/
|
|
71
|
+
export type FullMcpServerConfiguration = Required<McpServerConfiguration> & { host: string };
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Defense-in-depth filter for the init-side options payload. The static type already rules
|
|
75
|
+
* out deploy-only fields (`host`, `allowedHosts`, `allowedOrigins`, `acknowledgedNoAuth`) on
|
|
76
|
+
* `McpServerConfiguration.options`, but the wire payload is JSON, so a malformed or
|
|
77
|
+
* malicious client could smuggle extra keys. Destructure-based pick drops anything outside
|
|
78
|
+
* the allowed set so deploy-only fields are sourced *only* from adopter defaults.
|
|
79
|
+
*
|
|
80
|
+
* **Update this allowlist when adding a field to `McpServerInitOptions`** — the destructure
|
|
81
|
+
* below is the single source of truth for which init-side fields cross the wire.
|
|
82
|
+
*
|
|
83
|
+
* Exported for regression-test access only; not part of the public package surface.
|
|
84
|
+
*/
|
|
85
|
+
export function pickInitOptions(options: McpServerInitOptions): McpServerInitOptions {
|
|
86
|
+
const { dataMode, agentPersona, eventStoreLimit } = options;
|
|
87
|
+
const picked: McpServerInitOptions = {};
|
|
88
|
+
if (dataMode !== undefined) picked.dataMode = dataMode;
|
|
89
|
+
if (agentPersona !== undefined) picked.agentPersona = agentPersona;
|
|
90
|
+
if (eventStoreLimit !== undefined) picked.eventStoreLimit = eventStoreLimit;
|
|
91
|
+
return picked;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns true iff `host` is a loopback bind: `localhost`, `::1`, or any IPv4 in
|
|
96
|
+
* `127.0.0.0/8`. Any other value (`0.0.0.0`, `::`, LAN/public addresses) is non-loopback.
|
|
97
|
+
* Used by {@link assertLoopbackOrAcknowledged} for the auth-footgun runtime check.
|
|
98
|
+
*/
|
|
99
|
+
export function isLoopbackHost(host: string): boolean {
|
|
100
|
+
return host === 'localhost' || host === '::1' || /^127\./.test(host);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Refuse to bind on a non-loopback host unless the operator has acknowledged that traffic is
|
|
105
|
+
* authenticated externally (reverse proxy, mTLS, ACL). The MCP server has no built-in auth.
|
|
106
|
+
* Exported for regression tests only; not part of the public surface.
|
|
107
|
+
*/
|
|
108
|
+
export function assertLoopbackOrAcknowledged(host: string, acknowledgedNoAuth: boolean | undefined): void {
|
|
109
|
+
if (isLoopbackHost(host) || acknowledgedNoAuth === true) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Refusing to bind MCP server to non-loopback host '${host}' without authentication. ` +
|
|
114
|
+
'The MCP server has no built-in auth; binding to a non-loopback interface exposes an ' +
|
|
115
|
+
'unauthenticated MCP endpoint to the network. If this is intentional (e.g., the endpoint ' +
|
|
116
|
+
'is fronted by a reverse proxy, mTLS, or a network ACL that authenticates traffic), set ' +
|
|
117
|
+
'`acknowledgedNoAuth: true` on the McpServerDefaults you pass to the server module.'
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Boots the embedded MCP HTTP server when a GLSP `initialize` call carries an `mcpServer`
|
|
123
|
+
* configuration. Runs in-process via the {@link GLSPServerInitializer} lifecycle — not a
|
|
124
|
+
* separate process runner. Diagram-scope handler discovery and dispatch are delegated to
|
|
125
|
+
* {@link McpDiagramHandlerDispatcher}.
|
|
126
|
+
*/
|
|
127
|
+
@injectable()
|
|
128
|
+
export class McpServerLauncher implements GLSPServerInitializer, GLSPServerListener, Disposable {
|
|
129
|
+
@inject(Logger) protected logger: Logger;
|
|
130
|
+
|
|
131
|
+
@inject(McpServerOptions) protected mcpOptions: McpServerOptions;
|
|
132
|
+
|
|
133
|
+
@inject(McpServerDefaults) protected mcpDefaults: McpServerDefaults;
|
|
134
|
+
|
|
135
|
+
@inject(McpHttpTransport) protected transport: McpHttpTransport;
|
|
136
|
+
|
|
137
|
+
@inject(GLSPMcpServerFactory) protected glspMcpServerFactory: GLSPMcpServerFactory;
|
|
138
|
+
|
|
139
|
+
@inject(McpDiagramHandlerDispatcher) protected dispatcher: McpDiagramHandlerDispatcher;
|
|
140
|
+
|
|
141
|
+
@inject(McpLogLevelRegistry) protected logLevelRegistry: McpLogLevelRegistry;
|
|
142
|
+
|
|
143
|
+
@inject(ClientSessionManager) protected clientSessionManager: ClientSessionManager;
|
|
144
|
+
|
|
145
|
+
@multiInject(McpToolHandler) @optional() protected toolHandlers: McpToolHandler[] = [];
|
|
146
|
+
|
|
147
|
+
@multiInject(McpResourceHandler) @optional() protected resourceHandlers: McpResourceHandler[] = [];
|
|
148
|
+
|
|
149
|
+
@multiInject(McpPromptHandler) @optional() protected promptHandlers: McpPromptHandler[] = [];
|
|
150
|
+
|
|
151
|
+
protected toDispose = new DisposableCollection();
|
|
152
|
+
protected serverUrl: string | undefined;
|
|
153
|
+
protected serverConfig: FullMcpServerConfiguration | undefined;
|
|
154
|
+
|
|
155
|
+
/** Per-MCP-session GLSPMcpServer registry — populated on session-init, cleared on session-close. */
|
|
156
|
+
protected readonly sessionServers = new Map<string, GLSPMcpServer>();
|
|
157
|
+
|
|
158
|
+
async initializeServer(server: GLSPServer, params: InitializeParameters, result: InitializeResult): Promise<InitializeResult> {
|
|
159
|
+
const mcpServerParam = McpInitializeParameters.getServerConfig(params);
|
|
160
|
+
if (!mcpServerParam) {
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Idempotent: subsequent client sessions of the same GLSP server reuse the existing
|
|
165
|
+
// MCP HTTP server. Only the first call starts it.
|
|
166
|
+
if (this.serverUrl && this.serverConfig) {
|
|
167
|
+
return McpInitializeResult.attachServer(result, { name: this.serverConfig.name, url: this.serverUrl });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Port defaults to 0 (random); the resolved URL is announced via the stdout marker
|
|
171
|
+
// below. `host` is intentionally NOT in the init-time schema — it comes from the
|
|
172
|
+
// server module's adopter defaults (no DNS-rebinding foot-gun via the LLM path).
|
|
173
|
+
const { port = 0, route = '/mcp', name = 'glsp', options = {} } = mcpServerParam;
|
|
174
|
+
// Init-time options win per field, but only fields in the init allowlist —
|
|
175
|
+
// `pickInitOptions` strips any wire-smuggled deploy-only keys before merge.
|
|
176
|
+
const mergedOptions = { ...this.mcpDefaults, ...pickInitOptions(options) };
|
|
177
|
+
this.mcpOptions.values = mergedOptions;
|
|
178
|
+
const host = mergedOptions.host ?? '127.0.0.1';
|
|
179
|
+
// Auth-footgun guard: refuse non-loopback bind unless the operator opted in via
|
|
180
|
+
// `acknowledgedNoAuth`. Runs BEFORE the transport binds the socket so a careless
|
|
181
|
+
// `host: '0.0.0.0'` doesn't get a chance to expose an unauthenticated endpoint.
|
|
182
|
+
assertLoopbackOrAcknowledged(host, mergedOptions.acknowledgedNoAuth);
|
|
183
|
+
const mcpServerConfig: FullMcpServerConfiguration = { port, host, route, name, options: mergedOptions };
|
|
184
|
+
|
|
185
|
+
this.dispatcher.harvest();
|
|
186
|
+
|
|
187
|
+
// Capture the per-init subscription disposables so a dispose-then-restart cycle
|
|
188
|
+
// (transport is `inSingletonScope()`) doesn't accumulate stale listeners.
|
|
189
|
+
this.toDispose.push(this.transport.onSessionInitialized(client => this.onSessionInitialized(client, mcpServerConfig)));
|
|
190
|
+
this.toDispose.push(this.transport.onSessionClosed(sessionId => this.onSessionClosed(sessionId)));
|
|
191
|
+
this.toDispose.push(this.transport);
|
|
192
|
+
this.installResourceListChangedNotifier();
|
|
193
|
+
|
|
194
|
+
const endpoint = await this.transport.start(mcpServerConfig);
|
|
195
|
+
this.serverUrl = endpoint.url;
|
|
196
|
+
this.serverConfig = mcpServerConfig;
|
|
197
|
+
this.logger.info(
|
|
198
|
+
`MCP server '${mcpServerConfig.name}' is ready to accept new client requests on: ${this.serverUrl ?? '(no network endpoint)'}`
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// stdout ready-marker for parent processes to discover the URL. Uses `console.log`
|
|
202
|
+
// (not the GLSP logger) so adopter logger config can never hide it.
|
|
203
|
+
console.log(MCP_SERVER_READY_MSG + JSON.stringify({ name: mcpServerConfig.name, url: this.serverUrl, route }));
|
|
204
|
+
if (endpoint.url) {
|
|
205
|
+
return McpInitializeResult.attachServer(result, {
|
|
206
|
+
name: mcpServerConfig.name,
|
|
207
|
+
url: endpoint.url,
|
|
208
|
+
headers: endpoint.headers
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
protected onSessionInitialized(client: McpSession, config: FullMcpServerConfiguration): void {
|
|
215
|
+
this.logger.info(`MCP session initialized with ID: ${client.sessionId}`);
|
|
216
|
+
const glspMcpServer = this.createGlspMcpServer(config);
|
|
217
|
+
this.sessionServers.set(client.sessionId, glspMcpServer);
|
|
218
|
+
this.registerLogLevelHandler(glspMcpServer, client.sessionId);
|
|
219
|
+
// server assumes control of the connection
|
|
220
|
+
glspMcpServer.connect(client);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
protected onSessionClosed(sessionId: string): void {
|
|
224
|
+
const glspMcpServer = this.sessionServers.get(sessionId);
|
|
225
|
+
if (glspMcpServer) {
|
|
226
|
+
this.sessionServers.delete(sessionId);
|
|
227
|
+
this.logLevelRegistry.clear(sessionId);
|
|
228
|
+
// The transport already closes the client end; close the SDK server end too.
|
|
229
|
+
glspMcpServer.dispose();
|
|
230
|
+
this.logger.info(`MCP session closed: ${sessionId}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Fire `notifications/resources/list_changed` to every connected MCP client when a GLSP
|
|
236
|
+
* session opens or closes — diagram-scope resources aggregate across GLSP sessions, so the
|
|
237
|
+
* visible list mutates with that lifecycle. No-op when no diagram-scope resources are bound.
|
|
238
|
+
*/
|
|
239
|
+
protected installResourceListChangedNotifier(): void {
|
|
240
|
+
if (!this.dispatcher.hasDiagramResources()) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const listener: ClientSessionListener = {
|
|
244
|
+
sessionCreated: () => this.broadcastResourceListChanged(),
|
|
245
|
+
sessionDisposed: () => this.broadcastResourceListChanged()
|
|
246
|
+
};
|
|
247
|
+
this.clientSessionManager.addListener(listener);
|
|
248
|
+
this.toDispose.push(Disposable.create(() => this.clientSessionManager.removeListener(listener)));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Best-effort fan-out — failures on individual MCP sessions (e.g. transport mid-close) are swallowed. */
|
|
252
|
+
protected broadcastResourceListChanged(): void {
|
|
253
|
+
for (const glspMcpServer of this.sessionServers.values()) {
|
|
254
|
+
glspMcpServer
|
|
255
|
+
.getRawServer()
|
|
256
|
+
.server.sendResourceListChanged()
|
|
257
|
+
.catch(err => this.logger.debug('sendResourceListChanged failed:', err));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Register `logging/setLevel` so a connected MCP client can adjust its message severity threshold. */
|
|
262
|
+
protected registerLogLevelHandler(glspMcpServer: GLSPMcpServer, sessionId: string): void {
|
|
263
|
+
glspMcpServer.getRawServer().server.setRequestHandler(SetLevelRequestSchema, async request => {
|
|
264
|
+
this.logLevelRegistry.setLevel(sessionId, request.params.level);
|
|
265
|
+
return {};
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
protected createGlspMcpServer({ name, options }: FullMcpServerConfiguration): GLSPMcpServer {
|
|
270
|
+
const resourcesAsResources = options.dataMode === 'resources';
|
|
271
|
+
const server = new McpServer(
|
|
272
|
+
{ name, version: SERVER_VERSION },
|
|
273
|
+
{
|
|
274
|
+
capabilities: this.buildCapabilities(resourcesAsResources),
|
|
275
|
+
instructions: options.agentPersona
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
const glspMcpServer = this.glspMcpServerFactory(server, options);
|
|
279
|
+
this.registerHandlers(glspMcpServer, resourcesAsResources);
|
|
280
|
+
return glspMcpServer;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Build the MCP capabilities map from what is actually bound. Only declare a key when at
|
|
285
|
+
* least one handler contributes — declaring a capability the SDK never registers a handler
|
|
286
|
+
* for produces `-32601 Method not found` on `<cap>/list`. Resources surfaced as tools
|
|
287
|
+
* (`dataMode === 'tools'`) count toward `tools`, not `resources`.
|
|
288
|
+
*/
|
|
289
|
+
protected buildCapabilities(resourcesAsResources: boolean): ServerCapabilities {
|
|
290
|
+
const hasStaticTools = this.toolHandlers.length > 0;
|
|
291
|
+
const hasStaticPrompts = this.promptHandlers.length > 0;
|
|
292
|
+
const hasStaticResources = this.resourceHandlers.length > 0;
|
|
293
|
+
const hasDiagramTools = this.dispatcher.hasDiagramTools();
|
|
294
|
+
const hasDiagramPrompts = this.dispatcher.hasDiagramPrompts();
|
|
295
|
+
const hasDiagramResources = this.dispatcher.hasDiagramResources();
|
|
296
|
+
const anyResources = hasStaticResources || hasDiagramResources;
|
|
297
|
+
|
|
298
|
+
const hasTools = hasStaticTools || hasDiagramTools || (!resourcesAsResources && anyResources);
|
|
299
|
+
const hasPrompts = hasStaticPrompts || hasDiagramPrompts;
|
|
300
|
+
const hasResources = resourcesAsResources && anyResources;
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
logging: {},
|
|
304
|
+
...(hasTools ? { tools: { listChanged: false } } : {}),
|
|
305
|
+
// `resources.listChanged: true` iff the catalog contains diagram-scope resources —
|
|
306
|
+
// those aggregate across open GLSP sessions, so the visible list mutates with
|
|
307
|
+
// session add/remove. Server-scope-only catalogs are static, so the flag stays
|
|
308
|
+
// honest at `false` (the SDK reads it; clients refetch only when notified).
|
|
309
|
+
...(hasResources ? { resources: { listChanged: hasDiagramResources } } : {}),
|
|
310
|
+
...(hasPrompts ? { prompts: { listChanged: false } } : {})
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Registers tool/resource/prompt handlers against the per-MCP-session GLSP MCP server. Two
|
|
316
|
+
* sources flow into the catalog:
|
|
317
|
+
*
|
|
318
|
+
* 1. **Server-scope handlers**: singletons bound under `McpToolHandler` /
|
|
319
|
+
* `McpResourceHandler` / `McpPromptHandler`. Registered via their `register*(server)`
|
|
320
|
+
* methods — they're already-instantiated objects that close over their own state.
|
|
321
|
+
*
|
|
322
|
+
* 2. **Diagram-scope handlers**: registered by {@link McpDiagramHandlerDispatcher}, which
|
|
323
|
+
* walks the catalogs harvested at server start and dispatches each registered SDK
|
|
324
|
+
* callback by `params.sessionId` → per-GLSP-session container → registry lookup.
|
|
325
|
+
*/
|
|
326
|
+
protected registerHandlers(glspMcpServer: GLSPMcpServer, resourcesAsResources: boolean): void {
|
|
327
|
+
this.toolHandlers.forEach(handler => handler.registerTool(glspMcpServer));
|
|
328
|
+
this.promptHandlers.forEach(handler => handler.registerPrompt(glspMcpServer));
|
|
329
|
+
if (resourcesAsResources) {
|
|
330
|
+
this.resourceHandlers.forEach(handler => handler.registerResource(glspMcpServer));
|
|
331
|
+
} else {
|
|
332
|
+
this.resourceHandlers.forEach(handler => handler.registerToolAlternative?.(glspMcpServer));
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
this.dispatcher.registerAll(glspMcpServer, resourcesAsResources);
|
|
336
|
+
this.validatePromptToolReferences(glspMcpServer);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Warn when a server-scope prompt's {@link AbstractMcpPromptHandler.referencedToolNames}
|
|
341
|
+
* contains a name not registered on this MCP session — catches adopters who unbind a tool
|
|
342
|
+
* a shipped prompt references via `${OtherHandler.NAME}`.
|
|
343
|
+
*/
|
|
344
|
+
protected validatePromptToolReferences(glspMcpServer: GLSPMcpServer): void {
|
|
345
|
+
for (const handler of this.promptHandlers) {
|
|
346
|
+
const missing = handler.referencedToolNames().filter(name => !glspMcpServer.hasTool(name));
|
|
347
|
+
if (missing.length > 0) {
|
|
348
|
+
this.logger.warn(
|
|
349
|
+
`Prompt '${handler.name}' references unbound tool(s): ${missing.join(', ')}. ` +
|
|
350
|
+
'The prompt will still register but its text points at tools the LLM cannot invoke.'
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
serverShutDown(server: GLSPServer): void {
|
|
357
|
+
this.dispose();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
dispose(): void {
|
|
361
|
+
this.sessionServers.forEach(glspMcpServer => glspMcpServer.dispose());
|
|
362
|
+
this.sessionServers.clear();
|
|
363
|
+
this.toDispose.dispose();
|
|
364
|
+
this.toDispose.clear();
|
|
365
|
+
this.serverUrl = undefined;
|
|
366
|
+
this.serverConfig = undefined;
|
|
367
|
+
this.dispatcher.reset();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
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 { McpServerOptions as McpServerOptionsType } from '@eclipse-glsp/protocol';
|
|
18
|
+
import { BindingContext } from '@eclipse-glsp/protocol/lib/di';
|
|
19
|
+
import {
|
|
20
|
+
AbstractMultiBinding,
|
|
21
|
+
applyBindingTarget,
|
|
22
|
+
BindingTarget,
|
|
23
|
+
GLSPModule,
|
|
24
|
+
GLSPServerInitializer,
|
|
25
|
+
GLSPServerListener,
|
|
26
|
+
Logger
|
|
27
|
+
} from '@eclipse-glsp/server';
|
|
28
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
29
|
+
import { interfaces } from 'inversify';
|
|
30
|
+
import { DescribeDiagramMcpPromptHandler, SuggestImprovementsMcpPromptHandler } from '../prompts';
|
|
31
|
+
import { ElementTypesMcpToolHandler, SessionInfoMcpToolHandler } from '../tools';
|
|
32
|
+
import { DefaultGLSPMcpServer, GLSPMcpServerFactory } from './glsp-mcp-server';
|
|
33
|
+
import { DefaultMcpDiagramHandlerDispatcher, McpDiagramHandlerDispatcher } from './mcp-diagram-handler-dispatcher';
|
|
34
|
+
import { DefaultMcpLogLevelRegistry, McpLogLevelRegistry } from './mcp-log-level-registry';
|
|
35
|
+
import { LruEventStore } from './lru-event-store';
|
|
36
|
+
import { McpHttpTransport } from './mcp-http-transport';
|
|
37
|
+
import { McpLogger } from './mcp-logger';
|
|
38
|
+
import { McpServerDefaults, McpServerOptions } from './mcp-options';
|
|
39
|
+
import { McpProgressReporter } from './mcp-progress-reporter';
|
|
40
|
+
import { McpPromptHandler } from './mcp-prompt-handler';
|
|
41
|
+
import { McpResourceHandler } from './mcp-resource-handler';
|
|
42
|
+
import { McpServerLauncher } from './mcp-server-launcher';
|
|
43
|
+
import { McpToolHandler } from './mcp-tool-handler';
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* GLSP-generic default agent persona — adopters typically pass a product-specific persona to
|
|
47
|
+
* the {@link DefaultMcpServerModule} constructor (e.g. workflow-server might say "You are the
|
|
48
|
+
* Workflow Modeling Agent...").
|
|
49
|
+
*
|
|
50
|
+
* **Spec note.** This is wired to the MCP `instructions` field, which the spec describes as
|
|
51
|
+
* "concise instructions". This persona is intentionally verbose (~700 chars of behavior rules)
|
|
52
|
+
* — within the spec's "free-form server-supplied instructions" allowance and adopter-overridable
|
|
53
|
+
* via `mcpDefaults.agentPersona`. Don't trim on autopilot if a "concise" interpretation drifts
|
|
54
|
+
* back: the verbose form materially improves LLM tool-use compliance for graphical modelling.
|
|
55
|
+
*/
|
|
56
|
+
const DEFAULT_AGENT_PERSONA = `
|
|
57
|
+
You are the GLSP Modeling Agent. Your primary goal is to assist in the creation and modification of graphical models using the
|
|
58
|
+
GLSP MCP server. You have to adhere to the following principles:
|
|
59
|
+
- MCP-Interaction: Any modeling related activity has to occur using the MCP server.
|
|
60
|
+
- Real Data: The diagram model is the ground truth regarding the existing graphical model. Always query it before modifying the diagram.
|
|
61
|
+
- Real Creation: Consult the available element types before creating elements.
|
|
62
|
+
- Visual Proof: An image of the graphical model can be created, if you deem it useful for calculating or verifying layout decisions.
|
|
63
|
+
- Precision: All IDs and types must be exact.
|
|
64
|
+
- Visualization: When creating nodes, suggest sensible default positions and avoid visual overlapping.
|
|
65
|
+
- Careful: Under no circumstances save the model without explicit instruction. If you deem it sensible, you may ask the user for permission.
|
|
66
|
+
The same goes for Undo/Redo operations.
|
|
67
|
+
- Layouting: If available, make use of automatic layouting when not given explicit custom layouting requirements.
|
|
68
|
+
- Human-friendly references: When mentioning an element in user-visible prose, prefer its label, then its element type
|
|
69
|
+
(the bare ids returned by the tools are internal aliases that mean nothing to the user). Append the alias in parentheses
|
|
70
|
+
so the user can correlate it with follow-up tools. Use the \`set-selection\` tool — or the \`set-view\` tool with
|
|
71
|
+
\`action: "center-on-elements"\` — to point the user at the elements you reference.
|
|
72
|
+
`;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Multi-binding helper for MCP handler classes. Singleton-scoped sibling of core's
|
|
76
|
+
* `MultiBinding<T>` — same `binding.add(...)` / `binding.rebind(old, new)` adopter shape, but
|
|
77
|
+
* core's plain `MultiBinding` binds in transient scope, while MCP handlers cache deferred
|
|
78
|
+
* resolvers (selection/PNG round-trips) and need singleton scope to keep their state.
|
|
79
|
+
*/
|
|
80
|
+
export class McpHandlerMultiBinding<T> extends AbstractMultiBinding<interfaces.Newable<T>> {
|
|
81
|
+
override applyBindings(context: BindingContext): void {
|
|
82
|
+
this.bindings.forEach(handlerClass => {
|
|
83
|
+
if (!context.isBound(handlerClass)) {
|
|
84
|
+
context.bind(handlerClass).toSelf().inSingletonScope();
|
|
85
|
+
}
|
|
86
|
+
context.bind(this.identifier).toService(handlerClass);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Server-scope DI module for the MCP server. Adopters subclass {@link DefaultMcpServerModule}
|
|
93
|
+
* and override the `bind*` hooks to swap single-instance services or the `configure*` hooks to
|
|
94
|
+
* add/replace handlers in the multi-bindings. Mirrors the `DiagramModule` pattern from core
|
|
95
|
+
* (`bindGModelSerializer()`, `configureActionHandlers(binding)`, etc.).
|
|
96
|
+
*
|
|
97
|
+
* Adopter-provided default option values flow through the constructor — pass a
|
|
98
|
+
* `Partial<McpServerOptions>` to override individual fields. The launcher then merges these
|
|
99
|
+
* defaults with init-time options from the GLSP `initialize` request (init-time wins per field).
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* // Drop-in: GLSP defaults.
|
|
104
|
+
* launcher.configure(serverModule, new DefaultMcpServerModule());
|
|
105
|
+
*
|
|
106
|
+
* // Drop-in with a product-specific override.
|
|
107
|
+
* launcher.configure(serverModule, new DefaultMcpServerModule({ dataMode: 'resources' }));
|
|
108
|
+
*
|
|
109
|
+
* // Subclass when handler customization is needed.
|
|
110
|
+
* class WorkflowMcpServerModule extends DefaultMcpServerModule {
|
|
111
|
+
* constructor() { super({ agentPersona: WORKFLOW_PERSONA }); }
|
|
112
|
+
* protected override configureToolHandlers(binding) {
|
|
113
|
+
* super.configureToolHandlers(binding);
|
|
114
|
+
* binding.add(WorkflowSpecificTool);
|
|
115
|
+
* }
|
|
116
|
+
* }
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export abstract class AbstractMcpServerModule extends GLSPModule {
|
|
120
|
+
protected bind!: interfaces.Bind;
|
|
121
|
+
protected rebind!: interfaces.Rebind;
|
|
122
|
+
|
|
123
|
+
constructor(protected readonly defaultOptions: McpServerDefaults = {}) {
|
|
124
|
+
super();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
protected override configure(
|
|
128
|
+
bind: interfaces.Bind,
|
|
129
|
+
_unbind: interfaces.Unbind,
|
|
130
|
+
isBound: interfaces.IsBound,
|
|
131
|
+
rebind: interfaces.Rebind
|
|
132
|
+
): void {
|
|
133
|
+
this.bind = bind;
|
|
134
|
+
this.rebind = rebind;
|
|
135
|
+
const context = { bind, isBound };
|
|
136
|
+
applyBindingTarget(context, McpServerLauncher, this.bindMcpServerLauncher()).inSingletonScope();
|
|
137
|
+
// The launcher is bound under two additional service identifiers so core's existing
|
|
138
|
+
// multi-bindings pick it up alongside the rest of the server's contributions/listeners.
|
|
139
|
+
bind(GLSPServerInitializer).toService(McpServerLauncher);
|
|
140
|
+
bind(GLSPServerListener).toService(McpServerLauncher);
|
|
141
|
+
applyBindingTarget(context, McpHttpTransport, this.bindMcpHttpTransport()).inSingletonScope();
|
|
142
|
+
applyBindingTarget(context, McpDiagramHandlerDispatcher, this.bindMcpDiagramHandlerDispatcher()).inSingletonScope();
|
|
143
|
+
applyBindingTarget(context, McpServerOptions, this.bindMcpServerOptions()).inSingletonScope();
|
|
144
|
+
applyBindingTarget(context, McpServerDefaults, this.bindMcpServerDefaults());
|
|
145
|
+
applyBindingTarget(context, McpLogger, this.bindMcpLogger()).inSingletonScope();
|
|
146
|
+
applyBindingTarget(context, McpLogLevelRegistry, this.bindMcpLogLevelRegistry()).inSingletonScope();
|
|
147
|
+
applyBindingTarget(context, McpProgressReporter, this.bindMcpProgressReporter()).inSingletonScope();
|
|
148
|
+
applyBindingTarget(context, GLSPMcpServerFactory, this.bindGLSPMcpServerFactory());
|
|
149
|
+
this.configureMultiBinding(new McpHandlerMultiBinding<McpToolHandler>(McpToolHandler), binding =>
|
|
150
|
+
this.configureToolHandlers(binding as McpHandlerMultiBinding<McpToolHandler>)
|
|
151
|
+
);
|
|
152
|
+
this.configureMultiBinding(new McpHandlerMultiBinding<McpResourceHandler>(McpResourceHandler), binding =>
|
|
153
|
+
this.configureResourceHandlers(binding as McpHandlerMultiBinding<McpResourceHandler>)
|
|
154
|
+
);
|
|
155
|
+
this.configureMultiBinding(new McpHandlerMultiBinding<McpPromptHandler>(McpPromptHandler), binding =>
|
|
156
|
+
this.configurePromptHandlers(binding as McpHandlerMultiBinding<McpPromptHandler>)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* {@link McpServerLauncher} binding. Bound as a singleton AND aliased to
|
|
162
|
+
* `GLSPServerInitializer` + `GLSPServerListener` (the launcher implements both).
|
|
163
|
+
* Override to swap in a custom launcher impl.
|
|
164
|
+
*/
|
|
165
|
+
protected bindMcpServerLauncher(): BindingTarget<McpServerLauncher> {
|
|
166
|
+
return McpServerLauncher;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** {@link McpHttpTransport} binding. Override to swap to a different transport implementation. */
|
|
170
|
+
protected bindMcpHttpTransport(): BindingTarget<McpHttpTransport> {
|
|
171
|
+
return McpHttpTransport;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* {@link McpDiagramHandlerDispatcher} binding. Owns diagram-scope handler discovery,
|
|
176
|
+
* SDK registration, and per-call dispatch routing. Override (or `rebind` to a subclass)
|
|
177
|
+
* to customize registration without subclassing the launcher itself.
|
|
178
|
+
*/
|
|
179
|
+
protected bindMcpDiagramHandlerDispatcher(): BindingTarget<McpDiagramHandlerDispatcher> {
|
|
180
|
+
return DefaultMcpDiagramHandlerDispatcher;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** {@link McpServerOptions} holder binding. Mutated at init by the launcher. */
|
|
184
|
+
protected bindMcpServerOptions(): BindingTarget<McpServerOptions> {
|
|
185
|
+
return McpServerOptions;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* {@link McpServerDefaults} binding — adopter-supplied default option values flow through
|
|
190
|
+
* the constructor and land here as a constant. The launcher merges these defaults with
|
|
191
|
+
* init-time options at server init (init-time wins per field).
|
|
192
|
+
*/
|
|
193
|
+
protected bindMcpServerDefaults(): BindingTarget<McpServerDefaults> {
|
|
194
|
+
return { constantValue: this.defaultOptions };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* {@link McpLogger} binding. Bound on the server container; per-session containers inherit
|
|
199
|
+
* it, so handlers at any scope can inject it; routes through the active MCP request via
|
|
200
|
+
* {@link mcpRequestContext}.
|
|
201
|
+
*/
|
|
202
|
+
protected bindMcpLogger(): BindingTarget<McpLogger> {
|
|
203
|
+
return McpLogger;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** {@link McpProgressReporter} binding. Same scope/lifecycle story as {@link bindMcpLogger}. */
|
|
207
|
+
protected bindMcpProgressReporter(): BindingTarget<McpProgressReporter> {
|
|
208
|
+
return McpProgressReporter;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* {@link McpLogLevelRegistry} binding — holds per-MCP-session `logging/setLevel` thresholds
|
|
213
|
+
* read by {@link McpLogger} when filtering `notifications/message`.
|
|
214
|
+
*/
|
|
215
|
+
protected bindMcpLogLevelRegistry(): BindingTarget<McpLogLevelRegistry> {
|
|
216
|
+
return DefaultMcpLogLevelRegistry;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* {@link GLSPMcpServerFactory} binding — produces a fresh {@link DefaultGLSPMcpServer} per
|
|
221
|
+
* MCP-session-init call. Override to wrap the SDK `McpServer` differently (e.g. add custom
|
|
222
|
+
* middleware, swap the Proxy strategy).
|
|
223
|
+
*/
|
|
224
|
+
protected bindGLSPMcpServerFactory(): BindingTarget<GLSPMcpServerFactory> {
|
|
225
|
+
return {
|
|
226
|
+
dynamicValue: ctx => {
|
|
227
|
+
const logger = ctx.container.get<Logger>(Logger);
|
|
228
|
+
return (mcpServer: McpServer, options: McpServerOptionsType): DefaultGLSPMcpServer =>
|
|
229
|
+
new DefaultGLSPMcpServer(mcpServer, options, logger);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Override to add or replace tool handlers. Adopters typically `super.configureToolHandlers(binding)`
|
|
236
|
+
* to keep the defaults, then `binding.add(MyTool)` for additions or
|
|
237
|
+
* `binding.rebind(StandardTool, MyTool)` for overrides.
|
|
238
|
+
*/
|
|
239
|
+
protected configureToolHandlers(binding: McpHandlerMultiBinding<McpToolHandler>): void {
|
|
240
|
+
binding.add(SessionInfoMcpToolHandler);
|
|
241
|
+
binding.add(ElementTypesMcpToolHandler);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** See {@link configureToolHandlers}. No server-scope resources ship by default. */
|
|
245
|
+
protected configureResourceHandlers(_binding: McpHandlerMultiBinding<McpResourceHandler>): void {
|
|
246
|
+
// empty by default
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* See {@link configureToolHandlers}. Server-scope by default because the shipped prompts
|
|
251
|
+
* (`describe-diagram`, `suggest-improvements`) are diagram-type-agnostic and resolve their
|
|
252
|
+
* target session at invocation time — diagram-scope adopters add prompts via
|
|
253
|
+
* {@link DefaultMcpDiagramModule.configurePromptHandlers}.
|
|
254
|
+
*/
|
|
255
|
+
protected configurePromptHandlers(binding: McpHandlerMultiBinding<McpPromptHandler>): void {
|
|
256
|
+
binding.add(DescribeDiagramMcpPromptHandler);
|
|
257
|
+
binding.add(SuggestImprovementsMcpPromptHandler);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Default {@link AbstractMcpServerModule} entry point. Ships GLSP-default option values (see
|
|
263
|
+
* {@link DEFAULT_OPTIONS}) on top of the abstract module's hook defaults. Adopter-provided
|
|
264
|
+
* overrides via the constructor merge on top.
|
|
265
|
+
*
|
|
266
|
+
* @experimental The MCP integration is under active development. Option names, schema shapes,
|
|
267
|
+
* and handler contracts MAY change in minor releases until the feature graduates from
|
|
268
|
+
* experimental status.
|
|
269
|
+
*/
|
|
270
|
+
export class DefaultMcpServerModule extends AbstractMcpServerModule {
|
|
271
|
+
static readonly DEFAULT_OPTIONS: McpServerDefaults = {
|
|
272
|
+
host: '127.0.0.1',
|
|
273
|
+
allowedHosts: ['127.0.0.1', 'localhost'],
|
|
274
|
+
// `allowedOrigins` deliberately undefined: accept absent Origin (typical for desktop-IDE
|
|
275
|
+
// MCP clients) and rely on Host validation to gate DNS-rebinding. Adopters whose
|
|
276
|
+
// deployment is browser-fronted set this explicitly to their frontend's origin.
|
|
277
|
+
dataMode: 'tools',
|
|
278
|
+
agentPersona: DEFAULT_AGENT_PERSONA,
|
|
279
|
+
// 10K events per session is generous for typical workloads (a few MB) and large enough
|
|
280
|
+
// that disconnects within seconds recover via `Last-Event-ID` resumability.
|
|
281
|
+
eventStoreLimit: LruEventStore.DEFAULT_LIMIT
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
constructor(overrides: McpServerDefaults = {}) {
|
|
285
|
+
super({ ...DefaultMcpServerModule.DEFAULT_OPTIONS, ...overrides });
|
|
286
|
+
}
|
|
287
|
+
}
|