Skip to content

Commit 98d9088

Browse files
feat(server-mcp): introduce Model Context Protocol integration
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>
1 parent 87c6bcf commit 98d9088

109 files changed

Lines changed: 11513 additions & 159 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/generate-changelog/SKILL.md

Lines changed: 60 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ description: Generate changelog entries from merged PRs since the last release.
88
Generate changelog entries by analyzing merged PRs since the last release.
99

1010
Execute these phases in order:
11+
1112
1. **Data Gathering** — find last release, fetch PRs, classify, generate entries
1213
2. **Changelog Update** — write entries into CHANGELOG.md
1314
3. **Review & Approval** — present the actual diff to the user for review
@@ -20,11 +21,13 @@ Execute these phases in order:
2021
### Step 1.1: Find the latest release tag
2122

2223
Run:
24+
2325
```bash
2426
git tag --sort=-creatordate | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1
2527
```
2628

2729
Record as `LAST_TAG`. Get the tag's date:
30+
2831
```bash
2932
git log -1 --format=%aI $LAST_TAG
3033
```
@@ -46,12 +49,13 @@ Use the date portion only from `TAG_DATE` (e.g. `2026-02-09`).
4649
### Step 1.4: Filter PRs
4750

4851
**Skip rules** (in order):
52+
4953
1. PR has the `changelog` label → skip (already tracked in a previous changelog update)
5054
2. Author login is `dependabot` or `dependabot[bot]` → skip
5155
3. Title matches version bump patterns → skip:
52-
- Starts with `Switch to` and contains `-next`
53-
- Title is a bare version like `vX.Y.Z`
54-
- Title starts with `Release v`
56+
- Starts with `Switch to` and contains `-next`
57+
- Title is a bare version like `vX.Y.Z`
58+
- Title starts with `Release v`
5559
4. Title contains `update changelog` (case insensitive) → skip
5660
5. Title is purely CI/metadata (readme badges, workflow config) AND body does NOT contain `[x] This PR should be mentioned in the changelog` → skip
5761

@@ -62,9 +66,9 @@ Use the date portion only from `TAG_DATE` (e.g. `2026-02-09`).
6266
1. If body contains `[x] This PR introduces a breaking change`**breaking**
6367
2. If body contains `[ ] This PR introduces a breaking change`**normal**
6468
3. If no checkbox info, analyze title and body:
65-
- Breaking keywords: "refactor", "rename", "remove", "replace", "migrate", "breaking", "deprecate"
66-
- Clearly non-breaking (bug fix, docs, minor enhancement) → **normal**
67-
- Uncertain → flag for user review
69+
- Breaking keywords: "refactor", "rename", "remove", "replace", "migrate", "breaking", "deprecate"
70+
- Clearly non-breaking (bug fix, docs, minor enhancement) → **normal**
71+
- Uncertain → flag for user review
6872

6973
### Step 1.6: Assign category tags
7074

@@ -75,57 +79,65 @@ Pick the most fitting tag from the vocabulary (Step 1.2) based on PR title and b
7579
#### Entry Format
7680

7781
**Normal changes:**
82+
7883
```
7984
- [tag] Description [#N](https://github.com/OWNER/REPO/pull/N)
8085
```
8186

8287
**Breaking changes** with migration sub-items:
88+
8389
```
8490
- [tag] Description [#N](https://github.com/OWNER/REPO/pull/N)
8591
- Migration detail 1
8692
- Migration detail 2
8793
```
8894

8995
**Multiple PRs for the same change:**
96+
9097
```
9198
- [tag] Description [#N](url) [#M](url)
9299
```
93100

94101
#### Style Guide
95102

96103
**Formatting:**
97-
- Entry prefix: `- ` (dash + exactly 3 spaces)
98-
- Sub-item indent: 4 spaces + `- ` (4 spaces from parent dash)
99-
- Sub-sub-item indent: 8 spaces + `- `
100-
- Single space between `[tag]` and description text
101-
- Single space before PR link at end of line
102-
- PR links are mandatory, full URLs: `[#123](https://github.com/OWNER/REPO/pull/123)`
104+
105+
- Entry prefix: `- ` (dash + exactly 3 spaces)
106+
- Sub-item indent: 4 spaces + `- ` (4 spaces from parent dash)
107+
- Sub-sub-item indent: 8 spaces + `- `
108+
- Single space between `[tag]` and description text
109+
- Single space before PR link at end of line
110+
- PR links are mandatory, full URLs: `[#123](https://github.com/OWNER/REPO/pull/123)`
103111

