Skip to content

Extract MCP server into standalone @likec4/mcp package#2877

Merged
davydkov merged 6 commits intomainfrom
move-mcp-to-package
Apr 13, 2026
Merged

Extract MCP server into standalone @likec4/mcp package#2877
davydkov merged 6 commits intomainfrom
move-mcp-to-package

Conversation

@davydkov
Copy link
Copy Markdown
Member

@davydkov davydkov commented Apr 11, 2026

Summary

  • Move MCP server code from @likec4/language-server into dedicated @likec4/mcp package for reuse and modularity
  • Remove deprecated likec4.mcp.enabled and likec4.mcp.port VSCode settings — MCP is now auto-registered via VSCode's native MCP provider (stdio)
  • Update AI tools docs with configuration examples for Cursor, Windsurf, and Claude Code

Test plan

  • Verify VSCode extension activates and registers MCP server automatically
  • Verify likec4 mcp CLI still works with stdio and http transports
  • Verify npx @likec4/mcp works standalone
  • Verify docs render correctly on the AI Tools page

🤖 Generated with Claude Code

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 11, 2026

🦋 Changeset detected

Latest commit: 9d0ec87

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 21 packages
Name Type
@likec4/mcp Patch
@likec4/language-server Patch
@likec4/language-services Patch
likec4 Patch
likec4-vscode Patch
@likec4/playground Patch
@likec4/lsp Patch
@likec4/vite-plugin Patch
@likec4/docs-astro Patch
@likec4/style-preset Patch
@likec4/styles Patch
@likec4/config Patch
@likec4/core Patch
@likec4/diagram Patch
@likec4/generators Patch
@likec4/layouts Patch
@likec4/leanix-bridge Patch
@likec4/log Patch
@likec4/react Patch
@likec4/tsconfig Patch
@likec4/vscode-preview Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Remove unused `likec4.mcp.enabled` and `likec4.mcp.port` settings from
VSCode extension — MCP is now auto-registered via native MCP support.
Update docs with configuration examples for Cursor, Windsurf, and Claude Code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@davydkov davydkov force-pushed the move-mcp-to-package branch from 1fc377a to 5addca0 Compare April 11, 2026 12:37
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 11903baf-279a-420b-bced-d8dd26430bf7

📥 Commits

Reviewing files that changed from the base of the PR and between 89b9bc6 and 9d0ec87.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • packages/likec4/src/cli/build/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/likec4/src/cli/build/index.ts

📝 Walkthrough

Walkthrough

Extracts the MCP server and tooling into a new standalone @likec4/mcp package; removes MCP wiring/exports from language-server and language-services; updates CLI, VSCode integration, documentation, tests, build entries, and TypeScript project references to use the new MCP package and programmatic/CLI entrypoints.

Changes

