Signal MCP
Provides an adapter to parse and summarize errors from Biome linting and formatting output.
Provides an adapter for the Bun test runner, parsing failing test names into compact diagnostics.
Provides an adapter to parse ESLint's stylish multiline output into grouped error reports.
Supports multiple PHP testing and static analysis tools: PHPUnit, PHPStan, Pest, and PHPSpec via dedicated adapters.
Provides an adapter to parse pytest failure output, extracting failed test names and traceback blocks.
Covered by the generic adapter, parsing file:line:col message output from Ruff linter.
Provides an adapter to parse Vitest test runner output into grouped error summaries.
Provides a JUnit XML adapter to parse test report XML files into error groups.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Signal MCPrun the test suite for the backend project"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Signal MCP
An MCP server that sits between an AI agent and your project's developer tooling — tests, linters, type checkers, builds — and compresses noisy output into compact, actionable diagnostics.
When an AI agent runs a test suite or linter directly, it receives hundreds or thousands of lines of raw output that flood the context window. Signal solves this by running the command, storing the full log on disk, parsing errors with a language-aware adapter, grouping duplicates by normalized fingerprint, and returning only a structured summary. The model sees one line per error group instead of the full log.
huge logs → grouped errors → compact diagnostic → fewer tokensHow it works
Agent → run_check("backend_test")
→ Signal runs the command
→ stores full log on disk
→ parses errors with the configured adapter (auto-detected if not set)
→ groups duplicates by fingerprint
→ returns: N failing tests, M groups + raw_tail if nothing parsed
→ Agent fixes code
→ run_check again
→ diff_runs → "2 fixed, 1 persisting"
→ doneThe model never sees the full log unless it explicitly requests a slice with get_log_slice.
Related MCP server: projscan
Setup
npm install
npm run buildCreate a signal.config.json in your project root (see signal.config.example.json for reference):
{
"projects": {
"my-project": {
"root": "/path/to/my-project",
"checks": {
"test": {
"cmd": "npx vitest run"
},
"lint": {
"cmd": "pnpm exec biome check src --reporter json 2>&1"
}
}
}
}
}The adapter field is optional — Signal auto-detects the right adapter from the command (vitest, pytest, cargo test, eslint, etc.). Set it explicitly only when auto-detection would be wrong.
Register as MCP server
node dist/index.js install --config /path/to/signal.config.jsonOr add it manually to your ~/.claude.json:
{
"mcpServers": {
"signal": {
"type": "stdio",
"command": "node",
"args": ["/path/to/signal-mcp/dist/index.js"],
"env": {
"SIGNAL_CONFIG": "/path/to/signal.config.json"
}
}
}
}Signal auto-detects the active project from the working directory — it matches any subdirectory of a configured project root.
Environment variables in config
Use ${VAR} in any string field of signal.config.json to avoid hardcoding machine-specific values like Docker container names or paths:
{
"projects": {
"my-project": {
"root": "/path/to/my-project",
"checks": {
"test": {
"cmd": "docker exec ${APP_CONTAINER} pytest"
}
}
}
}
}Define the variables in the MCP server registration so each developer sets their own values without touching the shared config:
{
"mcpServers": {
"signal": {
"type": "stdio",
"command": "node",
"args": ["/path/to/signal-mcp/dist/index.js"],
"env": {
"SIGNAL_CONFIG": "/path/to/signal.config.json",
"APP_CONTAINER": "my-app-container-1"
}
}
}
}If a variable is not set, the literal ${VAR} is kept unchanged. Variables without braces ($VAR) are not interpolated.
MCP tools
Tool | Description |
| List all configured checks for the current project |
| Run a check and return the compact summary directly — no polling needed |
| Run multiple checks in parallel and return all summaries at once |
| Start a check asynchronously. Returns |
| Get the status of a running or finished check |
| Compact diagnostic: error groups with file/line occurrences |
| Compare two runs by fingerprint — shows what was fixed, what's new, what persists |
| Read any line range from the raw log when more context is needed |
| List recent runs, optionally filtered by check name |
| Re-run a single failing test with verbose flags using the group fingerprint |
Typical agent workflow
1. list_checks → discover available checks
2. run_check { name: "test" } → summary returned directly
3. (fix the errors)
4. run_check { name: "test" } → run again after the fix
5. diff_runs { check: "test" } → verify what changed
6. get_log_slice { run_id, stream } → zoom into raw log if neededRun frontend and backend checks simultaneously:
run_checks { names: ["frontend_test", "backend_test"] } → both run in parallel, one summary per checkFor long-running checks (E2E, integration):
1. start_check { name: "e2e" } → run_id returned immediately
2. get_run_status { run_id } → poll until status != "running"
3. get_run_summary { run_id } → read the compact diagnosticSummary options
get_run_summary and run_check accept these optional parameters:
Option | Description |
| Max error groups to return (default 5) |
| Max occurrences per group (default 5) |
| Filter by |
|
|
run_check also accepts:
Option | Description |
| If the check exceeds this duration, return |
raw_tail fallback
When a check fails but the adapter parses zero errors (unrecognized output format), the summary automatically includes a raw_tail field with the last 30 lines of output — so the agent always has something actionable without needing get_log_slice.
Multi-step pipelines
For checks where order matters (clean → prepare → test):
{
"checks": {
"full": {
"steps": [
{ "name": "clean", "cmd": "rm -rf var/cache/*", "timeout_ms": 30000 },
{ "name": "prepare", "cmd": "bin/prepare-test-db", "timeout_ms": 120000 },
{ "name": "test", "cmd": "vendor/bin/behat", "timeout_ms": 300000 }
],
"fail_fast": true
}
}
}Each step gets its own adapter (auto-detected from cmd). get_run_summary returns which step failed and grouped errors from that step.
Adapters
Signal auto-detects the adapter from the command — no need to set adapter explicitly for common tools.
Adapter | Works with | Auto-detected from |
| Vitest |
|
| Jest |
|
| pytest — parses |
|
| Mocha |
|
| PHPUnit failure/error sections |
|
| PHPStan |
|
| Behat "Failed scenarios:" block |
|
| Pest PHP |
|
| PHPSpec failure blocks with spec class and line |
|
| RSpec |
|
| ESLint stylish multiline output |
|
| Biome |
|
| RuboCop |
|
| Bun test runner |
|
| Go |
|
| Rust |
|
| Rust |
|
| Playwright numbered failure blocks with browser tag |
|
| Cypress |
|
| Structured JSON logs | — |
| JUnit XML reports | — |
| Any tool emitting | fallback |
Adding an adapter is ~30–50 lines + tests. The interface is:
parse({ stdout, stderr, projectRoot }): ParsedError[]Fingerprint algorithm
Errors are grouped by a 12-character SHA1 fingerprint:
If a
symbolwas extracted (test name, function name):type:sym:<symbol>Otherwise:
type:msg:<normalized_message>— quoted strings →<str>, paths →<path>, numbers →N
Errors that differ only in line numbers, paths, or quoted values collapse into one group. diff_runs compares fingerprints between runs to identify fixed vs. new vs. persisting errors.
Storage layout
.signal/runs/<check>_<timestamp>_<random>/
├── stdout.log
├── stderr.log
├── meta.json
└── steps/ # only for multi-step runs
├── 1-clean/
├── 2-prepare/
└── 3-test/run_id is validated against ^[a-zA-Z0-9_-]+$ — path traversal is rejected before any disk I/O.
Runs are cleaned up automatically after each execution: the last 20 runs per check are kept, older ones are deleted.
Configuration reference
Per-check fields (single command)
Field | Type | Default | Description |
| string | required | Shell command to run |
| string | auto-detected | Parser adapter name — omit to auto-detect from |
| number |
| Max execution time |
| string | project root | Working directory |
| object | — | Extra environment variables |
| string | — | Strip this prefix from file paths in errors (useful for Docker paths) |
| string | — | Command to run after a failure to capture extra context |
Per-check fields (multi-step)
Field | Type | Default | Description |
| array | required | Ordered list of steps, each with per-step fields above |
| boolean |
| Stop pipeline on first failing step |
Development
npm test # run all tests (vitest)
npm run typecheck # tsc --noEmit
npm run build # compile to dist/Tests are colocated under tests/. Each adapter has its own .test.ts file.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/R0MADEV/signal'
If you have feedback or need assistance with the MCP directory API, please join our Discord server