@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,52 @@
|
|
|
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 { GLabel, GModelElement } from '@eclipse-glsp/server';
|
|
18
|
+
import { injectable } from 'inversify';
|
|
19
|
+
|
|
20
|
+
export const McpLabelProvider = Symbol('McpLabelProvider');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Locates the {@link GLabel} that primarily represents an element to a user. Centralises the
|
|
24
|
+
* label-lookup logic so both LLM-facing reads (label-text echoes in tool results,
|
|
25
|
+
* `query-elements` rendering) and writes (`ApplyLabelEditOperation` from `create-nodes` /
|
|
26
|
+
* `modify-nodes`) share one override point.
|
|
27
|
+
*
|
|
28
|
+
* Diagram-scope: bound per GLSP session via {@link DefaultMcpDiagramModule.bindLabelProvider}.
|
|
29
|
+
* Adopters with non-trivial label structures (nested headers, compartments) override the
|
|
30
|
+
* {@link DefaultMcpLabelProvider} once instead of per-handler.
|
|
31
|
+
*
|
|
32
|
+
* @experimental
|
|
33
|
+
*/
|
|
34
|
+
export interface McpLabelProvider {
|
|
35
|
+
/**
|
|
36
|
+
* The {@link GLabel} primarily representing this element to a user. Returns `undefined`
|
|
37
|
+
* when the element has no label.
|
|
38
|
+
*/
|
|
39
|
+
getLabel(element: GModelElement): GLabel | undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Default {@link McpLabelProvider}: returns the first direct {@link GLabel} child. Adopters
|
|
44
|
+
* whose elements wrap labels in intermediary container nodes (headers, compartments) subclass
|
|
45
|
+
* and override {@link getLabel}.
|
|
46
|
+
*/
|
|
47
|
+
@injectable()
|
|
48
|
+
export class DefaultMcpLabelProvider implements McpLabelProvider {
|
|
49
|
+
getLabel(element: GModelElement): GLabel | undefined {
|
|
50
|
+
return element.children.find((child): child is GLabel => child instanceof GLabel);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
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 { DefaultMcpLogLevelRegistry, passesLogThreshold } from './mcp-log-level-registry';
|
|
19
|
+
|
|
20
|
+
describe('passesLogThreshold (G4 severity gate)', () => {
|
|
21
|
+
it('passes a level whose severity is at or above the threshold (RFC 5424: lower number = more severe)', () => {
|
|
22
|
+
// Threshold 'warning' (4) keeps emergency..warning, drops notice..debug.
|
|
23
|
+
expect(passesLogThreshold('emergency', 'warning')).to.equal(true);
|
|
24
|
+
expect(passesLogThreshold('error', 'warning')).to.equal(true);
|
|
25
|
+
expect(passesLogThreshold('warning', 'warning')).to.equal(true);
|
|
26
|
+
expect(passesLogThreshold('notice', 'warning')).to.equal(false);
|
|
27
|
+
expect(passesLogThreshold('info', 'warning')).to.equal(false);
|
|
28
|
+
expect(passesLogThreshold('debug', 'warning')).to.equal(false);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('passes everything when the threshold is debug (the default)', () => {
|
|
32
|
+
for (const level of ['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug'] as const) {
|
|
33
|
+
expect(passesLogThreshold(level, 'debug')).to.equal(true);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('passes only emergency when the threshold is emergency', () => {
|
|
38
|
+
expect(passesLogThreshold('emergency', 'emergency')).to.equal(true);
|
|
39
|
+
expect(passesLogThreshold('alert', 'emergency')).to.equal(false);
|
|
40
|
+
expect(passesLogThreshold('debug', 'emergency')).to.equal(false);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('DefaultMcpLogLevelRegistry', () => {
|
|
45
|
+
it('returns the default level for an unknown session id', () => {
|
|
46
|
+
const registry = new DefaultMcpLogLevelRegistry();
|
|
47
|
+
expect(registry.getLevel('never-set')).to.equal(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns the default level when sessionId is undefined (out-of-band logger calls)', () => {
|
|
51
|
+
const registry = new DefaultMcpLogLevelRegistry();
|
|
52
|
+
expect(registry.getLevel(undefined)).to.equal(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('persists the most recent setLevel value per session and isolates across sessions', () => {
|
|
56
|
+
const registry = new DefaultMcpLogLevelRegistry();
|
|
57
|
+
registry.setLevel('A', 'warning');
|
|
58
|
+
registry.setLevel('B', 'error');
|
|
59
|
+
expect(registry.getLevel('A')).to.equal('warning');
|
|
60
|
+
expect(registry.getLevel('B')).to.equal('error');
|
|
61
|
+
|
|
62
|
+
registry.setLevel('A', 'info');
|
|
63
|
+
expect(registry.getLevel('A')).to.equal('info');
|
|
64
|
+
expect(registry.getLevel('B')).to.equal('error');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('clear(sessionId) drops the entry so a recycled session id starts at the default', () => {
|
|
68
|
+
const registry = new DefaultMcpLogLevelRegistry();
|
|
69
|
+
registry.setLevel('reused', 'error');
|
|
70
|
+
expect(registry.getLevel('reused')).to.equal('error');
|
|
71
|
+
|
|
72
|
+
registry.clear('reused');
|
|
73
|
+
expect(registry.getLevel('reused')).to.equal(DefaultMcpLogLevelRegistry.DEFAULT_LEVEL);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,90 @@
|
|
|
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 { LoggingLevel } from '@modelcontextprotocol/sdk/types.js';
|
|
18
|
+
import { injectable } from 'inversify';
|
|
19
|
+
|
|
20
|
+
export const McpLogLevelRegistry = Symbol('McpLogLevelRegistry');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Per-MCP-session minimum-severity threshold for `notifications/message`. Updated by the
|
|
24
|
+
* server's `logging/setLevel` request handler (registered in {@link McpServerLauncher} on
|
|
25
|
+
* session-init); read by {@link McpLogger} to gate message delivery.
|
|
26
|
+
*
|
|
27
|
+
* Bound as a server-scope singleton: one registry shared across MCP sessions, keyed by
|
|
28
|
+
* session id. On session-close, the entry is cleared so a recycled session id does not
|
|
29
|
+
* inherit a stale threshold.
|
|
30
|
+
*/
|
|
31
|
+
export interface McpLogLevelRegistry {
|
|
32
|
+
/** Update the minimum severity for a session. Called by the SDK setLevel request handler. */
|
|
33
|
+
setLevel(sessionId: string, level: LoggingLevel): void;
|
|
34
|
+
/** Resolve the active threshold for a session, falling back to the default for unknown ids. */
|
|
35
|
+
getLevel(sessionId: string | undefined): LoggingLevel;
|
|
36
|
+
/** Drop the per-session entry on session-close. */
|
|
37
|
+
clear(sessionId: string): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* RFC 5424 severity numbering, mirroring the MCP `LoggingLevel` enum. Lower number = more
|
|
42
|
+
* severe; the threshold compares numerically.
|
|
43
|
+
*/
|
|
44
|
+
const SEVERITY: Record<LoggingLevel, number> = {
|
|
45
|
+
emergency: 0,
|
|
46
|
+
alert: 1,
|
|
47
|
+
critical: 2,
|
|
48
|
+
error: 3,
|
|
49
|
+
warning: 4,
|
|
50
|
+
notice: 5,
|
|
51
|
+
info: 6,
|
|
52
|
+
debug: 7
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns `true` iff a message of severity {@link level} should be delivered given the
|
|
57
|
+
* session's current {@link threshold}. A `setLevel('warning')` call drops `notice`, `info`,
|
|
58
|
+
* and `debug`; `setLevel('debug')` keeps everything (the default).
|
|
59
|
+
*/
|
|
60
|
+
export function passesLogThreshold(level: LoggingLevel, threshold: LoggingLevel): boolean {
|
|
61
|
+
return SEVERITY[level] <= SEVERITY[threshold];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@injectable()
|
|
65
|
+
export class DefaultMcpLogLevelRegistry implements McpLogLevelRegistry {
|
|
66
|
+
/**
|
|
67
|
+
* Default threshold used when the client has not sent `logging/setLevel`. `'debug'` is the
|
|
68
|
+
* MCP-spec-permitted "send everything" mode (the spec lets the server decide if no
|
|
69
|
+
* setLevel was received). Set wide so adopters who never wire setLevel see the same
|
|
70
|
+
* verbose behavior the server had before this registry existed.
|
|
71
|
+
*/
|
|
72
|
+
static readonly DEFAULT_LEVEL: LoggingLevel = 'debug';
|
|
73
|
+
|
|
74
|
+
protected readonly levels = new Map<string, LoggingLevel>();
|
|
75
|
+
|
|
76
|
+
setLevel(sessionId: string, level: LoggingLevel): void {
|
|
77
|
+
this.levels.set(sessionId, level);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
getLevel(sessionId: string | undefined): LoggingLevel {
|
|
81
|
+
if (sessionId === undefined) {
|
|
82
|
+
return DefaultMcpLogLevelRegistry.DEFAULT_LEVEL;
|
|
83
|
+
}
|
|
84
|
+
return this.levels.get(sessionId) ?? DefaultMcpLogLevelRegistry.DEFAULT_LEVEL;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
clear(sessionId: string): void {
|
|
88
|
+
this.levels.delete(sessionId);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
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 { Logger, NullLogger } from '@eclipse-glsp/server';
|
|
18
|
+
import { ServerNotification } from '@modelcontextprotocol/sdk/types.js';
|
|
19
|
+
import { expect } from 'chai';
|
|
20
|
+
import { Container, ContainerModule } from 'inversify';
|
|
21
|
+
import { DefaultMcpLogLevelRegistry, McpLogLevelRegistry } from './mcp-log-level-registry';
|
|
22
|
+
import { McpLogger } from './mcp-logger';
|
|
23
|
+
import { McpRequestExtra, mcpRequestContext } from './mcp-request-context';
|
|
24
|
+
|
|
25
|
+
interface RecordedLog {
|
|
26
|
+
level: string;
|
|
27
|
+
message: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class RecordingLogger extends NullLogger {
|
|
31
|
+
readonly entries: RecordedLog[] = [];
|
|
32
|
+
override info(message: string): void {
|
|
33
|
+
this.entries.push({ level: 'info', message });
|
|
34
|
+
}
|
|
35
|
+
override warn(message: string): void {
|
|
36
|
+
this.entries.push({ level: 'warn', message });
|
|
37
|
+
}
|
|
38
|
+
override error(message: string): void {
|
|
39
|
+
this.entries.push({ level: 'error', message });
|
|
40
|
+
}
|
|
41
|
+
override debug(message: string): void {
|
|
42
|
+
this.entries.push({ level: 'debug', message });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildLogger(): { logger: McpLogger; glspLogger: RecordingLogger; levelRegistry: DefaultMcpLogLevelRegistry } {
|
|
47
|
+
const container = new Container();
|
|
48
|
+
const glspLogger = new RecordingLogger();
|
|
49
|
+
const levelRegistry = new DefaultMcpLogLevelRegistry();
|
|
50
|
+
container.load(
|
|
51
|
+
new ContainerModule(bind => {
|
|
52
|
+
bind(Logger).toConstantValue(glspLogger);
|
|
53
|
+
bind(McpLogLevelRegistry).toConstantValue(levelRegistry);
|
|
54
|
+
bind(McpLogger).toSelf().inSingletonScope();
|
|
55
|
+
})
|
|
56
|
+
);
|
|
57
|
+
return { logger: container.get(McpLogger), glspLogger, levelRegistry };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Build a stub `RequestHandlerExtra` with a recording `sendNotification`. Only `sendNotification`
|
|
62
|
+
* is exercised by `McpLogger`; the remaining fields are never read here, so we cast rather
|
|
63
|
+
* than fabricate the full SDK shape.
|
|
64
|
+
*/
|
|
65
|
+
function buildExtra(sessionId?: string): { extra: McpRequestExtra; sent: ServerNotification[] } {
|
|
66
|
+
const sent: ServerNotification[] = [];
|
|
67
|
+
const extra = {
|
|
68
|
+
sessionId,
|
|
69
|
+
sendNotification: async (n: ServerNotification) => {
|
|
70
|
+
sent.push(n);
|
|
71
|
+
}
|
|
72
|
+
} as unknown as McpRequestExtra;
|
|
73
|
+
return { extra, sent };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
describe('McpLogger', () => {
|
|
77
|
+
describe('outside a request context (no MCP client to deliver to)', () => {
|
|
78
|
+
it('routes info/warn/error/debug to the GLSP Logger only', () => {
|
|
79
|
+
const { logger, glspLogger } = buildLogger();
|
|
80
|
+
|
|
81
|
+
logger.info('hello');
|
|
82
|
+
logger.warn('careful');
|
|
83
|
+
logger.error('boom');
|
|
84
|
+
logger.debug('trace');
|
|
85
|
+
|
|
86
|
+
expect(glspLogger.entries).to.deep.equal([
|
|
87
|
+
{ level: 'info', message: 'hello' },
|
|
88
|
+
{ level: 'warn', message: 'careful' },
|
|
89
|
+
{ level: 'error', message: 'boom' },
|
|
90
|
+
{ level: 'debug', message: 'trace' }
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('inside an mcpRequestContext.run frame', () => {
|
|
96
|
+
it('emits notifications/message to the bound MCP client AND the GLSP Logger', async () => {
|
|
97
|
+
const { logger, glspLogger } = buildLogger();
|
|
98
|
+
const { extra, sent } = buildExtra();
|
|
99
|
+
|
|
100
|
+
await mcpRequestContext.run(extra, async () => {
|
|
101
|
+
logger.info('one');
|
|
102
|
+
logger.warn('two');
|
|
103
|
+
logger.error('three');
|
|
104
|
+
logger.debug('four');
|
|
105
|
+
// Allow the fire-and-forget `.catch` chain in McpLogger.notify to settle.
|
|
106
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(glspLogger.entries.map(e => e.message)).to.deep.equal(['one', 'two', 'three', 'four']);
|
|
110
|
+
expect(
|
|
111
|
+
sent.map(n => ({
|
|
112
|
+
method: n.method,
|
|
113
|
+
level: (n.params as { level: string }).level,
|
|
114
|
+
data: (n.params as { data: string }).data
|
|
115
|
+
}))
|
|
116
|
+
).to.deep.equal([
|
|
117
|
+
{ method: 'notifications/message', level: 'info', data: 'one' },
|
|
118
|
+
{ method: 'notifications/message', level: 'warning', data: 'two' }, // GLSP warn → MCP warning
|
|
119
|
+
{ method: 'notifications/message', level: 'error', data: 'three' },
|
|
120
|
+
{ method: 'notifications/message', level: 'debug', data: 'four' }
|
|
121
|
+
]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('swallows transport failures so a broken MCP send never breaks the producing tool', async () => {
|
|
125
|
+
const { logger, glspLogger } = buildLogger();
|
|
126
|
+
const failingExtra = {
|
|
127
|
+
sendNotification: async () => {
|
|
128
|
+
throw new Error('transport closed');
|
|
129
|
+
}
|
|
130
|
+
} as unknown as McpRequestExtra;
|
|
131
|
+
|
|
132
|
+
await mcpRequestContext.run(failingExtra, async () => {
|
|
133
|
+
expect(() => logger.error('still works')).to.not.throw();
|
|
134
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Server-side log still fired.
|
|
138
|
+
expect(glspLogger.entries).to.deep.equal([{ level: 'error', message: 'still works' }]);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('concurrent request contexts', () => {
|
|
143
|
+
it('keeps each request frame isolated via AsyncLocalStorage', async () => {
|
|
144
|
+
const { logger } = buildLogger();
|
|
145
|
+
const { extra: extraA, sent: sentA } = buildExtra();
|
|
146
|
+
const { extra: extraB, sent: sentB } = buildExtra();
|
|
147
|
+
|
|
148
|
+
await Promise.all([
|
|
149
|
+
mcpRequestContext.run(extraA, async () => {
|
|
150
|
+
logger.info('A');
|
|
151
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
152
|
+
logger.info('A-after-yield');
|
|
153
|
+
}),
|
|
154
|
+
mcpRequestContext.run(extraB, async () => {
|
|
155
|
+
logger.info('B');
|
|
156
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
157
|
+
logger.info('B-after-yield');
|
|
158
|
+
})
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
expect(sentA.map(n => (n.params as { data: string }).data)).to.deep.equal(['A', 'A-after-yield']);
|
|
162
|
+
expect(sentB.map(n => (n.params as { data: string }).data)).to.deep.equal(['B', 'B-after-yield']);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('logging/setLevel threshold gate (G4)', () => {
|
|
167
|
+
it('drops messages below the per-session threshold; the GLSP-side log still fires', async () => {
|
|
168
|
+
const { logger, glspLogger, levelRegistry } = buildLogger();
|
|
169
|
+
const { extra, sent } = buildExtra('session-X');
|
|
170
|
+
// Client opted down to "warning" — info and debug must be dropped on the MCP side.
|
|
171
|
+
levelRegistry.setLevel('session-X', 'warning');
|
|
172
|
+
|
|
173
|
+
await mcpRequestContext.run(extra, async () => {
|
|
174
|
+
logger.info('chatty');
|
|
175
|
+
logger.debug('verbose');
|
|
176
|
+
logger.warn('important');
|
|
177
|
+
logger.error('critical');
|
|
178
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// GLSP-side log path is independent of the MCP threshold — keeps adopter logs intact.
|
|
182
|
+
expect(glspLogger.entries.map(entry => entry.message)).to.deep.equal(['chatty', 'verbose', 'important', 'critical']);
|
|
183
|
+
// MCP side: only warn + error survive.
|
|
184
|
+
expect(sent.map(n => (n.params as { level: string }).level)).to.deep.equal(['warning', 'error']);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('isolates thresholds across sessions (different setLevel per session id)', async () => {
|
|
188
|
+
const { logger, levelRegistry } = buildLogger();
|
|
189
|
+
const { extra: extraA, sent: sentA } = buildExtra('session-A');
|
|
190
|
+
const { extra: extraB, sent: sentB } = buildExtra('session-B');
|
|
191
|
+
levelRegistry.setLevel('session-A', 'error');
|
|
192
|
+
levelRegistry.setLevel('session-B', 'debug');
|
|
193
|
+
|
|
194
|
+
await Promise.all([
|
|
195
|
+
mcpRequestContext.run(extraA, async () => {
|
|
196
|
+
logger.info('A-info');
|
|
197
|
+
logger.error('A-error');
|
|
198
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
199
|
+
}),
|
|
200
|
+
mcpRequestContext.run(extraB, async () => {
|
|
201
|
+
logger.info('B-info');
|
|
202
|
+
logger.error('B-error');
|
|
203
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
204
|
+
})
|
|
205
|
+
]);
|
|
206
|
+
|
|
207
|
+
expect(sentA.map(n => (n.params as { data: string }).data)).to.deep.equal(['A-error']);
|
|
208
|
+
expect(sentB.map(n => (n.params as { data: string }).data).sort()).to.deep.equal(['B-error', 'B-info']);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('default threshold (no setLevel sent) lets every level through (preserves prior behavior)', async () => {
|
|
212
|
+
const { logger } = buildLogger();
|
|
213
|
+
const { extra, sent } = buildExtra('session-default');
|
|
214
|
+
// No setLevel call → default threshold = 'debug' → everything emitted.
|
|
215
|
+
|
|
216
|
+
await mcpRequestContext.run(extra, async () => {
|
|
217
|
+
logger.debug('d');
|
|
218
|
+
logger.info('i');
|
|
219
|
+
logger.warn('w');
|
|
220
|
+
logger.error('e');
|
|
221
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
expect(sent.map(n => (n.params as { level: string }).level)).to.deep.equal(['debug', 'info', 'warning', 'error']);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
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 { Logger } from '@eclipse-glsp/server';
|
|
18
|
+
import type { LoggingLevel } from '@modelcontextprotocol/sdk/types.js';
|
|
19
|
+
import { inject, injectable } from 'inversify';
|
|
20
|
+
import { McpLogLevelRegistry, passesLogThreshold } from './mcp-log-level-registry';
|
|
21
|
+
import { mcpRequestContext } from './mcp-request-context';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Logger that writes to BOTH the GLSP-side server log and the connected MCP client.
|
|
25
|
+
*
|
|
26
|
+
* Mirrors the {@link Logger} shape so handlers can drop-in switch from `@inject(Logger)` to
|
|
27
|
+
* `@inject(McpLogger)`. The server-side route always fires; the MCP-side route fires only when
|
|
28
|
+
* a call is made from inside an MCP request callback (tracked via {@link mcpRequestContext}).
|
|
29
|
+
*
|
|
30
|
+
* We deliberately do NOT auto-forward arbitrary GLSP `Logger.info` calls to MCP clients —
|
|
31
|
+
* that would leak unrelated server-wide log lines into every connected LLM. Adopters opt in
|
|
32
|
+
* per-handler by injecting `McpLogger` instead of `Logger`.
|
|
33
|
+
*
|
|
34
|
+
* Level mapping (GLSP → MCP, RFC 5424 names per the MCP spec):
|
|
35
|
+
* - `info` → `info`
|
|
36
|
+
* - `warn` → `warning`
|
|
37
|
+
* - `error` → `error`
|
|
38
|
+
* - `debug` → `debug`
|
|
39
|
+
*
|
|
40
|
+
* Shared across MCP clients on the same GLSP session; per-client routing is handled by the
|
|
41
|
+
* active `mcpRequestContext` frame, and the per-MCP-session `logging/setLevel` threshold is
|
|
42
|
+
* stored in {@link McpLogLevelRegistry}.
|
|
43
|
+
*
|
|
44
|
+
* @experimental
|
|
45
|
+
*/
|
|
46
|
+
@injectable()
|
|
47
|
+
export class McpLogger {
|
|
48
|
+
@inject(Logger) protected glspLogger: Logger;
|
|
49
|
+
|
|
50
|
+
@inject(McpLogLevelRegistry) protected levelRegistry: McpLogLevelRegistry;
|
|
51
|
+
|
|
52
|
+
info(message: string, ...meta: unknown[]): void {
|
|
53
|
+
this.glspLogger.info(message, ...meta);
|
|
54
|
+
this.notify('info', message);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
warn(message: string, ...meta: unknown[]): void {
|
|
58
|
+
this.glspLogger.warn(message, ...meta);
|
|
59
|
+
this.notify('warning', message);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
error(message: string, ...meta: unknown[]): void {
|
|
63
|
+
this.glspLogger.error(message, ...meta);
|
|
64
|
+
this.notify('error', message);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
debug(message: string, ...meta: unknown[]): void {
|
|
68
|
+
this.glspLogger.debug(message, ...meta);
|
|
69
|
+
this.notify('debug', message);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Send a `notifications/message` to the connected MCP client when invoked inside an active
|
|
74
|
+
* request context AND the message passes the session's `logging/setLevel` threshold.
|
|
75
|
+
* Outside a request context (init contributions, background timers) this is a no-op so the
|
|
76
|
+
* same logger can be used everywhere without orphan-notification leaks.
|
|
77
|
+
*
|
|
78
|
+
* Failures to deliver are swallowed — a broken transport must not break the producing tool.
|
|
79
|
+
*/
|
|
80
|
+
protected notify(level: LoggingLevel, data: string): void {
|
|
81
|
+
const extra = mcpRequestContext.getStore();
|
|
82
|
+
if (!extra) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const threshold = this.levelRegistry.getLevel(extra.sessionId);
|
|
86
|
+
if (!passesLogThreshold(level, threshold)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
extra.sendNotification({ method: 'notifications/message', params: { level, data } }).catch(() => undefined);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
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 { ProposalString } from '@eclipse-glsp/protocol';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* MIME type for an MCP resource. Annotating a `mimeType` field with this type prompts the IDE
|
|
21
|
+
* to suggest the listed common values; any other string the MCP SDK accepts is also valid (the
|
|
22
|
+
* `(string & {})` part of `ProposalString` keeps the field free-form).
|
|
23
|
+
*
|
|
24
|
+
* Unlike `MarkersReason` / `EditMode` (closed sets of framework-defined enum values), MIME
|
|
25
|
+
* types are open and IANA-defined — the listed literals are common, not exhaustive. There's
|
|
26
|
+
* no companion const object: at the call site, adopters write the string literal directly
|
|
27
|
+
* (`readonly mimeType: McpMimeType = 'image/png';`).
|
|
28
|
+
*/
|
|
29
|
+
export type McpMimeType = ProposalString<
|
|
30
|
+
'text/plain' | 'text/markdown' | 'text/html' | 'application/json' | 'image/png' | 'image/jpeg' | 'image/svg+xml'
|
|
31
|
+
>;
|
|
@@ -0,0 +1,43 @@
|
|
|
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 { injectable } from 'inversify';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Holds the launcher-scoped MCP options. The launcher merges adopter-provided defaults
|
|
22
|
+
* (passed to the {@link AbstractMcpServerModule} constructor, bound as
|
|
23
|
+
* {@link McpServerDefaults}) with deployment-time overrides from the GLSP `initialize` request,
|
|
24
|
+
* then writes the merged result to `values`. Consumers `@inject(McpServerOptions)` and read
|
|
25
|
+
* `.values.<key>` directly.
|
|
26
|
+
*
|
|
27
|
+
* Bound as a singleton on the server container — the shared reference means server-scope
|
|
28
|
+
* singletons constructed before init still observe populated values once init runs.
|
|
29
|
+
*
|
|
30
|
+
* @experimental
|
|
31
|
+
*/
|
|
32
|
+
@injectable()
|
|
33
|
+
export class McpServerOptions {
|
|
34
|
+
values: McpServerOptionsType = {};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* DI binding identifier for adopter-provided default options. Supplied via the
|
|
39
|
+
* {@link AbstractMcpServerModule} constructor and merged with init-time options by
|
|
40
|
+
* `McpServerLauncher.initializeServer` — init-time wins per field.
|
|
41
|
+
*/
|
|
42
|
+
export const McpServerDefaults = Symbol('McpServerDefaults');
|
|
43
|
+
export type McpServerDefaults = McpServerOptionsType;
|