Cohort / File(s) Summary
Changeset & Docs
\.changeset/move-mcp-to-package.md, apps/docs/src/content/docs/tooling/ai-tools.mdx
Adds changeset; updates AI-tools docs to reflect VSCode native MCP integration and new manual setup tabs/commands (Cursor/Windsurf/Claude Code) and example CLI usage.
Language Server: packaging & exports
packages/language-server/package.json, packages/language-server/build.config.ts
Removed ./mcp export and MCP deps; removed ./src/mcp/index.ts from bundle inputs; added ./test export.
Language Server: API & wiring
packages/language-server/src/index.ts, packages/language-server/src/LikeC4LanguageServices.ts, packages/language-server/src/module.ts, packages/language-server/src/common-exports.ts, packages/language-server/src/browser/index.ts
Removed mcpServer surface, enableMCP option, NoMCPServer re-exports and MCP service wiring; updated service/context types and disposal logic.
Language Server: removed MCP modules
packages/language-server/src/mcp/*, packages/language-server/src/empty.ts
Deleted MCP types, noop, WithMCPServer implementation, barrel exports and empty placeholder module.
Language Services: entry consolidation
packages/language-services/package.json, packages/language-services/build.config.ts, packages/language-services/src/node/*
Removed node/without-mcp entry and exports; deleted without-mcp implementation; removed MCP option handling; adjusted URI/workspace initialization in node entry.
MCP package: packaging & tests
packages/mcp/package.json, packages/mcp/build.config.ts, packages/mcp/tsconfig.json, packages/mcp/vitest.config.ts
New package exports/publish config and CLI bin, bundle inputs split, project refs added, Vitest config and test scripts added.
MCP package: implementation
packages/mcp/src/index.ts, packages/mcp/src/cli.ts, packages/mcp/src/utils.ts, packages/mcp/src/empty.ts, packages/mcp/README.md
Adds programmatic APIs initLikeC4MCP/startLikeC4MCP, new citty CLI entrypoint, logger/config handling, removes placeholder empty module and cleans README.
MCP server internals
packages/mcp/src/server/*.ts, packages/mcp/src/server/createMCPServer.ts
Introduced LikeC4MCPServer interface; server classes now accept LikeC4LanguageServices; replaced MCPServerFactory class with createMCPServer() function; removed editor-only tool registration.
MCP tools & tests
packages/mcp/src/tools/_common.ts, packages/mcp/src/tools/*.spec.ts, packages/mcp/src/tools/*.ts
Updated test imports to @likec4/language-server/test, changed projectIdSchema default to 'default', adjusted package-level import paths; minor test formatting.
CLI & consumers
packages/likec4/src/cli/**, packages/vite-plugin/src/plugin.ts, packages/likec4/tsconfig.cli.json
Replaced many imports from .../node/without-mcp to .../node; MCP CLI now uses startLikeC4MCP from @likec4/mcp; added MCP project ref to CLI tsconfig.
VSCode extension
packages/vscode/package.json, packages/vscode/src/node/mcp-server.ts, packages/vscode/tsconfig.json
Removed extension MCP settings schema; added @likec4/mcp project ref; replaced workspace init with startLikeC4MCP (stdio) and adjusted logger config and startup callsites.
Miscellaneous
packages/likec4/package.json, small import updates across packages
Added @likec4/mcp devDependency and updated various import paths to use new package entrypoints.

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant MCPPkg as `@likec4/mcp`
  participant Workspace as LikeC4 Workspace
  participant Server as MCP Server
  participant LangServ as LanguageServices

  CLI->>MCPPkg: startLikeC4MCP({ workspacePath, mcp:'stdio'|'port', ... })
  MCPPkg->>Workspace: fromWorkspace({ workspacePath, manualLayouts:true, watch, graphviz })
  Workspace-->>MCPPkg: likec4 (initialized)
  MCPPkg->>MCPPkg: createMCPServer(likec4.languageServices)
  MCPPkg->>Server: server.start()
  Server-->>MCPPkg: started (port/stdio)
  MCPPkg->>LangServ: server.mcp.sendLoggingMessage(...)
  LangServ-->>MCPPkg: ack (optional)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers the main objectives, test plan, and references generated changes, but the checklist is not filled out (all boxes are unchecked). Complete the PR checklist by checking applicable boxes (e.g., tests added, typecheck/test verified, changesets added, documentation updated).
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: extracting the MCP server into a standalone package.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch move-mcp-to-package

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@davydkov
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/mcp/package.json (1)

61-79: ⚠️ Potential issue | 🔴 Critical

Move all external runtime dependencies to dependencies (not devDependencies).

The code imports 11+ external packages at runtime (zod, hono, citty, langium, remeda, vscode-uri, @hono/mcp, @hono/node-server, @modelcontextprotocol/sdk, defu, tinyrainbow), but they are declared only under devDependencies. When this package is published and installed standalone (e.g., npm install @likec4/mcp``), or used programmatically outside the monorepo, these missing dependencies entries will cause module-not-found errors. Move all external packages to `dependencies`; workspace packages (`@likec4/*`) may remain in `devDependencies` if the build fully bundles them.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mcp/package.json` around lines 61 - 79, The package.json currently
lists many runtime packages under devDependencies (see the "devDependencies"
block and entries like "hono", "langium", "citty", "remeda", "vscode-uri",
"@hono/mcp", "@hono/node-server", "@modelcontextprotocol/sdk", "defu",
"tinyrainbow", "zod", etc.); move all externally required runtime packages into
the "dependencies" section so they are installed when this package is consumed
standalone, while leaving internal workspace packages (the "@likec4/*" entries)
in devDependencies if they are bundled by the build. Ensure the package.json
"dependencies" object contains those external package names and remove them from
"devDependencies" to prevent runtime module-not-found errors.
🧹 Nitpick comments (2)
packages/mcp/src/tools/_common.ts (1)

251-255: Don’t hardcode the default project id in the schema.

This adds a second source of truth for the default project id. If ProjectsManager ever changes its default or resolves aliases, omitted project values will stop behaving like the rest of the code path. Let the schema stay optional and keep default resolution inside ensureProjectId(...).

♻️ Suggested change
 export const projectIdSchema = z.string()
   .refine((_v): _v is ProjectId => true)
   .optional()
-  .default('default' as ProjectId)
-  .describe('Project id (optional, will use "default" if not specified)')
+  .describe('Project id (optional; uses the workspace default when omitted)')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mcp/src/tools/_common.ts` around lines 251 - 255, The schema
projectIdSchema currently hardcodes a default ('default' as ProjectId), creating
a second source of truth; remove the .default(...) so the schema remains
optional and does not inject a default value, i.e., keep
z.string().refine(...).optional().describe(...), and rely on ensureProjectId
(and ProjectsManager) to resolve the actual default/aliases at runtime instead
of the schema.
packages/mcp/src/server/StdioLikeC4MCPServer.ts (1)

8-14: Extract LikeC4MCPServer into a dedicated type module.

This interface is shared across implementations, but it is declared inside a concrete stdio server file, which creates avoidable cross-implementation coupling (see Line [12] in StreamableLikeC4MCPServer.ts).

♻️ Proposed refactor
+// packages/mcp/src/server/LikeC4MCPServer.ts
+import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
+
+export interface LikeC4MCPServer {
+  readonly mcp: McpServer
+  readonly isStarted: boolean
+  readonly port: number
+  start(port?: number): Promise<void>
+  stop(): Promise<void>
+}
-// packages/mcp/src/server/StdioLikeC4MCPServer.ts
-export interface LikeC4MCPServer {
-  ...
-}
+import type { LikeC4MCPServer } from './LikeC4MCPServer'
-// packages/mcp/src/server/StreamableLikeC4MCPServer.ts
-import type { LikeC4MCPServer } from './StdioLikeC4MCPServer'
+import type { LikeC4MCPServer } from './LikeC4MCPServer'

As per coding guidelines: "Agent types and interfaces should be defined separately and reused across the codebase"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mcp/src/server/StdioLikeC4MCPServer.ts` around lines 8 - 14, Extract
the LikeC4MCPServer interface from StdioLikeC4MCPServer into a new dedicated
module (e.g., likeC4MCPServer.ts), export it as a named type, then update all
implementations to import that shared type instead of redeclaring it;
specifically modify StdioLikeC4MCPServer (remove the inline interface and import
LikeC4MCPServer) and StreamableLikeC4MCPServer (replace the local reference with
an import), and run TypeScript checks to ensure start, stop, mcp, isStarted and
port signatures remain consistent across consumers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/move-mcp-to-package.md:
- Line 9: Update the release note to fix the typo: replace the word "toolst"
with "tools" in the text that currently reads "Extract MCP server and toolst to
`@likec4/mcp` package." so the sentence becomes "Extract MCP server and tools to
`@likec4/mcp` package."
- Around line 3-4: The changeset currently marks '@likec4/language-server' and
'@likec4/language-services' as 'patch' but removing MCP APIs is a breaking
change; update the entries in the .changeset/move-mcp-to-package.md file so both
package lines use a breaking bump (e.g., replace 'patch' with 'major' for
'@likec4/language-server' and '@likec4/language-services') to ensure a breaking
release is published.

In `@packages/mcp/build.config.ts`:
- Around line 4-9: The package is published without type declarations; enable
declaration generation and point package.json at the emitted .d.ts so consumers
can use startLikeC4MCP/initLikeC4MCP. In build.config.ts set dts: true for the
entry that builds ./src/index.ts (the entries array with type 'bundle' and input
['./src/cli.ts','./src/index.ts']), then add a "types": "./dist/index.d.ts"
field to package.json (or alternatively add a separate declaration-emission step
that uses your tsconfig with emitDeclarationOnly and includes the lib/ files) so
the dist .d.ts files are produced and referenced.

In `@packages/mcp/src/cli.ts`:
- Around line 59-80: The local process.on('uncaughtException', ...) and
process.on('unhandledRejection', ...) handlers are being registered twice
because startLikeC4MCP({ ..., configureLogger: true }) also attaches them;
remove the duplication by either deleting the two local handlers or by setting
configureLogger: false when calling startLikeC4MCP if you want to keep the local
handlers — update the code around the process.on(...) blocks and the
startLikeC4MCP call accordingly, referring to the process.on handlers and the
startLikeC4MCP(...) configureLogger option to ensure handlers are only
registered once.
- Around line 24-29: The CLI currently allows invalid --port values; add
validation inside the setup() function to parse the provided port option
(referencing the port option in the CLI config) as an integer only if the string
is all digits (e.g. /^\d+$/), convert to Number/parseInt, and ensure the
resulting integer is between 1 and 65535; if the value is invalid, reject it
immediately by throwing an Error or exiting with a clear message (e.g. "Invalid
--port: must be integer 1-65535") so startup does not continue with NaN or
partial parses.

In `@packages/mcp/src/index.ts`:
- Around line 41-45: The FromWorkspaceOptions flag throwIfInvalid is declared
but not forwarded to the workspace loader; update the call to fromWorkspace(...)
in packages/mcp/src/index.ts (the invocation that currently builds workspace
options) to include throwIfInvalid: opts.throwIfInvalid (or opts.throwIfInvalid
?? false) so the workspace loader receives the caller's strict validation
preference; ensure the option name matches the
FromWorkspaceOptions/throwIfInvalid symbol and is passed into the
fromWorkspace(...) call where other opts fields are forwarded.

In `@packages/mcp/src/tools/mcp-server-links.int.spec.ts`:
- Around line 9-12: The test currently only calls readElement and readDeployment
directly; change it to exercise the MCP server path by instantiating the test
services with createTestServices, registering or loading the tools, then
resolving the tool via the MCP server/name-based lookup and invoking it through
that interface (instead of or in addition to calling readElement/readDeployment
directly). Specifically, use createTestServices to bring up the MCP server, use
the server's registration/lookup API to find the tool by its registered name
(the same name the real wiring uses), then call the resolved tool and assert
results—ensuring the integration path (MCP registration + name lookup + tool
invocation) is covered in the .int.spec.ts.

---

Outside diff comments:
In `@packages/mcp/package.json`:
- Around line 61-79: The package.json currently lists many runtime packages
under devDependencies (see the "devDependencies" block and entries like "hono",
"langium", "citty", "remeda", "vscode-uri", "@hono/mcp", "@hono/node-server",
"@modelcontextprotocol/sdk", "defu", "tinyrainbow", "zod", etc.); move all
externally required runtime packages into the "dependencies" section so they are
installed when this package is consumed standalone, while leaving internal
workspace packages (the "@likec4/*" entries) in devDependencies if they are
bundled by the build. Ensure the package.json "dependencies" object contains
those external package names and remove them from "devDependencies" to prevent
runtime module-not-found errors.

---

Nitpick comments:
In `@packages/mcp/src/server/StdioLikeC4MCPServer.ts`:
- Around line 8-14: Extract the LikeC4MCPServer interface from
StdioLikeC4MCPServer into a new dedicated module (e.g., likeC4MCPServer.ts),
export it as a named type, then update all implementations to import that shared
type instead of redeclaring it; specifically modify StdioLikeC4MCPServer (remove
the inline interface and import LikeC4MCPServer) and StreamableLikeC4MCPServer
(replace the local reference with an import), and run TypeScript checks to
ensure start, stop, mcp, isStarted and port signatures remain consistent across
consumers.

In `@packages/mcp/src/tools/_common.ts`:
- Around line 251-255: The schema projectIdSchema currently hardcodes a default
('default' as ProjectId), creating a second source of truth; remove the
.default(...) so the schema remains optional and does not inject a default
value, i.e., keep z.string().refine(...).optional().describe(...), and rely on
ensureProjectId (and ProjectsManager) to resolve the actual default/aliases at
runtime instead of the schema.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cabd60d8-8d3f-4189-9fab-71003efb11b9

📥 Commits

Reviewing files that changed from the base of the PR and between e98d9f4 and 5addca0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (88)
  • .changeset/move-mcp-to-package.md
  • apps/docs/src/content/docs/tooling/ai-tools.mdx
  • packages/language-server/build.config.ts
  • packages/language-server/package.json
  • packages/language-server/src/LikeC4LanguageServices.ts
  • packages/language-server/src/browser/index.ts
  • packages/language-server/src/common-exports.ts
  • packages/language-server/src/empty.ts
  • packages/language-server/src/index.ts
  • packages/language-server/src/mcp/index.ts
  • packages/language-server/src/mcp/noop.ts
  • packages/language-server/src/mcp/server/WithMCPServer.ts
  • packages/language-server/src/mcp/types.ts
  • packages/language-server/src/module.ts
  • packages/language-services/README.md
  • packages/language-services/build.config.ts
  • packages/language-services/package.json
  • packages/language-services/src/node/createLanguageServices.ts
  • packages/language-services/src/node/index.ts
  • packages/language-services/src/node/without-mcp/createLanguageServices.ts
  • packages/language-services/src/node/without-mcp/index.ts
  • packages/likec4/package.json
  • packages/likec4/src/cli/build/index.ts
  • packages/likec4/src/cli/codegen/custom.ts
  • packages/likec4/src/cli/codegen/handler.ts
  • packages/likec4/src/cli/codegen/leanix-dry-run.ts
  • packages/likec4/src/cli/codegen/leanix-reconcile.ts
  • packages/likec4/src/cli/codegen/model/index.ts
  • packages/likec4/src/cli/codegen/react/index.ts
  • packages/likec4/src/cli/codegen/webcomponent/handler.ts
  • packages/likec4/src/cli/export/json/handler.ts
  • packages/likec4/src/cli/export/png/handler.ts
  • packages/likec4/src/cli/format/index.ts
  • packages/likec4/src/cli/mcp/index.ts
  • packages/likec4/src/cli/preview/preview.ts
  • packages/likec4/src/cli/serve/serve.ts
  • packages/likec4/src/cli/sync/leanix.ts
  • packages/likec4/src/cli/validate/index.ts
  • packages/likec4/tsconfig.cli.json
  • packages/mcp/README.md
  • packages/mcp/build.config.ts
  • packages/mcp/package.json
  • packages/mcp/src/cli.ts
  • packages/mcp/src/empty.ts
  • packages/mcp/src/index.ts
  • packages/mcp/src/server/StdioLikeC4MCPServer.ts
  • packages/mcp/src/server/StreamableLikeC4MCPServer.ts
  • packages/mcp/src/server/createMCPServer.ts
  • packages/mcp/src/tools/_common.spec.ts
  • packages/mcp/src/tools/_common.ts
  • packages/mcp/src/tools/batch-read-elements.spec.ts
  • packages/mcp/src/tools/batch-read-elements.ts
  • packages/mcp/src/tools/cloud-system-integration.spec.ts
  • packages/mcp/src/tools/element-diff.spec.ts
  • packages/mcp/src/tools/element-diff.ts
  • packages/mcp/src/tools/find-relationship-paths.spec.ts
  • packages/mcp/src/tools/find-relationship-paths.ts
  • packages/mcp/src/tools/find-relationships.ts
  • packages/mcp/src/tools/list-projects.ts
  • packages/mcp/src/tools/mcp-server-links.int.spec.ts
  • packages/mcp/src/tools/mcp-tools-links.spec.ts
  • packages/mcp/src/tools/open-view.ts
  • packages/mcp/src/tools/query-by-metadata.spec.ts
  • packages/mcp/src/tools/query-by-metadata.ts
  • packages/mcp/src/tools/query-by-tag-pattern.spec.ts
  • packages/mcp/src/tools/query-by-tag-pattern.ts
  • packages/mcp/src/tools/query-by-tags.spec.ts
  • packages/mcp/src/tools/query-by-tags.ts
  • packages/mcp/src/tools/query-graph.spec.ts
  • packages/mcp/src/tools/query-graph.ts
  • packages/mcp/src/tools/query-incomers-graph.spec.ts
  • packages/mcp/src/tools/query-incomers-graph.ts
  • packages/mcp/src/tools/query-outgoers-graph.spec.ts
  • packages/mcp/src/tools/query-outgoers-graph.ts
  • packages/mcp/src/tools/read-deployment.ts
  • packages/mcp/src/tools/read-element.ts
  • packages/mcp/src/tools/read-project-summary.ts
  • packages/mcp/src/tools/read-view.ts
  • packages/mcp/src/tools/search-element.ts
  • packages/mcp/src/tools/subgraph-summary.spec.ts
  • packages/mcp/src/tools/subgraph-summary.ts
  • packages/mcp/src/utils.ts
  • packages/mcp/tsconfig.json
  • packages/mcp/vitest.config.ts
  • packages/vite-plugin/src/plugin.ts
  • packages/vscode/package.json
  • packages/vscode/src/node/mcp-server.ts
  • packages/vscode/tsconfig.json
💤 Files with no reviewable changes (16)
  • packages/language-server/src/empty.ts
  • packages/mcp/src/empty.ts
  • packages/language-services/build.config.ts
  • packages/language-server/build.config.ts
  • packages/language-services/README.md
  • packages/language-services/package.json
  • packages/language-server/src/common-exports.ts
  • packages/language-server/src/LikeC4LanguageServices.ts
  • packages/language-server/src/mcp/index.ts
  • packages/mcp/README.md
  • packages/language-services/src/node/without-mcp/createLanguageServices.ts
  • packages/language-server/src/mcp/server/WithMCPServer.ts
  • packages/language-server/src/mcp/noop.ts
  • packages/language-server/src/browser/index.ts
  • packages/language-server/src/mcp/types.ts
  • packages/language-services/src/node/without-mcp/index.ts

Comment on lines +3 to +4
'@likec4/language-server': patch
'@likec4/language-services': patch
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use a breaking-release bump for the removed MCP APIs.

This PR removes MCP surface/entrypoints from @likec4/language-server and @likec4/language-services, so shipping them as patch would understate a downstream breaking change. Please mark those packages as breaking in the changeset.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/move-mcp-to-package.md around lines 3 - 4, The changeset
currently marks '@likec4/language-server' and '@likec4/language-services' as
'patch' but removing MCP APIs is a breaking change; update the entries in the
.changeset/move-mcp-to-package.md file so both package lines use a breaking bump
(e.g., replace 'patch' with 'major' for '@likec4/language-server' and
'@likec4/language-services') to ensure a breaking release is published.

Comment thread .changeset/move-mcp-to-package.md Outdated
Comment on lines 4 to +9
entries: [{
type: 'bundle',
input: './src/index.ts',
input: [
'./src/cli.ts',
'./src/index.ts',
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== packages/mcp/package.json =="
python - <<'PY'
import json
from pathlib import Path

pkg = Path('packages/mcp/package.json')
data = json.loads(pkg.read_text())
print(json.dumps({
    "name": data.get("name"),
    "types": data.get("types"),
    "typings": data.get("typings"),
    "exports": data.get("exports"),
}, indent=2))
PY

echo
echo "== declaration-related config under packages/mcp =="
rg -n "dts|declaration|emitDeclarationOnly|types" packages/mcp -g '!**/dist/**'

Repository: likec4/likec4

Length of output: 880


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Full packages/mcp/package.json (focusing on publication config) =="
cat packages/mcp/package.json | jq '{
  name,
  private,
  publishConfig,
  types,
  typings,
  main,
  module,
  bin,
  scripts,
  exports
}'

echo
echo "== packages/mcp/tsconfig.json (full) =="
cat packages/mcp/tsconfig.json

echo
echo "== Root tsconfig.json declaration settings =="
cat tsconfig.json | jq '{
  compilerOptions: .compilerOptions | {
    declaration,
    emitDeclarationOnly,
    declarationDir: .declarationDir,
    outDir: .outDir
  }
}'

Repository: likec4/likec4

Length of output: 289


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Full packages/mcp/package.json =="
cat packages/mcp/package.json

echo
echo "== packages/mcp/tsconfig.json =="
cat packages/mcp/tsconfig.json

echo
echo "== Root tsconfig.json compilerOptions (declaration-related) =="
cat tsconfig.json | head -50

Repository: likec4/likec4

Length of output: 4086


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== packages/mcp/build.config.ts (full) =="
cat packages/mcp/build.config.ts

echo
echo "== Check what 'obuild' is (package.json definition) =="
rg -A5 "obuild" pnpm-lock.yaml | head -30

echo
echo "== Root tsconfig declaration settings =="
cat tsconfig.json | jq '.compilerOptions | {declaration, emitDeclarationOnly, declarationDir, outDir}' 2>/dev/null || grep -A 20 '"compilerOptions"' tsconfig.json | head -25

Repository: likec4/likec4

Length of output: 1590


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Root tsconfig.json compilerOptions (raw grep) =="
sed -n '/"compilerOptions"/,/^  }/p' tsconfig.json

echo
echo "== Does packages/mcp/dist exist and what's in it? =="
if [ -d packages/mcp/dist ]; then
  find packages/mcp/dist -type f | head -20
else
  echo "(dist directory does not exist - likely not built yet)"
fi

echo
echo "== obuild documentation in node_modules =="
find node_modules/obuild -name "README*" -o -name "package.json" 2>/dev/null | head -5 | xargs cat 2>/dev/null | head -100

Repository: likec4/likec4

Length of output: 261


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Extended tsconfig base (what packages/mcp/tsconfig extends) =="
cat packages/tsconfig/base.json 2>/dev/null || cat node_modules/@likec4/tsconfig/base.json 2>/dev/null || find . -path "*/tsconfig/base.json" 2>/dev/null

