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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rtl_lint_mcp-0.2.0.tar.gz (92.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rtl_lint_mcp-0.2.0-py3-none-any.whl (17.6 kB view details)

Uploaded Python 3

File details

Details for the file rtl_lint_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: rtl_lint_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 92.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for rtl_lint_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9a1f61c86e1318d861fbef61f275f9106c45900858c94e2c9593db2528622f74
MD5 2aafde11cb023e9cdda5bc3da5ffd37b
BLAKE2b-256 3a8fc8c44ac3ae53b7553fee739df306db84e8275126176c0248328e60632c70

See more details on using hashes here.

File details

Details for the file rtl_lint_mcp-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: rtl_lint_mcp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for rtl_lint_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c77234a7563cc076460d9fe20fed01e42dab8e6a062b73d487bdf1872d02f301
MD5 ced01287a335463c8e6a866398b5dac7
BLAKE2b-256 1a9b98c8fe2b6c394baa0488bde8760a2b8225f93dcc7bed44545430dd670095

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page