Signal MCP
An MCP server that runs developer tooling commands (tests, linters, etc.) and returns compact, grouped error summaries to AI agents, reducing token usage and context window pollution. It supports multiple adapters for different tools and provides tools like run_check, diff_runs, and get_log_slice for iterative debugging.
README
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 tokens
How 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"
→ done
The model never sees the full log unless it explicitly requests a slice with get_log_slice.
Setup
npm install
npm run build
Create 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.json
Or 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_checks |
List all configured checks for the current project |
run_check |
Run a check and return the compact summary directly — no polling needed |
run_checks |
Run multiple checks in parallel and return all summaries at once |
start_check |
Start a check asynchronously. Returns run_id immediately |
get_run_status |
Get the status of a running or finished check |
get_run_summary |
Compact diagnostic: error groups with file/line occurrences |
diff_runs |
Compare two runs by fingerprint — shows what was fixed, what's new, what persists |
get_log_slice |
Read any line range from the raw log when more context is needed |
list_runs |
List recent runs, optionally filtered by check name |
rerun_failed |
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 needed
Run frontend and backend checks simultaneously:
run_checks { names: ["frontend_test", "backend_test"] } → both run in parallel, one summary per check
For 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 diagnostic
Summary options
get_run_summary and run_check accept these optional parameters:
| Option | Description |
|---|---|
max_groups |
Max error groups to return (default 5) |
max_occurrences |
Max occurrences per group (default 5) |
severity |
Filter by "error" or "warning" |
sort_by |
"count" (default — most frequent first), "last" (latest in log first, useful for cascading errors where the root cause appears last), "first" (earliest first) |
run_check also accepts:
| Option | Description |
|---|---|
max_wait_ms |
If the check exceeds this duration, return status: "running" with run_id instead of waiting |
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 |
Vitest | vitest in cmd |
jest |
Jest | jest in cmd |
pytest |
pytest — parses FAILED lines and traceback blocks |
pytest in cmd |
mocha |
Mocha N failing section |
mocha in cmd |
phpunit |
PHPUnit failure/error sections | phpunit in cmd |
phpstan |
PHPStan --error-format=json |
phpstan --error-format=json |
behat |
Behat "Failed scenarios:" block | behat in cmd |
pest |
Pest PHP ⨯ test name format |
pest in cmd |
phpspec |
PHPSpec failure blocks with spec class and line | phpspec in cmd |
rspec |
RSpec Failures: section with # file:line |
rspec in cmd |
eslint |
ESLint stylish multiline output | eslint in cmd |
biome |
Biome --reporter json output |
biome --reporter json |
rubocop |
RuboCop file:line:col: SEVERITY: Rule: msg |
rubocop in cmd |
bun_test |
Bun test runner ✗ test name format |
bun test in cmd |
go_test |
Go --- FAIL: TestName from go test ./... |
go test in cmd |
cargo_test |
Rust cargo test — panic sections with file/line |
cargo test in cmd |
cargo_clippy |
Rust cargo clippy — error[CODE]: + --> location |
cargo clippy in cmd |
playwright |
Playwright numbered failure blocks with browser tag | playwright in cmd |
cypress |
Cypress (Running: ...) blocks with numbered failures |
cypress in cmd |
json_log |
Structured JSON logs {"level":"error","message":"..."} |
— |
junit |
JUnit XML reports | — |
generic |
Any tool emitting file:line:col message — tsc, mypy, ruff, pyright, gcc, golangci-lint, and more |
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 |
|---|---|---|---|
cmd |
string | required | Shell command to run |
adapter |
string | auto-detected | Parser adapter name — omit to auto-detect from cmd |
timeout_ms |
number | 60000 |
Max execution time |
cwd |
string | project root | Working directory |
env |
object | — | Extra environment variables |
strip_path_prefix |
string | — | Strip this prefix from file paths in errors (useful for Docker paths) |
on_failure |
string | — | Command to run after a failure to capture extra context |
Per-check fields (multi-step)
| Field | Type | Default | Description |
|---|---|---|---|
steps |
array | required | Ordered list of steps, each with per-step fields above |
fail_fast |
boolean | true |
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
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。