@likec4/language-server 1.36.1 → 1.38.0

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 (94) hide show
  1. package/dist/LikeC4LanguageServices.d.ts +43 -7
  2. package/dist/LikeC4LanguageServices.js +51 -11
  3. package/dist/Rpc.js +22 -6
  4. package/dist/browser.d.ts +1 -1
  5. package/dist/browser.js +1 -1
  6. package/dist/bundled.mjs +4258 -3083
  7. package/dist/config/schema.d.ts +1 -1
  8. package/dist/config/schema.js +1 -1
  9. package/dist/empty.d.ts +2 -0
  10. package/dist/empty.js +1 -0
  11. package/dist/filesystem/ChokidarWatcher.d.ts +14 -0
  12. package/dist/filesystem/ChokidarWatcher.js +64 -0
  13. package/dist/filesystem/FileSystemWatcher.d.ts +19 -0
  14. package/dist/filesystem/FileSystemWatcher.js +11 -0
  15. package/dist/filesystem/LikeC4FileSystem.d.ts +5 -0
  16. package/dist/filesystem/LikeC4FileSystem.js +56 -0
  17. package/dist/filesystem/index.d.ts +20 -0
  18. package/dist/filesystem/index.js +16 -0
  19. package/dist/index.d.ts +18 -4
  20. package/dist/index.js +23 -10
  21. package/dist/likec4lib.d.ts +1 -1
  22. package/dist/lsp/DocumentLinkProvider.js +3 -3
  23. package/dist/lsp/DocumentSymbolProvider.js +1 -1
  24. package/dist/mcp/{sseserver/MCPServerFactory.d.ts → MCPServerFactory.d.ts} +1 -1
  25. package/dist/mcp/MCPServerFactory.js +69 -0
  26. package/dist/mcp/NoopLikeC4MCPServer.d.ts +4 -10
  27. package/dist/mcp/NoopLikeC4MCPServer.js +5 -10
  28. package/dist/mcp/interfaces.d.ts +7 -5
  29. package/dist/mcp/interfaces.js +4 -0
  30. package/dist/mcp/server/StdioLikeC4MCPServer.d.ts +16 -0
  31. package/dist/mcp/server/StdioLikeC4MCPServer.js +43 -0
  32. package/dist/mcp/{sseserver/MCPServer.d.ts → server/StreamableLikeC4MCPServer.d.ts} +3 -2
  33. package/dist/mcp/server/StreamableLikeC4MCPServer.js +156 -0
  34. package/dist/mcp/server/WithMCPServer.d.ts +2 -0
  35. package/dist/mcp/server/WithMCPServer.js +57 -0
  36. package/dist/mcp/tools/_common.d.ts +24 -5
  37. package/dist/mcp/tools/_common.js +31 -3
  38. package/dist/mcp/tools/find-relationships.d.ts +13 -0
  39. package/dist/mcp/tools/find-relationships.js +151 -0
  40. package/dist/mcp/tools/list-projects.js +42 -14
  41. package/dist/mcp/tools/open-view.d.ts +4 -3
  42. package/dist/mcp/tools/open-view.js +37 -14
  43. package/dist/mcp/tools/{read-project-elements.d.ts → read-deployment.d.ts} +6 -3
  44. package/dist/mcp/tools/read-deployment.js +130 -0
  45. package/dist/mcp/tools/read-element.d.ts +4 -3
  46. package/dist/mcp/tools/read-element.js +114 -51
  47. package/dist/mcp/tools/read-project-summary.d.ts +3 -2
  48. package/dist/mcp/tools/read-project-summary.js +141 -34
  49. package/dist/mcp/tools/read-view.d.ts +4 -3
  50. package/dist/mcp/tools/read-view.js +146 -105
  51. package/dist/mcp/tools/search-element.js +81 -30
  52. package/dist/mcp/utils.js +7 -4
  53. package/dist/model/builder/buildModel.d.ts +1 -1
  54. package/dist/model/builder/buildModel.js +4 -6
  55. package/dist/model/model-parser.d.ts +9 -9
  56. package/dist/model/model-parser.js +3 -0
  57. package/dist/model/parser/Base.d.ts +1 -1
  58. package/dist/model/parser/Base.js +1 -1
  59. package/dist/model/parser/DeploymentModelParser.d.ts +1 -1
  60. package/dist/model/parser/DeploymentViewParser.d.ts +1 -1
  61. package/dist/model/parser/DeploymentViewParser.js +2 -2
  62. package/dist/model/parser/FqnRefParser.d.ts +1 -1
  63. package/dist/model/parser/FqnRefParser.js +8 -1
  64. package/dist/model/parser/GlobalsParser.d.ts +1 -1
  65. package/dist/model/parser/ImportsParser.d.ts +1 -1
  66. package/dist/model/parser/ModelParser.d.ts +1 -1
  67. package/dist/model/parser/PredicatesParser.d.ts +1 -1
  68. package/dist/model/parser/SpecificationParser.d.ts +1 -1
  69. package/dist/model/parser/ViewsParser.d.ts +1 -1
  70. package/dist/model/parser/ViewsParser.js +3 -3
  71. package/dist/module.d.ts +13 -9
  72. package/dist/module.js +28 -30
  73. package/dist/protocol.d.ts +18 -4
  74. package/dist/protocol.js +5 -1
  75. package/dist/test/testServices.d.ts +5 -2
  76. package/dist/test/testServices.js +7 -3
  77. package/dist/validation/DocumentValidator.d.ts +11 -0
  78. package/dist/validation/DocumentValidator.js +16 -0
  79. package/dist/validation/index.d.ts +1 -1
  80. package/dist/validation/index.js +1 -0
  81. package/dist/workspace/LangiumDocuments.d.ts +1 -0
  82. package/dist/workspace/LangiumDocuments.js +10 -1
  83. package/dist/workspace/ProjectsManager.d.ts +35 -17
  84. package/dist/workspace/ProjectsManager.js +168 -54
  85. package/dist/workspace/WorkspaceManager.d.ts +9 -2
  86. package/dist/workspace/WorkspaceManager.js +31 -40
  87. package/package.json +14 -10
  88. package/dist/LikeC4FileSystem.d.ts +0 -14
  89. package/dist/LikeC4FileSystem.js +0 -39
  90. package/dist/mcp/sseserver/MCPServer.js +0 -80
  91. package/dist/mcp/sseserver/MCPServerFactory.js +0 -50
  92. package/dist/mcp/sseserver/WithMCPServer.d.ts +0 -9
  93. package/dist/mcp/sseserver/WithMCPServer.js +0 -53
  94. package/dist/mcp/tools/read-project-elements.js +0 -93