echo
echo "== Check if any script or config generates .d.ts for packages/mcp =="
rg "packages/mcp|@likec4/mcp" pnpm-workspace.yaml turbo.json package.json -A 3 -B 1 2>/dev/null | head -50

echo
echo "== Look for any declaration generation config in root =="
cat package.json | grep -A 10 '"scripts"' | head -20

Repository: likec4/likec4

Length of output: 1581


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== packages/mcp/package.json build script =="
cat packages/mcp/package.json | grep -A 20 '"scripts"'

echo
echo "== Root package.json build-related scripts =="
cat package.json | grep -A 3 '"build"'

echo
echo "== What does obuild do with declarations when dts: false? =="
python3 <<'PYEOF'
import json
# Check if there's obuild documentation or examples
import subprocess
result = subprocess.run(['find', 'node_modules/obuild', '-name', '*.md', '-o', '-name', 'README*'], 
                       capture_output=True, text=True, timeout=5)
print("obuild docs:")
print(result.stdout[:500] if result.stdout else "(none found)")
PYEOF

Repository: likec4/likec4

Length of output: 1168


Add type declarations to the published package.

@likec4/mcp is published to npm with a programmatic API (./dist/index.mjs), but package.json lacks a types field and build.config.ts sets dts: false. TS consumers cannot access types for startLikeC4MCP/initLikeC4MCP.

