Add support for Model Context Protocol#120
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds Model Context Protocol (MCP) support to the GLSP server, enabling AI assistants and other MCP clients to interact with GLSP diagrams through a standardized protocol. The implementation provides HTTP-based MCP server functionality with default tools for diagram manipulation and resources for querying diagram state.
Key changes:
- Introduces new
@eclipse-glsp/server-mcppackage with MCP server infrastructure, HTTP transport layer, and default tools/resources for diagram interaction - Extends GLSP server initialization to support contributions via
GLSPServerInitContributioninterface - Updates workflow example to demonstrate MCP integration
Reviewed changes
Copilot reviewed 19 out of 21 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/server/src/common/session/client-session-manager.ts | Adds getSessions() method to retrieve all active client sessions |
| packages/server/src/common/protocol/glsp-server.ts | Introduces GLSPServerInitContribution mechanism and deprecates handleInitializeArgs |
| packages/server/src/common/di/server-module.ts | Adds binding configuration for GLSPServerInitContribution |
| packages/server-mcp/tsconfig.json | TypeScript configuration for new MCP package |
| packages/server-mcp/src/mcp-util.ts | Utility functions for MCP parameter extraction and result formatting |
| packages/server-mcp/src/mcp-server-manager.ts | Core MCP server lifecycle management and HTTP server initialization |
| packages/server-mcp/src/mcp-server-contribution.ts | Interface for extending MCP server with custom tools and resources |
| packages/server-mcp/src/index.ts | Package exports |
| packages/server-mcp/src/http-server-with-sessions.ts | HTTP server implementation with MCP session management |
| packages/server-mcp/src/di.config.ts | Dependency injection configuration for MCP module |
| packages/server-mcp/src/default-mcp-tool-contribution.ts | Default MCP tools for diagram validation, element creation, undo/redo, and save operations |
| packages/server-mcp/src/default-mcp-resource-contribution.ts | Default MCP resources for querying sessions, diagram types, element types, and models |
| packages/server-mcp/package.json | Package metadata and dependencies for MCP package |
| packages/server-mcp/.eslintrc.js | ESLint configuration ignoring MCP SDK imports |
| examples/workflow-server/tsconfig.json | Adds reference to server-mcp package |
| examples/workflow-server/src/node/app.ts | Integrates MCP module into workflow server |
| examples/workflow-server/src/common/workflow-glsp-server.ts | Migrates from deprecated handleInitializeArgs to GLSPServerInitContribution |
| examples/workflow-server/src/common/workflow-diagram-module.ts | Updates binding to use new init contribution pattern |
| examples/workflow-server/package.json | Adds dependency on server-mcp package |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
fd94922 to
05c8fc5
Compare
84f5685 to
6fec69a
Compare
Exposes each GLSP server as an MCP server over Streamable HTTP, so LLM clients can query and mutate diagrams via MCP resources, tools, and prompts. Architecture - One MCP endpoint per GLSP server process; under per-window deployment, one endpoint per application instance. - Auto-discovers diagram-scoped contributions from all GLSP client sessions and merges them into a shared surface with cross-session ID aliasing. - Pluggable model-serializer, label-provider, and element-types extension points for diagram-specific overrides. - Opt-in: started only when configured on initialize. - Random port by default; the announced URL is surfaced for adopter discovery. - No built-in auth; loopback-only unless explicitly acknowledged. - Targets MCP spec 2025-06-18 via the official SDK. Adopters - Diagram module: register language-specific tools, prompts, resources, and override the diagram extension points. - Server module: configure server-wide options (port, route, auth acknowledgement). - The workflow server example wires both end-to-end. Server framework - Adds an initialize-contribution extension point on the default GLSP server, used by MCP to surface configuration on initialize. The previous `handleInitializeArgs` hook is deprecated — adopters subclassing the default server should migrate. Documentation - Adopter README plus a separate architecture document covering the feature matrix, lifecycle, extension points, and rationale. Misc - Small fix to a base type-guard on edges in the graph package. - Disposes the server instance when the JSON-RPC client connection closes uncleanly (browser/IDE force-close). - Action dispatcher drops stale response actions arriving without a registered handler instead of throwing. Part of eclipse-glsp/glsp#1546 Co-authored-by: Andreas Hell <44035624+Sakrafux@users.noreply.github.com>
6fec69a to
98d9088
Compare
tortmayr
left a comment
There was a problem hiding this comment.
Thanks for the rework Martin.
In general the code looks good to me.
I have a couple of inline comments.
In addition, we should probably create follow-up issues for the following tasks
-
Java alignment/implementation. Not planned in yet from our side, but we should open the issue nevertheless for tracking. (tag with help wanted, looking for sponsor)
-
Once this is merged we should update the protocol doc on the website
-
It seems like we have a couple of concepts in place (initializers, factories) which sole purpose is to bypass inversify circular dependencies for contribution points. We should consider an alignmnet here and use the
LazyInjectorapproach consistently (same as in client)
|
|
||
| @inject(GLSPMcpServerFactory) protected glspMcpServerFactory: GLSPMcpServerFactory; | ||
|
|
||
| @inject(McpDiagramHandlerDispatcher) protected dispatcher: DefaultMcpDiagramHandlerDispatcher; |
There was a problem hiding this comment.
Weird mix of symbol injection and direct class typing.
Should probably create an interface for the McpDiagramHandlerDispatcher and use it here.
Alternatively, if you dont want to interface this consider renaming to McpDiagramHandlerDispatcher and directly using the class as service identifier
| }); | ||
| } | ||
|
|
||
| protected dispatchStaticDiagramRead(name: string, uri: string): Promise<ReadResourceResult> { |
| () => | ||
| this.ping().catch(err => { | ||
| if (!(err instanceof McpError) || err.code !== ErrorCode.RequestTimeout) { | ||
| console.debug('MCP keep-alive ping failed:', err); |
There was a problem hiding this comment.
Consider injecting and using the logger here instead of plain console.log
| return new GLabelBuilder(GLabel) | ||
| .type(ModelTypes.LABEL_HEADING) | ||
| .id(this.proxy.id + '_classname') | ||
| .id(this.proxy.id + '_label') |
There was a problem hiding this comment.
Question: Should we update the example1.wf file on the client side to reflect this change?
Or is is purely cosmetically?
| /** Best-effort fan-out — failures on individual MCP sessions (e.g. transport mid-close) are swallowed. */ | ||
| protected broadcastResourceListChanged(): void { | ||
| for (const glspMcpServer of this.sessionServers.values()) { | ||
| glspMcpServer |
There was a problem hiding this comment.
SHould we directly expose this on the GLSPMcpServer TopLevel ?
Or is this a one time use, and we don't expect adopters to need the same functionality?
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
| ********************************************************************************/ | ||
|
|
||
| import { |
There was a problem hiding this comment.
Double check comments, trim fluff.
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
| ********************************************************************************/ | ||
|
|
||
| import * as http from 'http'; |
There was a problem hiding this comment.
Should be in a .spec.ts file. Otherwise it gets shipped as part of the source code
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
| ********************************************************************************/ | ||
|
|
||
| import { ApplyLabelEditOperation, CreateNodeOperation } from '@eclipse-glsp/server'; |
There was a problem hiding this comment.
Should this file be tested as well?
| } | ||
| } | ||
|
|
||
| export namespace CreateNodeOperationHandler { |
There was a problem hiding this comment.
Place the namespace alongside the corresponding interface
| try { | ||
| result = await initializer.initializeServer(this, params, result); | ||
| } catch (error: unknown) { | ||
| this.logger.error(`Error during server initialization from ${initializer.constructor.name}:`, error); |
There was a problem hiding this comment.
Catch without rethrow breaks promise resolution.
We catch all errors -> promise returned is never rejected
What it does
Exposes each GLSP server as an MCP server over Streamable HTTP, so LLM
clients can query and mutate diagrams via MCP resources, tools, and
prompts.
Architecture
deployment, one endpoint per application instance.
sessions and merges them into a shared surface with cross-session
ID aliasing.
extension points for diagram-specific overrides.
discovery.
Adopters
resources, and override the diagram extension points.
acknowledgement).
Server framework
GLSP server, used by MCP to surface configuration on initialize.
The previous
handleInitializeArgshook is deprecated — adopterssubclassing the default server should migrate.
Documentation
feature matrix, lifecycle, extension points, and rationale.
Misc
closes uncleanly (browser/IDE force-close).
registered handler instead of throwing.
Part of eclipse-glsp/glsp#1546
Requires eclipse-glsp/glsp-client#456
How to test
mcpServerconfiguration[McpServerManager] MCP server 'glspMcpServer' is ready to accept new client requests on: http://127.0.0.1:64577/glsp-mcpFollow-ups
Changelog