@eclipse-glsp/server-mcp 2.7.0-next.10
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 +66 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +82 -0
- package/lib/index.js.map +1 -0
- package/lib/modules/mcp-diagram-module.d.ts +123 -0
- package/lib/modules/mcp-diagram-module.d.ts.map +1 -0
- package/lib/modules/mcp-diagram-module.js +202 -0
- package/lib/modules/mcp-diagram-module.js.map +1 -0
- package/lib/modules/mcp-server-module.d.ts +143 -0
- package/lib/modules/mcp-server-module.d.ts.map +1 -0
- package/lib/modules/mcp-server-module.js +251 -0
- package/lib/modules/mcp-server-module.js.map +1 -0
- package/lib/prompts/handlers/describe-diagram-mcp-prompt-handler.d.ts +44 -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 +102 -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 +44 -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 +99 -0
- package/lib/prompts/handlers/suggest-improvements-mcp-prompt-handler.js.map +1 -0
- package/lib/resources/handlers/diagram-png-mcp-resource-handler.d.ts +84 -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 +177 -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 +55 -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 +99 -0
- package/lib/resources/handlers/diagram-svg-mcp-resource-handler.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/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-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-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 +47 -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 +77 -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 +113 -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 +191 -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 +82 -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 +124 -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 +53 -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 +74 -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 +60 -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 +79 -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 +98 -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 +156 -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 +44 -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 +70 -0
- package/lib/tools/handlers/get-selection-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.d.ts +44 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.js +72 -0
- package/lib/tools/handlers/layout-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/modify-edges-mcp-tool-handler.d.ts +79 -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 +138 -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 +93 -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 +127 -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 +103 -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 +160 -0
- package/lib/tools/handlers/query-elements-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.d.ts +46 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.js +75 -0
- package/lib/tools/handlers/redo-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/save-model-mcp-tool-handler.d.ts +57 -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 +93 -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 +66 -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 +109 -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 +61 -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 +104 -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 +111 -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 +144 -0
- package/lib/tools/handlers/set-view-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.d.ts +46 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.d.ts.map +1 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.js +76 -0
- package/lib/tools/handlers/undo-mcp-tool-handler.js.map +1 -0
- package/lib/tools/handlers/validate-diagram-mcp-tool-handler.d.ts +67 -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/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 +65 -0
- package/src/modules/mcp-diagram-module.ts +247 -0
- package/src/modules/mcp-server-module.ts +289 -0
- package/src/prompts/handlers/describe-diagram-mcp-prompt-handler.ts +88 -0
- package/src/prompts/handlers/suggest-improvements-mcp-prompt-handler.ts +85 -0
- package/src/resources/handlers/diagram-png-mcp-resource-handler.ts +177 -0
- package/src/resources/handlers/diagram-svg-mcp-resource-handler.ts +85 -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/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-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-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 +101 -0
- package/src/tools/handlers/count-elements-mcp-tool-handler.ts +68 -0
- package/src/tools/handlers/create-edges-mcp-tool-handler.spec.ts +198 -0
- package/src/tools/handlers/create-edges-mcp-tool-handler.ts +200 -0
- package/src/tools/handlers/create-nodes-mcp-tool-handler.spec.ts +199 -0
- package/src/tools/handlers/create-nodes-mcp-tool-handler.ts +126 -0
- package/src/tools/handlers/delete-elements-mcp-tool-handler.ts +69 -0
- package/src/tools/handlers/diagram-model-mcp-tool-handler.ts +68 -0
- package/src/tools/handlers/element-types-mcp-tool-handler.ts +152 -0
- package/src/tools/handlers/get-selection-mcp-tool-handler.ts +56 -0
- package/src/tools/handlers/layout-mcp-tool-handler.ts +58 -0
- package/src/tools/handlers/modify-edges-mcp-tool-handler.ts +142 -0
- package/src/tools/handlers/modify-nodes-mcp-tool-handler.ts +134 -0
- package/src/tools/handlers/query-elements-mcp-tool-handler.spec.ts +212 -0
- package/src/tools/handlers/query-elements-mcp-tool-handler.ts +157 -0
- package/src/tools/handlers/redo-mcp-tool-handler.ts +64 -0
- package/src/tools/handlers/save-model-mcp-tool-handler.ts +74 -0
- package/src/tools/handlers/session-info-mcp-tool-handler.spec.ts +152 -0
- package/src/tools/handlers/session-info-mcp-tool-handler.ts +98 -0
- package/src/tools/handlers/set-selection-mcp-tool-handler.spec.ts +120 -0
- package/src/tools/handlers/set-selection-mcp-tool-handler.ts +92 -0
- package/src/tools/handlers/set-view-mcp-tool-handler.ts +156 -0
- package/src/tools/handlers/undo-mcp-tool-handler.ts +63 -0
- package/src/tools/handlers/validate-diagram-mcp-tool-handler.ts +0 -0
- package/src/tools/tool-annotations.spec.ts +141 -0
- package/src/util/markdown-util.ts +44 -0
- package/src/util/mcp-util.ts +25 -0
|
@@ -0,0 +1,112 @@
|
|
|
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 { EventId, EventStore, StreamId } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
19
|
+
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* In-memory `EventStore` with a bounded LRU cap, replacing the SDK's `InMemoryEventStore`
|
|
23
|
+
* (which is unbounded and explicitly intended only for examples).
|
|
24
|
+
*
|
|
25
|
+
* Resumability via `Last-Event-ID` requires that historical events stay reachable. Without a
|
|
26
|
+
* cap, the underlying `Map` grows linearly with `MCP message volume × server uptime` — fine
|
|
27
|
+
* for local-dev, a slow leak for daemonised / multi-user / CI deployments.
|
|
28
|
+
*
|
|
29
|
+
* Eviction shape: insert-order LRU. JS `Map` already preserves insertion order, so newer
|
|
30
|
+
* events sit at the tail and `keys().next()` returns the oldest. On overflow we delete the
|
|
31
|
+
* oldest — no timer, no periodic sweep, no `dispose()` plumbing required. The cap must be
|
|
32
|
+
* comfortably larger than the worst-case in-flight event count (per-client × concurrent-clients
|
|
33
|
+
* × disconnect-window), or a client reconnecting with a stale `Last-Event-ID` will find its
|
|
34
|
+
* resume point already evicted.
|
|
35
|
+
*
|
|
36
|
+
* The event-id format mirrors the SDK's example impl (`<streamId>_<timestamp>_<random>`) so
|
|
37
|
+
* `replayEventsAfter` can extract the stream id with the same `split('_')[0]` trick.
|
|
38
|
+
*/
|
|
39
|
+
export class LruEventStore implements EventStore {
|
|
40
|
+
static readonly DEFAULT_LIMIT = 10_000;
|
|
41
|
+
|
|
42
|
+
protected readonly events = new Map<EventId, { streamId: StreamId; message: JSONRPCMessage }>();
|
|
43
|
+
protected readonly limit: number;
|
|
44
|
+
protected readonly logger?: Logger;
|
|
45
|
+
|
|
46
|
+
constructor(limit: number = LruEventStore.DEFAULT_LIMIT, logger?: Logger) {
|
|
47
|
+
if (limit < 1) {
|
|
48
|
+
throw new Error(`LruEventStore limit must be >= 1, got ${limit}`);
|
|
49
|
+
}
|
|
50
|
+
this.limit = limit;
|
|
51
|
+
this.logger = logger;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Current event count. Exposed for tests. */
|
|
55
|
+
get size(): number {
|
|
56
|
+
return this.events.size;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async storeEvent(streamId: StreamId, message: JSONRPCMessage): Promise<EventId> {
|
|
60
|
+
// Format: `<streamId>_<unixMs>_<8-char-base36-random>`. The leading `streamId` lets
|
|
61
|
+
// `replayEventsAfter` recover the stream via `split('_')[0]` without a side table; the
|
|
62
|
+
// timestamp + random suffix make ids globally unique across concurrent emits.
|
|
63
|
+
const eventId = `${streamId}_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
|
|
64
|
+
this.events.set(eventId, { streamId, message });
|
|
65
|
+
if (this.events.size > this.limit) {
|
|
66
|
+
const oldest = this.events.keys().next().value;
|
|
67
|
+
if (oldest !== undefined) {
|
|
68
|
+
this.events.delete(oldest);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return eventId;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async replayEventsAfter(
|
|
75
|
+
lastEventId: EventId,
|
|
76
|
+
{ send }: { send: (eventId: EventId, message: JSONRPCMessage) => Promise<void> }
|
|
77
|
+
): Promise<StreamId> {
|
|
78
|
+
if (!lastEventId) {
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
if (!this.events.has(lastEventId)) {
|
|
82
|
+
// Cap-eviction race: warn so adopters can tune `eventStoreLimit` upward.
|
|
83
|
+
this.logger?.warn(
|
|
84
|
+
`[LruEventStore] Replay miss for last-event-id '${lastEventId}'. ` +
|
|
85
|
+
`Cap is ${this.limit}; consider increasing \`eventStoreLimit\` if this fires under normal load.`
|
|
86
|
+
);
|
|
87
|
+
return '';
|
|
88
|
+
}
|
|
89
|
+
const streamId = lastEventId.split('_')[0];
|
|
90
|
+
if (!streamId) {
|
|
91
|
+
return '';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Map iteration is insertion-order — equivalent to the SDK example's `localeCompare`
|
|
95
|
+
// sort under our id format, but cheaper and not dependent on the lexicographic-vs-
|
|
96
|
+
// chronological coincidence of the timestamp segment.
|
|
97
|
+
let foundLast = false;
|
|
98
|
+
for (const [eventId, { streamId: evtStreamId, message }] of this.events) {
|
|
99
|
+
if (evtStreamId !== streamId) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (eventId === lastEventId) {
|
|
103
|
+
foundLast = true;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (foundLast) {
|
|
107
|
+
await send(eventId, message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return streamId;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
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 { CallToolResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
|
|
18
|
+
import { expect } from 'chai';
|
|
19
|
+
import { GLSPMcpServer } from './glsp-mcp-server';
|
|
20
|
+
import { DefaultMcpDiagramHandlerDispatcher, DiagramTypeCatalog } from './mcp-diagram-handler-dispatcher';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Tests the SDK-callback dispatch error path covered by `runWithToolErrorEnvelope`. The
|
|
24
|
+
* concern is that pre-handler routing errors (missing/unknown sessionId, unknown handler name)
|
|
25
|
+
* that the launcher's tool path `throw McpToolError` are converted into `{ isError: true }` tool
|
|
26
|
+
* results by the wrap, instead of bubbling up as JSON-RPC `-32603 Internal error`.
|
|
27
|
+
*
|
|
28
|
+
* The prompt path is intentionally NOT wrapped — prompt errors propagate as JSON-RPC errors per
|
|
29
|
+
* MCP spec semantics. This test pins that asymmetry too.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
type ToolCallback = (params: unknown, extra: unknown) => Promise<CallToolResult>;
|
|
33
|
+
type PromptCallback = (args: unknown, extra: unknown) => Promise<unknown>;
|
|
34
|
+
type StaticResourceCallback = (uri: URL, extra: unknown) => Promise<ReadResourceResult>;
|
|
35
|
+
|
|
36
|
+
class CapturingMcpServer {
|
|
37
|
+
readonly tools = new Map<string, ToolCallback>();
|
|
38
|
+
readonly prompts = new Map<string, PromptCallback>();
|
|
39
|
+
readonly staticResources = new Map<string, StaticResourceCallback>();
|
|
40
|
+
|
|
41
|
+
registerTool(name: string, _config: unknown, callback: ToolCallback): unknown {
|
|
42
|
+
this.tools.set(name, callback);
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
registerPrompt(name: string, _config: unknown, callback: PromptCallback): unknown {
|
|
47
|
+
this.prompts.set(name, callback);
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
registerResource(name: string, uriOrTemplate: unknown, _config: unknown, callback: unknown): unknown {
|
|
52
|
+
if (typeof uriOrTemplate === 'string') {
|
|
53
|
+
this.staticResources.set(name, callback as StaticResourceCallback);
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function makeDispatcher(
|
|
60
|
+
catalog: DiagramTypeCatalog,
|
|
61
|
+
sessions: Array<{ id: string; container?: unknown; diagramType?: string }> = []
|
|
62
|
+
): DefaultMcpDiagramHandlerDispatcher {
|
|
63
|
+
const dispatcher = new DefaultMcpDiagramHandlerDispatcher();
|
|
64
|
+
(dispatcher as unknown as { diagramCatalogs: DiagramTypeCatalog[] }).diagramCatalogs = [catalog];
|
|
65
|
+
(dispatcher as unknown as { clientSessionManager: unknown }).clientSessionManager = {
|
|
66
|
+
getSessions: () => sessions,
|
|
67
|
+
getSession: (id: string) => sessions.find(session => session.id === id)
|
|
68
|
+
};
|
|
69
|
+
return dispatcher;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
class FakeToolHandlerCtor {
|
|
73
|
+
name = 'fake-tool';
|
|
74
|
+
title = 'Fake';
|
|
75
|
+
description = 'A test tool';
|
|
76
|
+
inputSchema = { strict: () => ({}) };
|
|
77
|
+
toRegistrationConfig(): unknown {
|
|
78
|
+
return { title: this.title, description: this.description, inputSchema: {} };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
class FakePromptHandlerCtor {
|
|
83
|
+
name = 'fake-prompt';
|
|
84
|
+
title = 'FakePrompt';
|
|
85
|
+
description = 'A test prompt';
|
|
86
|
+
toRegistrationConfig(): unknown {
|
|
87
|
+
return { title: this.title, description: this.description };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
class FakeResourceAsToolHandlerCtor {
|
|
92
|
+
name = 'fake-resource';
|
|
93
|
+
title = 'FakeResource';
|
|
94
|
+
description = 'A test resource exposed as tool';
|
|
95
|
+
mimeType = 'text/plain';
|
|
96
|
+
uri = 'glsp://static/fake';
|
|
97
|
+
toolAlternativeInputSchema = { strict: () => ({}) };
|
|
98
|
+
toolAlternativeOutputSchema = undefined;
|
|
99
|
+
toAnnotations(): undefined {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
class FakeStaticResourceHandlerCtor {
|
|
105
|
+
name = 'fake-static-resource';
|
|
106
|
+
title = 'FakeStatic';
|
|
107
|
+
description = 'A test static-URI resource';
|
|
108
|
+
mimeType = 'text/plain';
|
|
109
|
+
uri = 'glsp://static/fake';
|
|
110
|
+
toAnnotations(): undefined {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
describe('DefaultMcpDiagramHandlerDispatcher · SDK-callback dispatch error envelope', () => {
|
|
116
|
+
it('tool callback returns isError envelope when sessionId is missing', async () => {
|
|
117
|
+
const dispatcher = makeDispatcher({
|
|
118
|
+
diagramType: 'test',
|
|
119
|
+
toolConstructors: [FakeToolHandlerCtor as unknown as DiagramTypeCatalog['toolConstructors'][number]],
|
|
120
|
+
resourceConstructors: [],
|
|
121
|
+
promptConstructors: []
|
|
122
|
+
});
|
|
123
|
+
const captured = new CapturingMcpServer();
|
|
124
|
+
dispatcher.registerAll(captured as unknown as GLSPMcpServer, false);
|
|
125
|
+
|
|
126
|
+
const result = await captured.tools.get('fake-tool')!({}, {});
|
|
127
|
+
expect(result.isError).to.equal(true);
|
|
128
|
+
expect((result.content as Array<{ text: string }>)[0].text).to.match(/sessionId/);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('tool callback returns isError envelope when sessionId is unknown', async () => {
|
|
132
|
+
const dispatcher = makeDispatcher(
|
|
133
|
+
{
|
|
134
|
+
diagramType: 'test',
|
|
135
|
+
toolConstructors: [FakeToolHandlerCtor as unknown as DiagramTypeCatalog['toolConstructors'][number]],
|
|
136
|
+
resourceConstructors: [],
|
|
137
|
+
promptConstructors: []
|
|
138
|
+
},
|
|
139
|
+
[] // no open sessions
|
|
140
|
+
);
|
|
141
|
+
const captured = new CapturingMcpServer();
|
|
142
|
+
dispatcher.registerAll(captured as unknown as GLSPMcpServer, false);
|
|
143
|
+
|
|
144
|
+
const result = await captured.tools.get('fake-tool')!({ sessionId: 'unknown-glsp-id' }, {});
|
|
145
|
+
expect(result.isError).to.equal(true);
|
|
146
|
+
expect((result.content as Array<{ text: string }>)[0].text).to.match(/Session not found/);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('tool callback returns isError envelope when registered handler is absent for the session', async () => {
|
|
150
|
+
const sessionContainer = {
|
|
151
|
+
get: () => ({
|
|
152
|
+
get: () => undefined // registry returns no handler
|
|
153
|
+
})
|
|
154
|
+
};
|
|
155
|
+
const dispatcher = makeDispatcher(
|
|
156
|
+
{
|
|
157
|
+
diagramType: 'test',
|
|
158
|
+
toolConstructors: [FakeToolHandlerCtor as unknown as DiagramTypeCatalog['toolConstructors'][number]],
|
|
159
|
+
resourceConstructors: [],
|
|
160
|
+
promptConstructors: []
|
|
161
|
+
},
|
|
162
|
+
[{ id: 'session-1', container: sessionContainer, diagramType: 'test' }]
|
|
163
|
+
);
|
|
164
|
+
const captured = new CapturingMcpServer();
|
|
165
|
+
dispatcher.registerAll(captured as unknown as GLSPMcpServer, false);
|
|
166
|
+
|
|
167
|
+
const result = await captured.tools.get('fake-tool')!({ sessionId: 'session-1' }, {});
|
|
168
|
+
expect(result.isError).to.equal(true);
|
|
169
|
+
expect((result.content as Array<{ text: string }>)[0].text).to.match(/No tool handler/);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('resource-as-tool callback returns isError envelope when sessionId is missing', async () => {
|
|
173
|
+
const dispatcher = makeDispatcher({
|
|
174
|
+
diagramType: 'test',
|
|
175
|
+
toolConstructors: [],
|
|
176
|
+
resourceConstructors: [FakeResourceAsToolHandlerCtor as unknown as DiagramTypeCatalog['resourceConstructors'][number]],
|
|
177
|
+
promptConstructors: []
|
|
178
|
+
});
|
|
179
|
+
const captured = new CapturingMcpServer();
|
|
180
|
+
// dataMode='tools' (resourcesAsResources=false) → resource registers as tool fallback.
|
|
181
|
+
dispatcher.registerAll(captured as unknown as GLSPMcpServer, false);
|
|
182
|
+
|
|
183
|
+
const result = await captured.tools.get('fake-resource')!({}, {});
|
|
184
|
+
expect(result.isError).to.equal(true);
|
|
185
|
+
expect((result.content as Array<{ text: string }>)[0].text).to.match(/sessionId/);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('static-URI resource read throws McpToolError when no GLSP session is open', async () => {
|
|
189
|
+
const dispatcher = makeDispatcher(
|
|
190
|
+
{
|
|
191
|
+
diagramType: 'test',
|
|
192
|
+
toolConstructors: [],
|
|
193
|
+
resourceConstructors: [FakeStaticResourceHandlerCtor as unknown as DiagramTypeCatalog['resourceConstructors'][number]],
|
|
194
|
+
promptConstructors: []
|
|
195
|
+
},
|
|
196
|
+
[] // no open sessions
|
|
197
|
+
);
|
|
198
|
+
const captured = new CapturingMcpServer();
|
|
199
|
+
// dataMode='resources' (resourcesAsResources=true) → resource registers as URI-addressable resource.
|
|
200
|
+
dispatcher.registerAll(captured as unknown as GLSPMcpServer, true);
|
|
201
|
+
|
|
202
|
+
let rejection: unknown;
|
|
203
|
+
try {
|
|
204
|
+
await captured.staticResources.get('fake-static-resource')!(new URL('glsp://static/fake'), {});
|
|
205
|
+
} catch (err: unknown) {
|
|
206
|
+
rejection = err;
|
|
207
|
+
}
|
|
208
|
+
expect(rejection).to.exist;
|
|
209
|
+
expect((rejection as Error).message).to.match(/No open GLSP session/);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('prompt callback rejects with McpToolError when sessionId is missing (no envelope wrap — by design)', async () => {
|
|
213
|
+
const dispatcher = makeDispatcher({
|
|
214
|
+
diagramType: 'test',
|
|
215
|
+
toolConstructors: [],
|
|
216
|
+
resourceConstructors: [],
|
|
217
|
+
promptConstructors: [FakePromptHandlerCtor as unknown as DiagramTypeCatalog['promptConstructors'][number]]
|
|
218
|
+
});
|
|
219
|
+
const captured = new CapturingMcpServer();
|
|
220
|
+
dispatcher.registerAll(captured as unknown as GLSPMcpServer, false);
|
|
221
|
+
|
|
222
|
+
let rejection: unknown;
|
|
223
|
+
try {
|
|
224
|
+
await captured.prompts.get('fake-prompt')!({}, {});
|
|
225
|
+
} catch (err: unknown) {
|
|
226
|
+
rejection = err;
|
|
227
|
+
}
|
|
228
|
+
expect(rejection).to.exist;
|
|
229
|
+
expect((rejection as Error).message).to.match(/sessionId/);
|
|
230
|
+
});
|
|
231
|
+
});
|