Either:

  • Add "types": "./dist/index.d.ts" to package.json and enable dts: true in build.config.ts, or
  • Configure a separate declaration-emission step (the base tsconfig targets lib/ with emitDeclarationOnly: true, but files array excludes it)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mcp/build.config.ts` around lines 4 - 9, The package is published
without type declarations; enable declaration generation and point package.json
at the emitted .d.ts so consumers can use startLikeC4MCP/initLikeC4MCP. In
build.config.ts set dts: true for the entry that builds ./src/index.ts (the
entries array with type 'bundle' and input ['./src/cli.ts','./src/index.ts']),
then add a "types": "./dist/index.d.ts" field to package.json (or alternatively
add a separate declaration-emission step that uses your tsconfig with
emitDeclarationOnly and includes the lib/ files) so the dist .d.ts files are
produced and referenced.

Comment thread packages/mcp/src/cli.ts
Comment on lines +24 to +29
port: {
type: 'string',
description: 'change http port',
valueHint: 'number',
required: false,
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and read the relevant parts of the CLI file
cd packages/mcp/src && wc -l cli.ts

Repository: likec4/likec4

Length of output: 66


🏁 Script executed:

# Read the relevant sections
cat -n packages/mcp/src/cli.ts | sed -n '20,75p'

Repository: likec4/likec4

Length of output: 1955


🏁 Script executed:

# Also check if there are any imports or other context needed
cat -n packages/mcp/src/cli.ts | head -20

Repository: likec4/likec4

Length of output: 651


🏁 Script executed:

# Search for all uses of args.port in the cli.ts file
rg "args\.port" packages/mcp/src/cli.ts -n

Repository: likec4/likec4

Length of output: 234


🏁 Script executed:

# Check the rest of the run() function to see how port is used
cat -n packages/mcp/src/cli.ts | sed -n '56,88p'

Repository: likec4/likec4

Length of output: 1119


Reject invalid --port values before startup.

--port foo currently becomes NaN, and values like 12abc are partially parsed and passed through as if valid. Add validation in the setup() function to only accept integers between 1 and 65535.

Suggested validation
   setup({ args }) {
     if (args.stdio && (args.http || args.port)) {
       throw new Error('stdio and http are mutually exclusive')
     }
+    if (args.port !== undefined) {
+      const port = Number(args.port)
+      if (!Number.isInteger(port) || port < 1 || port > 65535) {
+        throw new Error('port must be an integer between 1 and 65535')
+      }
+    }
   },
   async run({ args }) {
     const useStdio = args.stdio || (!args.http && !args.port)

     process.on('uncaughtException', (err) => {
       logger.error('uncaughtException', { err })
     })

     process.on('unhandledRejection', (err) => {
       logger.error('unhandledRejection', { err })
     })

-    const port = args.port ? parseInt(args.port) : 33335
+    const port = args.port ? Number(args.port) : 33335
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mcp/src/cli.ts` around lines 24 - 29, The CLI currently allows
invalid --port values; add validation inside the setup() function to parse the
provided port option (referencing the port option in the CLI config) as an
integer only if the string is all digits (e.g. /^\d+$/), convert to
Number/parseInt, and ensure the resulting integer is between 1 and 65535; if the
value is invalid, reject it immediately by throwing an Error or exiting with a
clear message (e.g. "Invalid --port: must be integer 1-65535") so startup does
not continue with NaN or partial parses.

