Architecture
How a validated MCP call becomes cached, clustered diagnostics while local engines remain authoritative.
Signalint is a local stdio MCP server. Adapters are the only modules that invoke diagnostic engines; every layer above them operates on normalized issue objects. The implementation is static and local: no cloud service is required.
check_files data flow
- The server validates the tool object through strict Zod schemas.
- Requested paths are resolved against the project root and checked again after symlink canonicalization.
- Ignore globs and unconditional
node_modulesexclusion remove out-of-scope paths. - Signalint reads snapshots and computes engine configuration hashes.
- File-local cache hits are reused; Oxlint and optional Biome receive only misses.
- tsc is skipped only when supplied TypeScript-relevant snapshots still match the latest whole-program result.
- Enabled engines settle independently, so one failure does not discard another engine's diagnostics.
- Issues are normalized, filtered, clustered, sorted with priority 1 first, and limited to ten clusters by default.
- Loop state and metrics are recorded before the JSON response is returned.
Engine invocation strategy
Oxlint and Biome
These engines are file-local. A check_files call hashes each file, reuses SQLite entries on a complete key match, and sends only cache misses to the adapter.
TypeScript
tsc is whole-program. Supplied file hashes decide whether a run is necessary, but files are never passed as compiler roots. A normal root config uses --project with incremental state. A solution-style root containing references uses --build, so referenced composite projects are traversed.
Storage bounds
The SQLite cache refreshes timestamps on read and evicts least-recently-used rows above 10,000 entries. Session startup replays only a bounded recent tail; writes rotate the JSONL file to a .1 backup at its size limit. Stats include both retained files.
Trust boundary
MCP arguments are treated as untrusted because a model can be prompt-injected by project content. Absolute, escaping, leading-dash, and NUL-containing paths are rejected, argument arrays are capped, and adapters spawn resolved binaries without a shell.
Read the full current implementation overview in ARCHITECTURE.md and the threat model in SECURITY.md.