@eclipse-glsp/server-mcp 2.8.0-next.0 → 2.8.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.
Files changed (120) hide show
  1. package/README.md +7 -7
  2. package/lib/browser/modules/browser-mcp-server-module.js +1 -1
  3. package/lib/browser/modules/browser-mcp-server-module.js.map +1 -1
  4. package/lib/common/modules/abstract-mcp-server-module.d.ts +1 -2
  5. package/lib/common/modules/abstract-mcp-server-module.d.ts.map +1 -1
  6. package/lib/common/modules/abstract-mcp-server-module.js.map +1 -1
  7. package/lib/common/prompts/handlers/describe-diagram-mcp-prompt-handler.js +3 -2
  8. package/lib/common/prompts/handlers/describe-diagram-mcp-prompt-handler.js.map +1 -1
  9. package/lib/common/prompts/handlers/suggest-improvements-mcp-prompt-handler.js +3 -2
  10. package/lib/common/prompts/handlers/suggest-improvements-mcp-prompt-handler.js.map +1 -1
  11. package/lib/common/resources/handlers/diagram-png-mcp-resource-handler.js +5 -4
  12. package/lib/common/resources/handlers/diagram-png-mcp-resource-handler.js.map +1 -1
  13. package/lib/common/resources/handlers/diagram-svg-mcp-resource-handler.js +4 -3
  14. package/lib/common/resources/handlers/diagram-svg-mcp-resource-handler.js.map +1 -1
  15. package/lib/common/resources/services/element-types-provider.d.ts.map +1 -1
  16. package/lib/common/resources/services/element-types-provider.js +1 -2
  17. package/lib/common/resources/services/element-types-provider.js.map +1 -1
  18. package/lib/common/resources/services/mcp-model-serializer.d.ts +1 -2
  19. package/lib/common/resources/services/mcp-model-serializer.d.ts.map +1 -1
  20. package/lib/common/resources/services/mcp-model-serializer.js +3 -5
  21. package/lib/common/resources/services/mcp-model-serializer.js.map +1 -1
  22. package/lib/common/server/abstract-mcp-server-launcher.d.ts +3 -4
  23. package/lib/common/server/abstract-mcp-server-launcher.d.ts.map +1 -1
  24. package/lib/common/server/abstract-mcp-server-launcher.js +9 -14
  25. package/lib/common/server/abstract-mcp-server-launcher.js.map +1 -1
  26. package/lib/common/server/glsp-mcp-server.d.ts.map +1 -1
  27. package/lib/common/server/glsp-mcp-server.js +2 -2
  28. package/lib/common/server/glsp-mcp-server.js.map +1 -1
  29. package/lib/common/server/lru-event-store.js +2 -3
  30. package/lib/common/server/lru-event-store.js.map +1 -1
  31. package/lib/common/server/mcp-diagram-handler-dispatcher.js +4 -8
  32. package/lib/common/server/mcp-diagram-handler-dispatcher.js.map +1 -1
  33. package/lib/common/server/mcp-handler-shared.d.ts +1 -2
  34. package/lib/common/server/mcp-handler-shared.d.ts.map +1 -1
  35. package/lib/common/server/mcp-handler-shared.js +1 -1
  36. package/lib/common/server/mcp-handler-shared.js.map +1 -1
  37. package/lib/common/server/mcp-id-alias-service.js +1 -2
  38. package/lib/common/server/mcp-id-alias-service.js.map +1 -1
  39. package/lib/common/server/mcp-log-level-registry.js +10 -10
  40. package/lib/common/server/mcp-log-level-registry.js.map +1 -1
  41. package/lib/common/server/mcp-mime-types.d.ts +1 -1
  42. package/lib/common/server/mcp-mime-types.d.ts.map +1 -1
  43. package/lib/common/server/mcp-options.d.ts +1 -1
  44. package/lib/common/server/mcp-options.d.ts.map +1 -1
  45. package/lib/common/server/mcp-progress-reporter.js +1 -2
  46. package/lib/common/server/mcp-progress-reporter.js.map +1 -1
  47. package/lib/common/server/mcp-resource-handler.js +5 -9
  48. package/lib/common/server/mcp-resource-handler.js.map +1 -1
  49. package/lib/common/server/mcp-tool-handler.js +1 -2
  50. package/lib/common/server/mcp-tool-handler.js.map +1 -1
  51. package/lib/common/tools/handlers/count-elements-mcp-tool-handler.js +4 -4
  52. package/lib/common/tools/handlers/count-elements-mcp-tool-handler.js.map +1 -1
  53. package/lib/common/tools/handlers/create-edges-mcp-tool-handler.js +4 -3
  54. package/lib/common/tools/handlers/create-edges-mcp-tool-handler.js.map +1 -1
  55. package/lib/common/tools/handlers/create-nodes-mcp-tool-handler.js +5 -5
  56. package/lib/common/tools/handlers/create-nodes-mcp-tool-handler.js.map +1 -1
  57. package/lib/common/tools/handlers/delete-elements-mcp-tool-handler.js +3 -2
  58. package/lib/common/tools/handlers/delete-elements-mcp-tool-handler.js.map +1 -1
  59. package/lib/common/tools/handlers/diagram-model-mcp-tool-handler.js +3 -2
  60. package/lib/common/tools/handlers/diagram-model-mcp-tool-handler.js.map +1 -1
  61. package/lib/common/tools/handlers/element-types-mcp-tool-handler.js +4 -3
  62. package/lib/common/tools/handlers/element-types-mcp-tool-handler.js.map +1 -1
  63. package/lib/common/tools/handlers/get-selection-mcp-tool-handler.js +3 -2
  64. package/lib/common/tools/handlers/get-selection-mcp-tool-handler.js.map +1 -1
  65. package/lib/common/tools/handlers/layout-mcp-tool-handler.js +3 -2
  66. package/lib/common/tools/handlers/layout-mcp-tool-handler.js.map +1 -1
  67. package/lib/common/tools/handlers/modify-edges-mcp-tool-handler.js +3 -2
  68. package/lib/common/tools/handlers/modify-edges-mcp-tool-handler.js.map +1 -1
  69. package/lib/common/tools/handlers/modify-nodes-mcp-tool-handler.js +6 -6
  70. package/lib/common/tools/handlers/modify-nodes-mcp-tool-handler.js.map +1 -1
  71. package/lib/common/tools/handlers/query-elements-mcp-tool-handler.js +7 -7
  72. package/lib/common/tools/handlers/query-elements-mcp-tool-handler.js.map +1 -1
  73. package/lib/common/tools/handlers/redo-mcp-tool-handler.js +3 -2
  74. package/lib/common/tools/handlers/redo-mcp-tool-handler.js.map +1 -1
  75. package/lib/common/tools/handlers/save-model-mcp-tool-handler.js +3 -2
  76. package/lib/common/tools/handlers/save-model-mcp-tool-handler.js.map +1 -1
  77. package/lib/common/tools/handlers/session-info-mcp-tool-handler.js +4 -4
  78. package/lib/common/tools/handlers/session-info-mcp-tool-handler.js.map +1 -1
  79. package/lib/common/tools/handlers/set-selection-mcp-tool-handler.js +5 -4
  80. package/lib/common/tools/handlers/set-selection-mcp-tool-handler.js.map +1 -1
  81. package/lib/common/tools/handlers/set-view-mcp-tool-handler.js +5 -4
  82. package/lib/common/tools/handlers/set-view-mcp-tool-handler.js.map +1 -1
  83. package/lib/common/tools/handlers/undo-mcp-tool-handler.js +3 -2
  84. package/lib/common/tools/handlers/undo-mcp-tool-handler.js.map +1 -1
  85. package/lib/common/tools/handlers/validate-diagram-mcp-tool-handler.js +0 -0
  86. package/lib/common/tools/handlers/validate-diagram-mcp-tool-handler.js.map +1 -1
  87. package/lib/common/util/markdown-util.js +1 -2
  88. package/lib/common/util/markdown-util.js.map +1 -1
  89. package/lib/node/modules/node-mcp-server-module.js +8 -8
  90. package/lib/node/modules/node-mcp-server-module.js.map +1 -1
  91. package/package.json +17 -17
  92. package/src/common/modules/abstract-mcp-server-module.ts +3 -3
  93. package/src/common/resources/services/element-types-provider.ts +2 -1
  94. package/src/common/resources/services/mcp-model-serializer.ts +1 -2
  95. package/src/common/server/abstract-mcp-server-launcher.ts +3 -3
  96. package/src/common/server/glsp-mcp-server.ts +2 -1
  97. package/src/common/server/mcp-handler-shared.ts +2 -4
  98. package/src/common/server/mcp-mime-types.ts +1 -1
  99. package/src/common/server/mcp-options.ts +1 -1
  100. package/src/common/server/mcp-resource-handler.ts +1 -1
  101. package/src/common/server/abstract-mcp-server-launcher.spec.ts +0 -458
  102. package/src/common/server/glsp-mcp-server.spec.ts +0 -73
  103. package/src/common/server/lru-event-store.spec.ts +0 -121
  104. package/src/common/server/mcp-diagram-handler-dispatcher.spec.ts +0 -231
  105. package/src/common/server/mcp-handler-shared.spec.ts +0 -53
  106. package/src/common/server/mcp-id-alias-service.spec.ts +0 -106
  107. package/src/common/server/mcp-log-level-registry.spec.ts +0 -75
  108. package/src/common/server/mcp-logger.spec.ts +0 -235
  109. package/src/common/server/mcp-progress-reporter.spec.ts +0 -103
  110. package/src/common/server/mcp-tool-handler.spec.ts +0 -182
  111. package/src/common/tools/handlers/count-elements-mcp-tool-handler.spec.ts +0 -101
  112. package/src/common/tools/handlers/create-edges-mcp-tool-handler.spec.ts +0 -198
  113. package/src/common/tools/handlers/create-nodes-mcp-tool-handler.spec.ts +0 -199
  114. package/src/common/tools/handlers/query-elements-mcp-tool-handler.spec.ts +0 -212
  115. package/src/common/tools/handlers/session-info-mcp-tool-handler.spec.ts +0 -152
  116. package/src/common/tools/handlers/set-selection-mcp-tool-handler.spec.ts +0 -120
  117. package/src/common/tools/tool-annotations.spec.ts +0 -141
  118. package/src/node/server/mcp-http-transport-e2e.spec.ts +0 -297
  119. package/src/node/server/node-mcp-server-launcher.spec.ts +0 -184
  120. package/src/node/server/raw-http.spec.ts +0 -59