104112
**Wording:**
105-
- Always start with a **present tense imperative verb** (not past tense)
106-
- Common verbs: Fix, Improve, Add, Update, Extend, Ensure, Introduce, Remove, Refactor, Rename, Provide, Allow, Support
107-
- **Bug fixes**: "Fix a bug that caused/prevented...", "Fix X behavior"
108-
- **Features**: "Introduce...", "Add support for...", "Provide..."
109-
- **Enhancements**: "Improve...", "Extend...", "Ensure that..."
110-
- **Refactors**: "Refactor...", "Rework...", "Rename..."
111-
- Be specific — never "Fix various issues"
113+
114+
- Always start with a **present tense imperative verb** (not past tense)
115+
- Common verbs: Fix, Improve, Add, Update, Extend, Ensure, Introduce, Remove, Refactor, Rename, Provide, Allow, Support
116+
- **Bug fixes**: "Fix a bug that caused/prevented...", "Fix X behavior"
117+
- **Features**: "Introduce...", "Add support for...", "Provide..."
118+
- **Enhancements**: "Improve...", "Extend...", "Ensure that..."
119+
- **Refactors**: "Refactor...", "Rework...", "Rename..."
120+
- Be specific — never "Fix various issues"
112121

113122
**Capitalization:**
114-
- Tags are always lowercase: `[diagram]`, not `[Diagram]`
115-
- Description starts lowercase after the tag (unless proper noun or code element)
116-
- Section headers: Title Case (`### Potentially Breaking Changes`)
123+
124+
- Tags are always lowercase: `[diagram]`, not `[Diagram]`
125+
- Description starts lowercase after the tag (unless proper noun or code element)
126+
- Section headers: Title Case (`### Potentially Breaking Changes`)
117127

118128
**Description cleanup from PR title:**
119-
- Remove issue tracker prefixes (e.g. `GLSP-1234:`, `GH-123:`, `ISSUE-456:`)
120-
- Remove conventional commit prefixes: `fix:`, `feat:`, `chore:`
121-
- Rephrase bug-report style to changelog style:
122-
- BAD: "Edit label UI does not resize on graph zoom"
123-
- GOOD: "Fix edit label UI not resizing on graph zoom"
124-
- Keep concise — one line
129+
130+
- Remove issue tracker prefixes (e.g. `GLSP-1234:`, `GH-123:`, `ISSUE-456:`)
131+
- Remove conventional commit prefixes: `fix:`, `feat:`, `chore:`
132+
- Rephrase bug-report style to changelog style:
133+
- BAD: "Edit label UI does not resize on graph zoom"
134+
- GOOD: "Fix edit label UI not resizing on graph zoom"
135+
- Keep concise — one line
125136

126137
**Breaking changes:**
127-
- Describe what changed, why it's breaking, and how to migrate
128-
- Extract migration sub-items from the PR body's "What it does" section
138+
139+
- Describe what changed, why it's breaking, and how to migrate
140+
- Extract migration sub-items from the PR body's "What it does" section
129141

130142
---
131143

@@ -136,13 +148,15 @@ Pick the most fitting tag from the vocabulary (Step 1.2) based on PR title and b
136148
Read `CHANGELOG.md` in the repository root.
137149

138150
**Active section detection:**
139-
- An active section has the `- active` suffix (e.g. `## v2.7.0 - active`)
140-
- If an active section exists → merge new entries into it
141-
- If the topmost section is a released version (no `- active` suffix) → create a new active section above it
151+
152+
- An active section has the `- active` suffix (e.g. `## v2.7.0 - active`)
153+
- If an active section exists → merge new entries into it
154+
- If the topmost section is a released version (no `- active` suffix) → create a new active section above it
142155

143156
**Creating a new section:**
144-
- Bump the minor version of `LAST_TAG` (e.g. `v2.6.0``v2.7.0`)
145-
- Insert after the title line, before the first `## ` heading:
157+
158+
- Bump the minor version of `LAST_TAG` (e.g. `v2.6.0``v2.7.0`)
159+
- Insert after the title line, before the first `## ` heading:
146160

