Metadata-Version: 2.5
Name: rtl-lint-mcp
Version: 0.2.0
Summary: Portable RTL lint MCP server for Codex, VS Code, Cursor, KRutrim, and other MCP hosts
License: MIT
Requires-Python: >=3.10
Requires-Dist: mcp[cli]<3,>=2.0
Provides-Extra: krutrim
Requires-Dist: flask<4,>=3.1; extra == 'krutrim'
Provides-Extra: test
Requires-Dist: pytest<10,>=8; extra == 'test'
Description-Content-Type: text/markdown

# Portable RTL Lint MCP

<!-- mcp-name: io.github.jaspresi/rtl-lint-mcp -->

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

```text
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

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

### With a virtual environment

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

For the optional KRutrim Flask bridge:

```bash
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:

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

JSON output:

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

## Local MCP for any IDE

Run over stdio:

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

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

### Codex

From this directory:

```bash
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:

```bash
codex mcp list
```

Start a new Codex conversation, then ask:

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

### VS Code / GitHub Copilot Chat

Copy [`configs/vscode-mcp.json`](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`](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:

```bash
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:

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

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

```bash
--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:

```text
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:

```json
{
  "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`](integrations/krutrim/README.md) for the
two deployment choices, the small Flask dispatcher patch, and a matching
front-end invocation example.

## Docker deployment

```bash
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:

```json
{
  "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:

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

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

```bash
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

- Official MCP Python SDK: https://py.sdk.modelcontextprotocol.io/
- VS Code MCP configuration: https://code.visualstudio.com/docs/agents/reference/mcp-configuration
