Extract MCP server into standalone @likec4/mcp package#2877
Conversation
🦋 Changeset detectedLatest commit: 9d0ec87 The changes in this PR will be included in the next version bump. This PR includes changesets to release 21 packages
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>
1fc377a to
5addca0
Compare
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughExtracts the MCP server and tooling into a new standalone Changes
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
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 | 🔴 CriticalMove all external runtime dependencies to
dependencies(notdevDependencies).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 underdevDependencies. When this package is published and installed standalone (e.g.,npm install@likec4/mcp``), or used programmatically outside the monorepo, these missingdependenciesentries 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
ProjectsManagerever changes its default or resolves aliases, omittedprojectvalues will stop behaving like the rest of the code path. Let the schema stay optional and keep default resolution insideensureProjectId(...).♻️ 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: ExtractLikeC4MCPServerinto 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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (88)
.changeset/move-mcp-to-package.mdapps/docs/src/content/docs/tooling/ai-tools.mdxpackages/language-server/build.config.tspackages/language-server/package.jsonpackages/language-server/src/LikeC4LanguageServices.tspackages/language-server/src/browser/index.tspackages/language-server/src/common-exports.tspackages/language-server/src/empty.tspackages/language-server/src/index.tspackages/language-server/src/mcp/index.tspackages/language-server/src/mcp/noop.tspackages/language-server/src/mcp/server/WithMCPServer.tspackages/language-server/src/mcp/types.tspackages/language-server/src/module.tspackages/language-services/README.mdpackages/language-services/build.config.tspackages/language-services/package.jsonpackages/language-services/src/node/createLanguageServices.tspackages/language-services/src/node/index.tspackages/language-services/src/node/without-mcp/createLanguageServices.tspackages/language-services/src/node/without-mcp/index.tspackages/likec4/package.jsonpackages/likec4/src/cli/build/index.tspackages/likec4/src/cli/codegen/custom.tspackages/likec4/src/cli/codegen/handler.tspackages/likec4/src/cli/codegen/leanix-dry-run.tspackages/likec4/src/cli/codegen/leanix-reconcile.tspackages/likec4/src/cli/codegen/model/index.tspackages/likec4/src/cli/codegen/react/index.tspackages/likec4/src/cli/codegen/webcomponent/handler.tspackages/likec4/src/cli/export/json/handler.tspackages/likec4/src/cli/export/png/handler.tspackages/likec4/src/cli/format/index.tspackages/likec4/src/cli/mcp/index.tspackages/likec4/src/cli/preview/preview.tspackages/likec4/src/cli/serve/serve.tspackages/likec4/src/cli/sync/leanix.tspackages/likec4/src/cli/validate/index.tspackages/likec4/tsconfig.cli.jsonpackages/mcp/README.mdpackages/mcp/build.config.tspackages/mcp/package.jsonpackages/mcp/src/cli.tspackages/mcp/src/empty.tspackages/mcp/src/index.tspackages/mcp/src/server/StdioLikeC4MCPServer.tspackages/mcp/src/server/StreamableLikeC4MCPServer.tspackages/mcp/src/server/createMCPServer.tspackages/mcp/src/tools/_common.spec.tspackages/mcp/src/tools/_common.tspackages/mcp/src/tools/batch-read-elements.spec.tspackages/mcp/src/tools/batch-read-elements.tspackages/mcp/src/tools/cloud-system-integration.spec.tspackages/mcp/src/tools/element-diff.spec.tspackages/mcp/src/tools/element-diff.tspackages/mcp/src/tools/find-relationship-paths.spec.tspackages/mcp/src/tools/find-relationship-paths.tspackages/mcp/src/tools/find-relationships.tspackages/mcp/src/tools/list-projects.tspackages/mcp/src/tools/mcp-server-links.int.spec.tspackages/mcp/src/tools/mcp-tools-links.spec.tspackages/mcp/src/tools/open-view.tspackages/mcp/src/tools/query-by-metadata.spec.tspackages/mcp/src/tools/query-by-metadata.tspackages/mcp/src/tools/query-by-tag-pattern.spec.tspackages/mcp/src/tools/query-by-tag-pattern.tspackages/mcp/src/tools/query-by-tags.spec.tspackages/mcp/src/tools/query-by-tags.tspackages/mcp/src/tools/query-graph.spec.tspackages/mcp/src/tools/query-graph.tspackages/mcp/src/tools/query-incomers-graph.spec.tspackages/mcp/src/tools/query-incomers-graph.tspackages/mcp/src/tools/query-outgoers-graph.spec.tspackages/mcp/src/tools/query-outgoers-graph.tspackages/mcp/src/tools/read-deployment.tspackages/mcp/src/tools/read-element.tspackages/mcp/src/tools/read-project-summary.tspackages/mcp/src/tools/read-view.tspackages/mcp/src/tools/search-element.tspackages/mcp/src/tools/subgraph-summary.spec.tspackages/mcp/src/tools/subgraph-summary.tspackages/mcp/src/utils.tspackages/mcp/tsconfig.jsonpackages/mcp/vitest.config.tspackages/vite-plugin/src/plugin.tspackages/vscode/package.jsonpackages/vscode/src/node/mcp-server.tspackages/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
| '@likec4/language-server': patch | ||
| '@likec4/language-services': patch |
There was a problem hiding this comment.
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.
| entries: [{ | ||
| type: 'bundle', | ||
| input: './src/index.ts', | ||
| input: [ | ||
| './src/cli.ts', | ||
| './src/index.ts', | ||
| ], |
There was a problem hiding this comment.
🧩 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 -50Repository: 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 -25Repository: 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 -100Repository: 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 -20Repository: 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)")
PYEOFRepository: 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"topackage.jsonand enabledts: trueinbuild.config.ts, or - Configure a separate declaration-emission step (the base tsconfig targets
lib/withemitDeclarationOnly: true, butfilesarray 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.
| port: { | ||
| type: 'string', | ||
| description: 'change http port', | ||
| valueHint: 'number', | ||
| required: false, | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and read the relevant parts of the CLI file
cd packages/mcp/src && wc -l cli.tsRepository: 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 -20Repository: 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 -nRepository: 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.
| 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' |
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/mcp/src/cli.ts (1)
51-55:⚠️ Potential issue | 🟠 MajorValidate and strictly parse
--portbefore constructing HTTP transport.Line [59] parses unchecked user input with
parseInt, so values like12abcbecome12andfoobecomesNaN, which can still flow intomcp: { port }. Please reject invalid values insetupand parse withNumber.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 -C2Expected result: you should see parsing at Line 59 and no dedicated strict validation block for
args.portinsetup.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
📒 Files selected for processing (3)
.changeset/move-mcp-to-package.mdpackages/mcp/src/cli.tspackages/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>
Summary
@likec4/language-serverinto dedicated@likec4/mcppackage for reuse and modularitylikec4.mcp.enabledandlikec4.mcp.portVSCode settings — MCP is now auto-registered via VSCode's native MCP provider (stdio)Test plan
likec4 mcpCLI still works with stdio and http transportsnpx @likec4/mcpworks standalone🤖 Generated with Claude Code