147161
```markdown
148162
## v2.7.0 - active
@@ -160,9 +174,10 @@ Read `CHANGELOG.md` in the repository root.
160174
Only include "Potentially Breaking Changes" if there are breaking entries.
161175

162176
**Merging into existing active section:**
163-
- Check PR numbers against existing entries to avoid duplicates
164-
- Append new entries to the appropriate subsection
165-
- Create missing subsections as needed
177+
178+
- Check PR numbers against existing entries to avoid duplicates
179+
- Append new entries to the appropriate subsection
180+
- Create missing subsections as needed
166181

167182
### Step 2.2: Write the updated CHANGELOG.md
168183

@@ -185,13 +200,14 @@ Present the diff to the user.
185200
List any entries flagged as uncertain (category or breaking status) and ask the user to resolve them.
186201

187202
Even if nothing is uncertain, ask:
203+
188204
> "Does everything look correct, or would you like to adjust any entries?"
189205
190206
### Step 3.3: Collect user feedback
191207

192-
- **Approve as-is** → done (or proceed to Phase 4 if PR was requested)
193-
- **Request edits** → apply changes, show updated diff, ask again
194-
- **Resolve uncertain items** → apply, show updated diff
208+
- **Approve as-is** → done (or proceed to Phase 4 if PR was requested)
209+
- **Request edits** → apply changes, show updated diff, ask again
210+
- **Resolve uncertain items** → apply, show updated diff
195211

196212
**Do NOT proceed to Phase 4 unless the user explicitly requests a PR.**
197213

@@ -200,11 +216,13 @@ Even if nothing is uncertain, ask:
200216
## Phase 4: PR Creation (Optional)
201217

202218
Only execute this phase if the user explicitly requests a PR (either in their initial prompt or after reviewing the changelog). If the user hasn't mentioned a PR, ask after approval:
219+
203220
> "Would you like me to create a PR for this changelog update, or are you done?"
204221
205222
### Step 4.1: Determine the branch name
206223

207224
Check if `changelog-update` exists on remote:
225+
208226
```bash
209227
git ls-remote --heads origin changelog-update
210228
```
@@ -229,6 +247,7 @@ Report the PR URL.
229247
### Step 4.4: Label referenced PRs
230248

231249
Add the `changelog` label to every PR mentioned in the new entries:
250+
232251
```bash
233252
gh pr edit PR_NUMBER --add-label "changelog"
234253
```

eslint.config.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ export default [
2222
rules: {
2323
'@typescript-eslint/no-shadow': 'off',
2424
'@typescript-eslint/padding-line-between-statements': 'off',
25+
// The MCP SDK uses `exports` subpath patterns with explicit `.js` suffixes (e.g.
26+
// `@modelcontextprotocol/sdk/server/mcp.js`). The TypeScript import resolver does
27+
// not match these against the `./*` wildcard, even though tsc and Node resolve
28+
// them correctly at compile- and runtime.
29+
'import-x/no-unresolved': ['error', { ignore: ['^@modelcontextprotocol/sdk/'] }],
2530
'no-restricted-imports': [
2631
'warn',
2732
{

examples/workflow-server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"dependencies": {
5959
"@eclipse-glsp/layout-elk": "2.7.0-next",
6060
"@eclipse-glsp/server": "2.7.0-next",
61+
"@eclipse-glsp/server-mcp": "2.7.0-next",
6162
"inversify": "^6.1.3"
6263
},
6364
"devDependencies": {

examples/workflow-server/src/common/graph-extension.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/********************************************************************************
2-
* Copyright (c) 2022-2023 STMicroelectronics and others.
2+
* Copyright (c) 2022-2026 STMicroelectronics and others.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -86,7 +86,7 @@ export class TaskNodeBuilder<T extends TaskNode = TaskNode> extends GNodeBuilder
8686
protected createCompartmentHeader(): GLabel {
8787
return new GLabelBuilder(GLabel)
8888
.type(ModelTypes.LABEL_HEADING)
89-
.id(this.proxy.id + '_classname')
89+
.id(this.proxy.id + '_label')
9090
.text(this.proxy.name)
9191
.build();
9292
}
@@ -151,7 +151,7 @@ export class CategoryNodeBuilder<T extends Category = Category> extends Activity
151151
protected createCompartmentHeader(): GLabel {
152152
return new GLabelBuilder(GLabel)
153153
.type(ModelTypes.LABEL_HEADING)
154-
.id(this.proxy.id + '_classname')
154+
.id(this.proxy.id + '_label')
155155
.text(this.proxy.name)
156156
.build();
157157
}

examples/workflow-server/src/common/handler/create-decision-node-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/********************************************************************************
2-
* Copyright (c) 2022-2024 STMicroelectronics and others.
2+
* Copyright (c) 2022-2026 STMicroelectronics and others.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at

examples/workflow-server/src/common/handler/create-merge-node-handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/********************************************************************************
2-
* Copyright (c) 2022-2024 STMicroelectronics and others.
2+
* Copyright (c) 2022-2026 STMicroelectronics and others.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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 { DefaultTypes } from '@eclipse-glsp/server';
18+
import { ElementTypeEntry, ElementTypes, ElementTypesProvider } from '@eclipse-glsp/server-mcp';
19+
import { injectable } from 'inversify';
20+
import { ModelTypes } from '../util/model-types';
21+
22+
const NODE_TYPES: ElementTypeEntry[] = [
23+
{ id: ModelTypes.AUTOMATED_TASK, label: 'Automated Task', description: 'Task without human input', acceptsText: true },
24+
{ id: ModelTypes.MANUAL_TASK, label: 'Manual Task', description: 'Task done by a human', acceptsText: true },
25+
{ id: ModelTypes.JOIN_NODE, label: 'Join Node', description: 'Gateway that merges parallel flows', acceptsText: false },
26+
{ id: ModelTypes.FORK_NODE, label: 'Fork Node', description: 'Gateway that splits into parallel flows', acceptsText: false },
27+
{ id: ModelTypes.MERGE_NODE, label: 'Merge Node', description: 'Gateway that merges alternative flows', acceptsText: false },
28+
{ id: ModelTypes.DECISION_NODE, label: 'Decision Node', description: 'Gateway that splits into alternative flows', acceptsText: false },
29+
{ id: ModelTypes.CATEGORY, label: 'Category', description: 'Container node that groups other elements', acceptsText: true }
30+
];
31+
32+
const EDGE_TYPES: ElementTypeEntry[] = [
33+
{ id: DefaultTypes.EDGE, label: 'Edge', description: 'Standard control flow edge', acceptsText: false },
34+
{
35+
id: ModelTypes.WEIGHTED_EDGE,
36+
label: 'Weighted Edge',
37+
description: 'Edge that indicates a weighted probability. Typically used with a Decision Node.',
38+
acceptsText: false
39+
}
40+
];
41+
42+
/**
43+
* Workflow-specific {@link ElementTypesProvider}. Returns the constant set of creatable types
44+
* with richer LLM-facing fields (`description`, `acceptsText`) than the default registry-scrape
45+
* impl can infer. Bound on the workflow MCP diagram module via `bindElementTypesProvider()`;
46+
* the standard `element-types` tool handler exposes the full entries via `structuredContent`
47+
* (with a short summary in the text content) — no handler rebind needed.
48+
*/
49+
@injectable()
50+
export class WorkflowElementTypesProvider implements ElementTypesProvider {
51+
get(): ElementTypes {
52+
return { nodeTypes: NODE_TYPES, edgeTypes: EDGE_TYPES };
53+
}
54+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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 { DefaultMcpLabelProvider } from '@eclipse-glsp/server-mcp';
19+
import { injectable } from 'inversify';
20+
import { ModelTypes } from '../util/model-types';
21+
22+
/**
23+
* Workflow-specific {@link DefaultMcpLabelProvider}: category labels are nested inside a
24+
* compartment-header child rather than directly under the category, so the default
25+
* direct-child lookup misses them. Other workflow element types fall through to the
26+
* inherited default.
27+
*/
28+
@injectable()
29+
export class WorkflowMcpLabelProvider extends DefaultMcpLabelProvider {
30+
override getLabel(element: GModelElement): GLabel | undefined {
31+
if (element.type === ModelTypes.CATEGORY) {
32+
const header = element.children.find(child => child.type === ModelTypes.COMP_HEADER);
33+
return header?.children.find((child): child is GLabel => child instanceof GLabel);
34+
}
35+
return super.getLabel(element);
36+
}
37+
}

0 commit comments

Comments
 (0)