@@ -1,231 +0,0 @@
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
- });
@@ -1,53 +0,0 @@
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 { ClientSessionManager } from '@eclipse-glsp/server';
18
- import { expect } from 'chai';
19
- import { McpToolError, resolveActiveSessionId } from './mcp-handler-shared';
20
-
21
- function stubSessionManager(sessionIds: string[]): ClientSessionManager {
22
- return { getSessions: () => sessionIds.map(id => ({ id })) } as unknown as ClientSessionManager;
23
- }
24
-
25
- describe('resolveActiveSessionId', () => {
26
- it('returns the explicit session id when it matches an open session', () => {
27
- const result = resolveActiveSessionId(stubSessionManager(['alpha', 'beta']), 'alpha');
28
- expect(result).to.equal('alpha');
29
- });
30
-
31
- it('defaults to the only open session when sessionId is omitted', () => {
32
- const result = resolveActiveSessionId(stubSessionManager(['solo']), undefined);
33
- expect(result).to.equal('solo');
34
- });
35
-
36
- it('throws McpToolError listing the open sessions when ambiguous', () => {
37
- expect(() => resolveActiveSessionId(stubSessionManager(['session-a', 'session-b']), undefined)).to.throw(
38
- McpToolError,
39
- /Multiple sessions open.*session-a.*session-b/
40
- );
41
- });
42
-
43
- it('throws McpToolError when no sessions are open', () => {
44
- expect(() => resolveActiveSessionId(stubSessionManager([]), undefined)).to.throw(McpToolError, /No open diagram sessions/);
45
- });
46
-
47
- it('throws McpToolError when an explicit sessionId does not match any open session', () => {
48
- expect(() => resolveActiveSessionId(stubSessionManager(['real-session']), 'ghost')).to.throw(
49
- McpToolError,
50
- /Unknown sessionId: ghost/
51
- );
52
- });
53
- });
@@ -1,106 +0,0 @@
1
- /********************************************************************************
2
- * Copyright (c) 2026 EclipseSource and others.
3
- *
4
- * This program and the accompanying materials are made available under the
5
- * terms of the Eclipse Public License v. 2.0 which is available at
6
- * http://www.eclipse.org/legal/epl-2.0.
7
- *
8
- * This Source Code may also be made available under the following Secondary
9
- * Licenses when the conditions for such availability set forth in the Eclipse
10
- * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
- * with the GNU Classpath Exception which is available at
12
- * https://www.gnu.org/software/classpath/license.html.
13
- *
14
- * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
- ********************************************************************************/
16
-
17
- import { expect } from 'chai';
18
- import { DefaultMcpIdAliasService, NullMcpIdAliasService } from './mcp-id-alias-service';
19
-
20
- describe('DefaultMcpIdAliasService', () => {
21
- it('returns the same alias on repeated calls with the same id (round-trip stability)', () => {
22
- const service = new DefaultMcpIdAliasService();
23
-
24
- const aliasA = service.alias('uuid-a');
25
- const aliasA2 = service.alias('uuid-a');
26
- const aliasB = service.alias('uuid-b');
27
-
28
- expect(aliasA).to.equal(aliasA2);
29
- expect(aliasA).to.not.equal(aliasB);
30
- // Aliases are integer strings, starting at "1".
31
- expect(aliasA).to.match(/^\d+$/);
32
- expect(aliasB).to.match(/^\d+$/);
33
- });
34
-
35
- it('lookup(alias) returns the original id (round-trip)', () => {
36
- const service = new DefaultMcpIdAliasService();
37
-
38
- const alias = service.alias('uuid-foo');
39
- expect(service.lookup(alias)).to.equal('uuid-foo');
40
- });
41
-
42
- it('lookup(unknown) returns the input verbatim (best-effort fallback)', () => {
43
- const service = new DefaultMcpIdAliasService();
44
-
45
- // Unknown ids may come from manual user input, copy-paste, or earlier server-side
46
- // state. The service passes them through; downstream existence checks decide.
47
- expect(service.lookup('never-issued')).to.equal('never-issued');
48
- });
49
-
50
- it('skips alias candidates that collide with a known real id (no shadowing)', () => {
51
- // Regression: pre-fix, alias() always handed out sequential integers starting at "1".
52
- // A model element whose actual id was "1" would then be shadowed — `lookup("1")`
53
- // resolved to the *aliased* real id rather than passing through to the real "1".
54
- // The service now records every real id seen via alias() and skips counter values
55
- // that would collide.
56
- const service = new DefaultMcpIdAliasService();
57
- const aliasOf1 = service.alias('1');
58
- const aliasOfX = service.alias('uuid-other');
59
-
60
- expect(aliasOf1).to.not.equal('1');
61
- expect(aliasOfX).to.not.equal('1');
62
- expect(service.lookup('1')).to.equal('1');
63
- expect(service.lookup(aliasOf1)).to.equal('1');
64
- expect(service.lookup(aliasOfX)).to.equal('uuid-other');
65
-
66
- // Multiple pre-known real ids: every issued alias is outside the known-real set.
67
- const service2 = new DefaultMcpIdAliasService();
68
- const knownReals = ['1', '2', '3'];
69
- knownReals.forEach(id => service2.alias(id));
70
- const fresh = service2.alias('uuid-fresh');
71
- expect(knownReals).to.not.include(fresh);
72
- });
73
-
74
- it('keeps independent counters and maps across separate instances (per-session isolation)', () => {
75
- // Adopters get one instance per GLSP session; aliases must not bleed between sessions.
76
- const sessionA = new DefaultMcpIdAliasService();
77
- const sessionB = new DefaultMcpIdAliasService();
78
-
79
- const aliasA1 = sessionA.alias('uuid-x');
80
- const aliasA2 = sessionA.alias('uuid-y');
81
- const aliasB1 = sessionB.alias('uuid-z');
82
-
83
- // Counters are independent: B's first alias is "1", same as A's first.
84
- expect(aliasA1).to.equal('1');
85
- expect(aliasA2).to.equal('2');
86
- expect(aliasB1).to.equal('1');
87
-
88
- // Bleed-isolation: alias "1" in B resolves to uuid-z, NOT to uuid-x (A's "1").
89
- expect(sessionA.lookup('1')).to.equal('uuid-x');
90
- expect(sessionB.lookup('1')).to.equal('uuid-z');
91
-
92
- // Unknown ids in either session fall through to the input verbatim.
93
- expect(sessionA.lookup('3')).to.equal('3');
94
- expect(sessionB.lookup('2')).to.equal('2');
95
- });
96
- });
97
-
98
- describe('NullMcpIdAliasService', () => {
99
- it('alias and lookup return the argument unchanged', () => {
100
- const service = new NullMcpIdAliasService();
101
-
102
- expect(service.alias('uuid-foo')).to.equal('uuid-foo');
103
- expect(service.lookup('uuid-foo')).to.equal('uuid-foo');
104
- expect(service.lookup('never-seen')).to.equal('never-seen');
105
- });
106
- });
@@ -1,75 +0,0 @@
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
- });