@@ -1,9 +1,6 @@
1
- import { invariant } from "@likec4/core";
2
1
  import z from "zod";
3
- import { safeCall } from "../../utils/index.js";
4
- import { ProjectsManager } from "../../workspace/index.js";
5
2
  import { likec4Tool } from "../utils.js";
6
- import { locationSchema } from "./_common.js";
3
+ import { locationSchema, mkLocate, projectIdSchema } from "./_common.js";
7
4
  const modelRef = (node) => {
8
5
  if (node.hasElement()) {
9
6
  return node.element.id;
@@ -13,152 +10,196 @@ const modelRef = (node) => {
13
10
  }
14
11
  return null;
15
12
  };
13
+ const nodeSchema = z.discriminatedUnion("type", [
14
+ z.object({
15
+ type: z.literal("element"),
16
+ id: z.string().describe("Node ID"),
17
+ elementId: z.string().describe("Element ID (FQN)"),
18
+ kind: z.string().describe("Element kind"),
19
+ title: z.string().describe("Node title"),
20
+ description: z.string().nullable(),
21
+ technology: z.string().nullable(),
22
+ children: z.array(z.string()).describe("Children nodes, array of node IDs"),
23
+ shape: z.string().describe("Rendered shape"),
24
+ color: z.string().describe("Rendered color"),
25
+ tags: z.array(z.string())
26
+ }),
27
+ z.object({
28
+ type: z.literal("deployment-node"),
29
+ id: z.string().describe("Node ID"),
30
+ deploymentId: z.string().describe("Deployment entity ID (FQN)"),
31
+ kind: z.string().describe("Deployment kind"),
32
+ title: z.string().describe("Node title"),
33
+ description: z.string().nullable(),
34
+ technology: z.string().nullable(),
35
+ children: z.array(z.string()).describe("Children nodes, array of node IDs"),
36
+ shape: z.string().describe("Rendered shape"),
37
+ color: z.string().describe("Rendered color"),
38
+ tags: z.array(z.string())
39
+ }),
40
+ z.object({
41
+ type: z.literal("deployed-instance"),
42
+ id: z.string().describe("Node ID"),
43
+ deploymentId: z.string().describe("Deployment entity ID (FQN)"),
44
+ title: z.string().describe("Node title"),
45
+ description: z.string().nullable(),
46
+ technology: z.string().nullable(),
47
+ referencedElement: z.object({
48
+ id: z.string().describe("Element ID (FQN)"),
49
+ kind: z.string().describe("Element kind"),
50
+ title: z.string().describe("Element title")
51
+ }),
52
+ shape: z.string().describe("Rendered shape"),
53
+ color: z.string().describe("Rendered color"),
54
+ tags: z.array(z.string())
55
+ })
56
+ ]);
16
57
  export const readView = likec4Tool({
17
58
  name: "read-view",
18
59
  description: `
19
- Returns information about LikeC4 view, includes:
20
- - id (view name)
21
- - type (element, deployment, dynamic)
22
- - title, description, tags
23
- - project name this view belongs to
24
- - array of elements included in this view
25
- - array of relationships in this view (source, target, title, description, technology, tags)
26
- - viewOf (element id this view is the default view of)
27
- - source location (if running in the editor)
28
- `.trimStart(),
60
+ Read detailed information about a LikeC4 view.
61
+
62
+ Request:
63
+ - viewId: string \u2014 view id (name)
64
+ - project: string (optional) \u2014 project id. Defaults to "default" if omitted.
65
+
66
+ Response (JSON object):
67
+ - id: string \u2014 view id
68
+ - type: "element" | "deployment" | "dynamic" \u2014 view type
69
+ - title: string \u2014 view title (falls back to id if not set)
70
+ - description: string|null \u2014 optional description
71
+ - tags: string[] \u2014 view tags
72
+ - project: string \u2014 project id this view belongs to
73
+ - nodes: Node[] \u2014 nodes included in the view
74
+ - edges: Edge[] \u2014 relationships between nodes
75
+ - sourceLocation: { path: string, range: { start: { line: number, character: number }, end: { line: number, character: number } } } | null \u2014 source location if available
76
+
77
+ Node (discriminated union by "type"):
78
+ - type = "element": { id: string, elementId: string, kind: string, title: string, description: string|null, technology: string|null, children: string[], shape: string, color: string, tags: string[] }
79
+ - type = "deployment-node": { id: string, deploymentId: string, kind: string, title: string, description: string|null, technology: string|null, children: string[], shape: string, color: string, tags: string[] }
80
+ - type = "deployed-instance": { id: string, deploymentId: string, title: string, description: string|null, technology: string|null, referencedElement: { id: string, kind: string, title: string }, shape: string, color: string, tags: string[] }
81
+
82
+ Edge object:
83
+ - { source: string, target: string, label: string|null, description: string|null, technology: string|null, tags: string[] }
84
+
85
+ Notes:
86
+ - Read-only, idempotent, no side effects.
87
+
88
+ Example response:
89
+ {
90
+ "id": "system-overview",
91
+ "type": "element",
92
+ "title": "System Overview",
93
+ "description": null,
94
+ "tags": [],
95
+ "project": "default",
96
+ "nodes": [
97
+ { "type": "logical", "id": "n1", "elementId": "shop.frontend", "kind": "container", "title": "Frontend", "description": null, "technology": "React", "children": [], "shape": "rounded-rectangle", "color": "#2F80ED", "tags": [] }
98
+ ],
99
+ "edges": [
100
+ { "source": "n1", "target": "n2", "label": "calls", "description": null, "technology": "HTTPS", "tags": [] }
101
+ ],
102
+ "sourceLocation": {
103
+ "path": "/abs/path/project/model.c4",
104
+ "range": { "start": { "line": 10, "character": 0 }, "end": { "line": 30, "character": 0 } }
105
+ }
106
+ }
107
+ `,
29
108
  annotations: {
30
- readOnlyHint: true
109
+ readOnlyHint: true,
110
+ idempotentHint: true,
111
+ title: "Read view"
31
112
  },
32
113
  inputSchema: {
33
114
  viewId: z.string().describe("View id (name)"),
34
- project: z.string().optional().describe('Project name (optional, will use "default" if not specified)')
115
+ project: projectIdSchema
35
116
  },
36
117
  outputSchema: {
37
118
  id: z.string(),
38
- type: z.enum(["element", "deployment", "dynamic"]),
39
- title: z.string().nullish(),
40
- description: z.string().nullish(),
119
+ type: z.enum(["element", "deployment", "dynamic"]).describe("View type"),
120
+ title: z.string(),
121
+ description: z.string().nullable(),
41
122
  tags: z.array(z.string()),
42
123
  project: z.string(),
43
- elements: z.array(
44
- z.discriminatedUnion("type", [
45
- z.object({
46
- type: z.literal("logical"),
47
- id: z.string().describe("Element ID (FQN)"),
48
- kind: z.string().describe("Element kind"),
49
- title: z.string().describe("Element title"),
50
- description: z.string().nullish(),
51
- technology: z.string().nullish(),
52
- children: z.array(z.string()),
53
- shape: z.string().describe("Element shape"),
54
- tags: z.array(z.string())
55
- }),
56
- z.object({
57
- type: z.literal("deployment-node"),
58
- id: z.string().describe("Deployment ID (FQN)"),
59
- kind: z.string().describe("Deployment kind"),
60
- title: z.string().describe("Deployment title"),
61
- description: z.string().nullish(),
62
- technology: z.string().nullish(),
63
- children: z.array(z.string()),
64
- shape: z.string().describe("Deployment shape"),
65
- tags: z.array(z.string())
66
- }),
67
- z.object({
68
- type: z.literal("deployed-instance"),
69
- id: z.string().describe("Deployment ID (FQN)"),
70
- title: z.string().describe("Deployment title"),
71
- description: z.string().nullish(),
72
- technology: z.string().nullish(),
73
- logicalElementId: z.string().describe("Logical element ID (FQN)"),
74
- shape: z.string().describe("Deployment shape"),
75
- tags: z.array(z.string())
76
- })
77
- ])
78
- ).describe("Elements in this view"),
79
- relationships: z.array(
124
+ nodes: z.array(nodeSchema),
125
+ edges: z.array(
80
126
  z.object({
81
- source: z.string().describe("Source element ID"),
82
- target: z.string().describe("Target element ID"),
83
- title: z.string().nullish(),
84
- description: z.string().nullish(),
85
- technology: z.string().nullish(),
127
+ source: z.string().describe("Source node"),
128
+ target: z.string().describe("Target node"),
129
+ label: z.string().nullable(),
130
+ description: z.string().nullable(),
131
+ technology: z.string().nullable(),
86
132
  tags: z.array(z.string())
87
133
  })
88
- ).describe("Relationships in this view"),
89
- defaultViewOf: z.string().optional().describe("Element ID (FQN) this view is the default view of"),
90
- sourceLocation: locationSchema.nullish()
134
+ ).describe("Edge represents relationship between nodes"),
135
+ sourceLocation: locationSchema
91
136
  }
92
137
  }, async (languageServices, args) => {
93
- const projectId = args.project ?? ProjectsManager.DefaultProjectId;
94
- const project = languageServices.projects().find((p) => p.id === projectId);
95
- invariant(project, `Project "${projectId}" not found`);
96
- const model = await languageServices.computedModel(project.id);
138
+ const projectId = languageServices.projectsManager.ensureProjectId(args.project);
139
+ const project = languageServices.project(projectId);
140
+ const model = await languageServices.computedModel(projectId);
97
141
  const view = model.findView(args.viewId);
98
142
  if (!view) {
99
143
  throw new Error(`View with ID '${args.viewId}' not found in project ${project.id}`);
100
144
  }
145
+ const locate = mkLocate(languageServices, project.id);
101
146
  return {
102
147
  id: view.id,
103
148
  type: view.$view._type,
104
- title: view.title,
149
+ title: view.title ?? view.id,
105
150
  description: view.description.text,
106
151
  tags: [...view.tags],
107
152
  project: project.id,
108
- elements: [...view.nodes()].flatMap((node) => {
153
+ nodes: [...view.nodes()].flatMap((node) => {
154
+ const base = {
155
+ id: node.id,
156
+ title: node.title,
157
+ description: node.description.text,
158
+ technology: node.technology,
159
+ shape: node.shape,
160
+ color: node.color,
161
+ tags: [...node.tags]
162
+ };
109
163
  if (node.hasDeployedInstance()) {
110
164
  return {
165
+ ...base,
111
166
  type: "deployed-instance",
112
- id: node.deployment.id,
113
- title: node.title,
114
- logicalElementId: node.deployment.element.id,
115
- description: node.description.text,
116
- technology: node.technology,
117
- shape: node.shape,
118
- tags: [...node.tags]
167
+ deploymentId: node.deployment.id,
168
+ referencedElement: {
169
+ id: node.deployment.element.id,
170
+ kind: node.deployment.element.kind,
171
+ title: node.deployment.element.title
172
+ }
119
173
  };
120
174
  }
121
175
  if (node.hasDeployment()) {
122
176
  return {
177
+ ...base,
123
178
  type: "deployment-node",
124
- id: node.deployment.id,
125
- title: node.title,
126
179
  kind: node.deployment.kind,
127
- description: node.description.text,
128
- technology: node.technology,
129
- shape: node.shape,
130
- tags: [...node.tags],
131
- children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
180
+ deploymentId: node.deployment.id,
181
+ children: [...node.children()].map((c) => c.id)
132
182
  };
133
183
  }
134
184
  if (node.hasElement()) {
135
185
  return {
136
- type: "logical",
137
- id: node.element.id,
138
- title: node.title,
186
+ ...base,
187
+ type: "element",
188
+ elementId: node.element.id,
139
189
  kind: node.element.kind,
140
- description: node.description.text,
141
- technology: node.technology,
142
- shape: node.shape,
143
- tags: [...node.tags],
144
190
  children: [...node.children()].flatMap((c) => modelRef(c) ?? [])
145
191
  };
146
192
  }
147
193
  return [];
148
194
  }),
149
- viewOf: view.viewOf?.id,
150
- relationships: [...view.edges()].flatMap((r) => {
151
- const source = modelRef(r.source);
152
- const target = modelRef(r.target);
153
- return source && target ? [{
154
- source,
155
- target,
156
- title: r.label,
157
- description: r.description.text,
158
- technology: r.technology,
159
- tags: [...r.tags]
160
- }] : [];
161
- }),
162
- sourceLocation: safeCall(() => languageServices.locate({ view: view.id, projectId }))
195
+ edges: [...view.edges()].map((r) => ({
196
+ source: r.source.id,
197
+ target: r.target.id,
198
+ label: r.label,
199
+ description: r.description.text,
200
+ technology: r.technology,
201
+ tags: [...r.tags]
202
+ })),
203
+ sourceLocation: locate({ view: view.id })
163
204
  };
164
205
  });
@@ -1,24 +1,31 @@
1
1
  import { ifilter } from "@likec4/core/utils";
2
2
  import z from "zod";
3
- import { likec4Tool } from "../utils.js";
3
+ import { likec4Tool, logger } from "../utils.js";
4
+ import { includedInViews, includedInViewsSchema } from "./_common.js";
4
5
  const searchResultSchema = z.array(
5
6
  z.discriminatedUnion("type", [
6
7
  z.object({
7
- type: z.literal("logical"),
8
+ type: z.literal("element"),
9
+ project: z.string().describe("Project ID"),
8
10
  id: z.string().describe("Element ID (FQN)"),
11
+ name: z.string().describe("Element name"),
9
12
  kind: z.string(),
10
13
  title: z.string(),
14
+ technology: z.string().nullable(),
11
15
  shape: z.string(),
12
- project: z.string().describe("Project name"),
16
+ includedInViews: includedInViewsSchema,
13
17
  tags: z.array(z.string())
14
18
  }),
15
19
  z.object({
16
20
  type: z.literal("deployment-node"),
21
+ project: z.string().describe("Project ID"),
17
22
  id: z.string().describe("Deployment ID (FQN)"),
23
+ name: z.string().describe("Deployment name"),
18
24
  kind: z.string(),
19
25
  title: z.string(),
26
+ technology: z.string().nullable(),
20
27
  shape: z.string(),
21
- project: z.string().describe("Project name"),
28
+ includedInViews: includedInViewsSchema,
22
29
  tags: z.array(z.string())
23
30
  })
24
31
  ])
@@ -26,32 +33,69 @@ const searchResultSchema = z.array(
26
33
  export const searchElement = likec4Tool({
27
34
  name: "search-element",
28
35
  annotations: {
29
- readOnlyHint: true
36
+ readOnlyHint: true,
37
+ idempotentHint: true,
38
+ title: "Search elements"
30
39
  },
31
40
  description: `
32
- Search for LikeC4 elements and deployment nodes by partial match of:
33
- - id (FQN)
34
- - title
35
- - kind (if search string starts with "kind:")
36
- - shape (if search string starts with "shape:")
37
- - any assigned tags (if search string starts with "#")
41
+ Search LikeC4 elements and deployment nodes across all projects.
38
42
 
39
- Returns array of found elements with:
40
- - type (logical or deployment-node)
41
- - id (FQN)
42
- - kind
43
- - title
44
- - shape
45
- - project name this element belongs to
46
- - assigned tags
43
+ Query syntax (case-insensitive):
44
+ - Free text: matches id (FQN) or title
45
+ - kind:<value>: filters by kind
46
+ - shape:<value>: filters by shape
47
+ - #<value>: matches assigned tags
47
48
 
48
- Can be used for further requests (like read-element or read-project-summary)
49
- `.trimStart(),
49
+ Request:
50
+ - search: string \u2014 at least 2 characters
51
+
52
+ Response (JSON object):
53
+ - found: Result[] - returns top 20 results
54
+ - total: number - total number of results
55
+
56
+ Result (discriminated union by "type"):
57
+ - type = "element": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[] }
58
+ - type = "deployment-node": { id: string, name: string, kind: string, title: string, technology: string|null, shape: string, project: string, includedInViews: View[], tags: string[] }
59
+
60
+ View (object) fields:
61
+ - id: string \u2014 view identifier
62
+ - title: string \u2014 view title
63
+ - type: "element" | "deployment" | "dynamic"
64
+
65
+ Notes:
66
+ - Read-only, idempotent.
67
+ - Use results as input to other tools (e.g., read-element, read-view).
68
+
69
+ Example response:
70
+ {
71
+ "found": [
72
+ {
73
+ "type": "logical",
74
+ "project": "default",
75
+ "id": "shop.frontend",
76
+ "name": "frontend",
77
+ "kind": "container",
78
+ "title": "Frontend",
79
+ "technology": "React",
80
+ "shape": "rectangle",
81
+ "includedInViews": [
82
+ {
83
+ "id": "system-overview",
84
+ "title": "System Overview",
85
+ "type": "element"
86
+ }
87
+ ],
88
+ "tags": ["public"]
89
+ }
90
+ ]
91
+ }
92
+ `,
50
93
  inputSchema: {
51
94
  search: z.string().min(2, "Search must be at least 2 characters long")
52
95
  },
53
96
  outputSchema: {
54
- found: searchResultSchema
97
+ found: searchResultSchema,
98
+ total: z.number()
55
99
  }
56
100
  }, async (languageServices, args) => {
57
101
  const projects = languageServices.projects();
@@ -73,33 +117,40 @@ Can be used for further requests (like read-element or read-project-summary)
73
117
  for (const project of projects) {
74
118
  try {
75
119
  const model = await languageServices.computedModel(project.id);
76
- for (const el of ifilter(model.elements(), predicate)) {
120
+ for (const el of ifilter(model.elements(), (e) => !e.imported && predicate(e))) {
77
121
  found.push({
78
- type: "logical",
122
+ type: "element",
123
+ project: project.id,
79
124
  id: el.id,
125
+ name: el.name,
80
126
  kind: el.kind,
81
127
  title: el.title,
128
+ technology: el.technology,
82
129
  shape: el.shape,
83
- project: project.id,
84
- tags: [...el.tags]
130
+ tags: [...el.tags],
131
+ includedInViews: includedInViews(el.views())
85
132
  });
86
133
  }
87
134
  for (const el of ifilter(model.deployment.nodes(), predicate)) {
88
135
  found.push({
89
136
  type: "deployment-node",
137
+ project: project.id,
90
138
  id: el.id,
139
+ name: el.name,
91
140
  kind: el.kind,
92
141
  title: el.title,
142
+ technology: el.technology,
93
143
  shape: el.shape,
94
- project: project.id,
95
- tags: [...el.tags]
144
+ tags: [...el.tags],
145
+ includedInViews: includedInViews(el.views())
96
146
  });
97
147
  }
98
148
  } catch (error) {
99
- console.error(`Error searching in project ${project.id}:`, error);
149
+ logger.error(`Error searching in project ${project.id}:`, { error });
100
150
  }
101
151
  }
102
152
  return {
103
- found
153
+ found: found.slice(0, 20),
154
+ total: found.length
104
155
  };
105
156
  });
package/dist/mcp/utils.js CHANGED
@@ -2,17 +2,20 @@ import { loggable } from "@likec4/log";
2
2
  import { logger as mainLogger } from "../logger.js";
3
3
  export const logger = mainLogger.getChild("mcp");
4
4
  export function likec4Tool(config, cb) {
5
- const { name, ...rest } = config;
5
+ const { name, description, ...rest } = config;
6
6
  return (languageServices) => [
7
7
  name,
8
- rest,
8
+ {
9
+ description: description?.trim() ?? "",
10
+ ...rest
11
+ },
9
12
  mkcallTool(name, languageServices, cb)
10
13
  ];
11
14
  }
12
15
  function mkcallTool(name, languageServices, cb) {
13
16
  const tool = cb.bind(null, languageServices);
14
17
  return async function callTool(args, extra) {
15
- logger.debug("Calling tool {name}", { name, args });
18
+ logger.debug("Calling tool {name}, args: {args}", { name, args });
16
19
  try {
17
20
  const result = await tool.call(null, args, extra);
18
21
  if (typeof result === "string") {
@@ -35,7 +38,7 @@ function mkcallTool(name, languageServices, cb) {
35
38
  return {
36
39
  content: [{
37
40
  type: "text",
38
- text: loggable(err)
41
+ text: err instanceof Error ? err.message : loggable(err)
39
42
  }],
40
43
  isError: true
41
44
  };
@@ -16,6 +16,6 @@ export type BuildModelData = {
16
16
  */
17
17
  export declare function buildModelData(project: {
18
18
  id: c4.ProjectId;
19
- folder: URI;
19
+ folderUri: URI;
20
20
  config: Readonly<ProjectConfig>;
21
21
  }, docs: ParsedLikeC4LangiumDocument[]): BuildModelData;
@@ -190,16 +190,14 @@ export function buildModelData(project, docs) {
190
190
  indexBy(prop("id")),
191
191
  resolveRulesExtendedViews
192
192
  );
193
- const projectInfo = {
194
- id: project.id,
195
- name: project.config.name,
196
- ...project.config.title && { title: project.config.title }
197
- };
198
193
  return {
199
194
  data: {
200
195
  [c4._stage]: "parsed",
201
196
  projectId: project.id,
202
- project: projectInfo,
197
+ project: {
198
+ id: project.id,
199
+ title: project.config.title ?? project.config.name
200
+ },
203
201
  specification: {
204
202
  tags: c4Specification.tags,
205
203
  elements: c4Specification.specs.elements,
@@ -57,7 +57,7 @@ declare const DocumentParserFromMixins: {
57
57
  readonly doc: ParsedLikeC4LangiumDocument;
58
58
  get project(): {
59
59
  id: ProjectId;
60
- folder: ProjectId;
60
+ folderUri: ProjectId;
61
61
  config: Readonly<import("../config").ProjectConfig>;
62
62
  };
63
63
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -150,7 +150,7 @@ declare const DocumentParserFromMixins: {
150
150
  readonly doc: ParsedLikeC4LangiumDocument;
151
151
  get project(): {
152
152
  id: ProjectId;
153
- folder: ProjectId;
153
+ folderUri: ProjectId;
154
154
  config: Readonly<import("../config").ProjectConfig>;
155
155
  };
156
156
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -205,7 +205,7 @@ declare const DocumentParserFromMixins: {
205
205
  readonly doc: ParsedLikeC4LangiumDocument;
206
206
  get project(): {
207
207
  id: ProjectId;
208
- folder: ProjectId;
208
+ folderUri: ProjectId;
209
209
  config: Readonly<import("../config").ProjectConfig>;
210
210
  };
211
211
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -274,7 +274,7 @@ declare const DocumentParserFromMixins: {
274
274
  readonly doc: ParsedLikeC4LangiumDocument;
275
275
  get project(): {
276
276
  id: ProjectId;
277
- folder: ProjectId;
277
+ folderUri: ProjectId;
278
278
  config: Readonly<import("../config").ProjectConfig>;
279
279
  };
280
280
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -336,7 +336,7 @@ declare const DocumentParserFromMixins: {
336
336
  readonly doc: ParsedLikeC4LangiumDocument;
337
337
  get project(): {
338
338
  id: ProjectId;
339
- folder: ProjectId;
339
+ folderUri: ProjectId;
340
340
  config: Readonly<import("../config").ProjectConfig>;
341
341
  };
342
342
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -406,7 +406,7 @@ declare const DocumentParserFromMixins: {
406
406
  readonly doc: ParsedLikeC4LangiumDocument;
407
407
  get project(): {
408
408
  id: ProjectId;
409
- folder: ProjectId;
409
+ folderUri: ProjectId;
410
410
  config: Readonly<import("../config").ProjectConfig>;
411
411
  };
412
412
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -469,7 +469,7 @@ declare const DocumentParserFromMixins: {
469
469
  readonly doc: ParsedLikeC4LangiumDocument;
470
470
  get project(): {
471
471
  id: ProjectId;
472
- folder: ProjectId;
472
+ folderUri: ProjectId;
473
473
  config: Readonly<import("../config").ProjectConfig>;
474
474
  };
475
475
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -512,7 +512,7 @@ declare const DocumentParserFromMixins: {
512
512
  readonly doc: ParsedLikeC4LangiumDocument;
513
513
  get project(): {
514
514
  id: ProjectId;
515
- folder: ProjectId;
515
+ folderUri: ProjectId;
516
516
  config: Readonly<import("../config").ProjectConfig>;
517
517
  };
518
518
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -570,7 +570,7 @@ declare const DocumentParserFromMixins: {
570
570
  readonly doc: ParsedLikeC4LangiumDocument;
571
571
  get project(): {
572
572
  id: ProjectId;
573
- folder: ProjectId;
573
+ folderUri: ProjectId;
574
574
  config: Readonly<import("../config").ProjectConfig>;
575
575
  };
576
576
  resolveFqn(node: import("../generated/ast").FqnReferenceable): ProjectId;
@@ -37,6 +37,9 @@ export class LikeC4ModelParser {
37
37
  DocumentState.Linked,
38
38
  (doc) => {
39
39
  try {
40
+ if (services.shared.workspace.ProjectsManager.checkIfExcluded(doc)) {
41
+ return;
42
+ }
40
43
  if (!isLikeC4Builtin(doc.uri)) {
41
44
  this.cachedParsers.set(doc, this.createParser(doc));
42
45
  }
@@ -25,7 +25,7 @@ export declare class BaseParser {
25
25
  constructor(services: LikeC4Services, doc: ParsedLikeC4LangiumDocument);
26
26
  get project(): {
27
27
  id: c4.ProjectId;
28
- folder: URI;
28
+ folderUri: URI;
29
29
  config: Readonly<ProjectConfig>;
30
30
  };
31
31
  resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
@@ -187,7 +187,7 @@ export class BaseParser {
187
187
  return joinRelativeURL(this.doc.uri.toString(), "../", value);
188
188
  }
189
189
  case (value && hasLeadingSlash(value)): {
190
- return joinURL(this.project.folder.toString(), value);
190
+ return joinURL(this.project.folderUri.toString(), value);
191
191
  }
192
192
  default: {
193
193
  return void 0;
@@ -32,7 +32,7 @@ export declare function DeploymentModelParser<TBase extends WithExpressionV2>(B:
32
32
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
33
33
  get project(): {
34
34
  id: c4.ProjectId;
35
- folder: c4;
35
+ folderUri: c4;
36
36
  config: Readonly<import("../../config").ProjectConfig>;
37
37
  };
38
38
  resolveFqn(node: ast.FqnReferenceable): c4.Fqn;