Comment thread packages/mcp/src/cli.ts Outdated
Comment thread packages/mcp/src/index.ts
Comment on lines +9 to +12
import { createTestServices } from '@likec4/language-server/test'
import { describe, expect, it } from 'vitest'
import { MCPServerFactory } from '../mcp/server/MCPServerFactory'
import { readDeployment } from '../mcp/tools/read-deployment'
import { readElement } from '../mcp/tools/read-element'
import { createTestServices } from '../test'
import { readDeployment } from './read-deployment'
import { readElement } from './read-element'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Keep this as a real integration test.

Calling readElement and readDeployment directly only verifies the tool implementations. It no longer exercises MCP server registration, name-based lookup, or the extracted @likec4/mcp wiring, so this .int.spec.ts can stay green while the integration path is broken. Please keep at least one path here that instantiates the server and resolves the tool through the registered MCP interface.

Based on learnings: "Write unit tests for agent functions and API integrations" and "Aim to cover new features with relevant tests and keep test names descriptive".

Also applies to: 33-36, 65-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mcp/src/tools/mcp-server-links.int.spec.ts` around lines 9 - 12, The
test currently only calls readElement and readDeployment directly; change it to
exercise the MCP server path by instantiating the test services with
createTestServices, registering or loading the tools, then resolving the tool
via the MCP server/name-based lookup and invoking it through that interface
(instead of or in addition to calling readElement/readDeployment directly).
Specifically, use createTestServices to bring up the MCP server, use the
server's registration/lookup API to find the tool by its registered name (the
same name the real wiring uses), then call the resolved tool and assert
results—ensuring the integration path (MCP registration + name lookup + tool
invocation) is covered in the .int.spec.ts.

- Fix typo in changeset ("toolst" → "tools")
- Remove duplicate process.on handlers in cli.ts (already registered by configureLogger)
- Forward throwIfInvalid option to fromWorkspace

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/mcp/src/cli.ts (1)

51-55: ⚠️ Potential issue | 🟠 Major

Validate and strictly parse --port before constructing HTTP transport.

Line [59] parses unchecked user input with parseInt, so values like 12abc become 12 and foo becomes NaN, which can still flow into mcp: { port }. Please reject invalid values in setup and parse with Number.parseInt(..., 10) only after validation.

Suggested fix
   setup({ args }) {
     if (args.stdio && (args.http || args.port)) {
-      throw new Error('stdio and http are mutually exclusive')
+      throw new Error('stdio is mutually exclusive with --http and --port')
+    }
+    if (args.port !== undefined) {
+      if (!/^\d+$/.test(args.port)) {
+        throw new Error('Invalid --port: must be integer 1-65535')
+      }
+      const port = Number.parseInt(args.port, 10)
+      if (port < 1 || port > 65535) {
+        throw new Error('Invalid --port: must be integer 1-65535')
+      }
     }
   },
   async run({ args }) {
     const useStdio = args.stdio || (!args.http && !args.port)

-    const port = args.port ? parseInt(args.port) : 33335
+    const port = args.port ? Number.parseInt(args.port, 10) : 33335
#!/bin/bash
set -euo pipefail

# Verify current parsing/validation behavior for --port in the CLI source
cat -n packages/mcp/src/cli.ts | sed -n '50,66p'
rg -n "args\.port|parseInt\(|Number\.parseInt\(|Invalid --port|port.*65535" packages/mcp/src/cli.ts -C2

Expected result: you should see parsing at Line 59 and no dedicated strict validation block for args.port in setup.

Also applies to: 59-59

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/mcp/src/cli.ts` around lines 51 - 55, The CLI accepts --port without
strict validation and later uses parseInt (parseInt(...)) so inputs like "12abc"
or "foo" can produce invalid numbers that flow into the mcp transport config
(mcp: { port }). Update the setup({ args }) function to strictly validate
args.port: if args.port is provided, ensure it's composed only of digits and
within 1–65535, then parse with Number.parseInt(args.port, 10) (or Number) and
assign the validated numeric port to the config; otherwise throw a clear Error
for invalid --port values so an invalid string never reaches mcp: { port }.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/mcp/src/cli.ts`:
- Around line 51-55: The CLI accepts --port without strict validation and later
uses parseInt (parseInt(...)) so inputs like "12abc" or "foo" can produce
invalid numbers that flow into the mcp transport config (mcp: { port }). Update
the setup({ args }) function to strictly validate args.port: if args.port is
provided, ensure it's composed only of digits and within 1–65535, then parse
with Number.parseInt(args.port, 10) (or Number) and assign the validated numeric
port to the config; otherwise throw a clear Error for invalid --port values so
an invalid string never reaches mcp: { port }.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4ced6481-9595-4662-b700-86b320c2ba8b

📥 Commits

Reviewing files that changed from the base of the PR and between 5addca0 and 89b9bc6.

📒 Files selected for processing (3)
  • .changeset/move-mcp-to-package.md
  • packages/mcp/src/cli.ts
  • packages/mcp/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/move-mcp-to-package.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/mcp/src/index.ts

Signed-off-by: Denis Davydkov <denis@davydkov.com>
@davydkov davydkov merged commit 51adb85 into main Apr 13, 2026
17 checks passed
@davydkov davydkov deleted the move-mcp-to-package branch April 13, 2026 07:40
@likec4-ci likec4-ci Bot mentioned this pull request Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant