Skip to main content

Portable RTL Lint MCP

This package moves the RTL lint engine out of a VS Code extension and exposes one stable service to every client:

Codex / VS Code / Cursor / another MCP IDE
                    |
              MCP protocol
        +-----------+------------+
        |                        |
   stdio (local)       Streamable HTTP (remote)
        |                        |
        +------ rtl_lint_mcp ----+
                       |
             shared lint service
                       |
          Verilog / SystemVerilog files

KRutrim can use the same service through its existing custom /api/mcp/invoke dispatcher or, after it gains a standard MCP registry, by connecting to the remote /mcp endpoint.

Why this is portable

  • The lint engine is a normal Python package, not stored inside an IDE extension.
  • The official MCP Python SDK handles protocol messages and tool schemas.
  • Local IDEs use stdio; deployed clients use Streamable HTTP.
  • CLI, MCP, VS Code, and KRutrim receive the same rtl-lint-report.v1 schema.
  • File access is restricted by RTL_LINT_ALLOWED_ROOTS.
  • There are no repository-specific absolute paths in the implementation.

Tools

  • list_rtl_lint_rules
  • lint_rtl_text
  • lint_rtl_file
  • lint_rtl_project

Requirements

  • Python 3.10 or newer. KRutrim currently reports Python 3.11.13, so it meets this requirement.
  • uv is recommended, but a Python virtual environment also works.

Install

With uv

cd tools/rtl-lint-mcp-portable
uv sync

With a virtual environment

cd tools/rtl-lint-mcp-portable
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install -e .

For the optional KRutrim Flask bridge:

python3 -m pip install -e '.[krutrim]'

Local CLI smoke test

The server rejects file paths outside its allowlist. Set the project root before running a file or project check:

export RTL_LINT_ALLOWED_ROOTS=/path/to/rtl/project
rtl-lint /path/to/rtl/project/rtl/top.sv --fail-on never

JSON output:

rtl-lint /path/to/rtl/project/rtl/top.sv --json --fail-on never

Local MCP for any IDE

Run over stdio:

export RTL_LINT_ALLOWED_ROOTS=/path/to/rtl/project
rtl-lint-mcp

Normally the IDE starts this command itself. Use configs/generic-stdio.json as the base for any client that accepts an mcpServers configuration.

Codex

From this directory:

codex mcp add rtl-lint \
  --env RTL_LINT_ALLOWED_ROOTS=/path/to/rtl/project \
  -- uv run --project /absolute/path/to/rtl-lint-mcp-portable rtl-lint-mcp

Verify:

codex mcp list

Start a new Codex conversation, then ask:

Use the RTL lint MCP to lint /path/to/rtl/project/rtl/top.sv.

VS Code / GitHub Copilot Chat

Copy configs/vscode-mcp.json to .vscode/mcp.json, replace the package path, and open the folder in VS Code. Use MCP: List Servers to start and inspect it. In Remote SSH, install/run the server on the remote host so the MCP process can see the remote RTL path.

Other IDEs

For Cursor, Claude-compatible clients, and other MCP hosts, start from configs/generic-stdio.json. Replace:

  • the absolute package path;
  • RTL_LINT_ALLOWED_ROOTS with the RTL workspace;
  • uv with the environment's full executable path when necessary.

Remote Streamable HTTP server

Run the same MCP as a network service:

export RTL_LINT_ALLOWED_ROOTS=/ws:/auto
rtl-lint-mcp --transport streamable-http \
  --host 0.0.0.0 \
  --port 8765 \
  --allowed-host fpga-vm-bgl002.cisco.com:8765

Endpoint:

http://fpga-vm-bgl002.cisco.com:8765/mcp

If a browser calls the endpoint directly, also allow the KRutrim origin:

--allowed-origin http://fpga-vm-bgl002.cisco.com:5200

Do not expose the service beyond the Cisco network without authentication and TLS. The hostname/origin allowlist prevents DNS-rebinding attacks; it is not user authentication.

KRutrim integration

The inspected KRutrim service is a Flask application. Its front end calls:

POST /api/mcp/invoke

with payloads containing toolId, action, and target. Its output renderer uses the first available string among response, answer, completion, output, or text.

The bridge therefore returns:

{
  "output": "Markdown report for the KRutrim panel",
  "result": {"schema_version": "rtl-lint-report.v1"},
  "backend": "rtl-lint-mcp",
  "tool_id": "rtl_lint"
}

See integrations/krutrim/README.md for the two deployment choices, the small Flask dispatcher patch, and a matching front-end invocation example.

Docker deployment

docker build -t rtl-lint-mcp:0.2.0 .
docker run --rm -p 8765:8765 \
  -v /ws:/workspace:ro \
  -e RTL_LINT_ALLOWED_ROOTS=/workspace \
  -e RTL_LINT_ALLOWED_HOSTS=fpga-vm-bgl002.cisco.com:8765 \
  rtl-lint-mcp:0.2.0

Mount RTL read-only. The linter never needs write access.

Report contract

A single-file call returns a direct report, not a project wrapper:

{
  "schema_version": "rtl-lint-report.v1",
  "server_version": "0.2.0",
  "operation": "lint_file",
  "file": "/project/rtl/top.sv",
  "issue_count": 1,
  "summary": {"error": 1, "warning": 0, "info": 0},
  "issues": []
}

This avoids the earlier VS Code integration bug where a caller expected result.issues but the CLI returned result.files[0].issues.

Test

Core tests need only the standard library:

PYTHONPATH=src python3 -m unittest discover -s tests -v

For protocol testing, install the development environment and use the official MCP Inspector:

uv run mcp dev src/rtl_lint_mcp/server.py

Production checklist

  1. Keep RTL_LINT_ALLOWED_ROOTS narrow and explicit.
  2. Mount repositories read-only for the HTTP service.
  3. Use TLS and authenticated access for any non-local endpoint.
  4. Keep the MCP sidecar on an internal interface or behind the KRutrim proxy.
  5. Add the rtl_lint dispatch case to KRutrim's existing route.
  6. Add a KRutrim UI action that sends toolId: rtl_lint and the selected path.
  7. Run the included tests and the MCP Inspector before deployment.

Important limitation

This is a lightweight text-pattern linter. It is useful for early feedback and demonstrations, but it does not replace compilation, synthesis, formal checks, or sign-off lint products.

References

Metadata

Release files for rtl-lint-mcp 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for rtl-lint-mcp 0.2.0
File Size Uploaded
rtl_lint_mcp-0.2.0.tar.gz 92.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for rtl-lint-mcp 0.2.0
File Interpreter ABI Platform
rtl_lint_mcp-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 110.4 kB

Release files / rtl_lint_mcp-0.2.0.tar.gz

Download URL rtl_lint_mcp-0.2.0.tar.gz
Size 92.9 kB
Tags Source
SHA-256 checksum
How to use checksums
9a1f61c86e1318d861fbef61f275f9106c45900858c94e2c9593db2528622f74
BLAKE2b-256 checksum
How to use checksums
3a8fc8c44ac3ae53b7553fee739df306db84e8275126176c0248328e60632c70
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / rtl_lint_mcp-0.2.0-py3-none-any.whl

Download URL rtl_lint_mcp-0.2.0-py3-none-any.whl
Size 17.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c77234a7563cc076460d9fe20fed01e42dab8e6a062b73d487bdf1872d02f301
BLAKE2b-256 checksum
How to use checksums
1a9b98c8fe2b6c394baa0488bde8760a2b8225f93dcc7bed44545430dd670095
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page