MCP Server
Run shellfirm as an MCP server for AI coding agents
shellfirm implements a Model Context Protocol (MCP) server that AI agents can connect to for command safety checks. The server runs over stdio using JSON-RPC 2.0.
Starting the server
shellfirm mcp
This starts the MCP server, reading JSON-RPC requests from stdin and writing responses to stdout. The server runs until stdin is closed.
Exposed tools
The MCP server exposes four tools:
| Tool | Purpose |
|---|---|
check_command | Check if a shell command is risky. Returns a full risk assessment. |
suggest_alternative | Get safer alternative commands for a risky command. |
get_policy | Get the current shellfirm configuration and active policy. |
explain_risk | Get a detailed explanation of why a command is risky. |
check_command
The primary tool. Send a command and receive a structured risk assessment.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "check_command",
"arguments": {
"command": "git push --force origin main"
}
}
}
Response (risky command):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{
"type": "text",
"text": "{\"allowed\":false,\"risk_level\":\"Normal\",\"severity\":\"High\",\"matched_rules\":[{\"id\":\"git:force_push\",\"description\":\"Force push can overwrite remote history.\",\"severity\":\"High\",\"group\":\"git\"}],\"alternatives\":[{\"command\":\"git push --force-with-lease\",\"explanation\":\"Prevents overwriting others' work\",\"source\":\"regex-pattern\"}],\"context\":{\"risk_level\":\"Normal\",\"labels\":[]},\"requires_human_approval\":false,\"denial_reason\":\"Severity HIGH meets or exceeds agent auto-deny threshold HIGH\"}"
}]
}
}
Response (safe command):
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [{
"type": "text",
"text": "{\"allowed\":true,\"risk_level\":\"Normal\",\"severity\":null,\"matched_rules\":[],\"alternatives\":[],\"context\":{\"risk_level\":\"Normal\",\"labels\":[]},\"requires_human_approval\":false}"
}]
}
}
RiskAssessment fields
The check_command tool returns a RiskAssessment JSON object:
| Field | Type | Description |
|---|---|---|
allowed | boolean | Whether the command is safe to execute |
risk_level | string | Normal, Elevated, or Critical |
severity | string or null | Highest severity among matched rules (Info, Low, Medium, High, Critical) |
matched_rules | array | List of matched check patterns |
alternatives | array | Safer alternative commands |
context | object | Runtime context with risk_level and labels |
requires_human_approval | boolean | Whether human approval is needed |
denial_reason | string or null | Explanation for why the command was denied |
blast_radius_scope | string or null | Scope of impact (RESOURCE, PROJECT, MACHINE) |
blast_radius_detail | string or null | Human-readable impact description |
Each entry in matched_rules contains:
| Field | Type | Description |
|---|---|---|
id | string | Pattern ID (e.g., git:force_push) |
description | string | Human-readable description of the risk |
severity | string | Info, Low, Medium, High, or Critical |
group | string | Check group (e.g., git, fs, kubernetes) |
blast_radius_scope | string or null | Impact scope for this specific match |
blast_radius_detail | string or null | Impact detail for this specific match |
suggest_alternative
Get safer alternatives for a risky command.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "suggest_alternative",
"arguments": {
"command": "git push --force"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [{
"type": "text",
"text": "{\"command\":\"git push --force\",\"alternatives\":[{\"command\":\"git push --force-with-lease\",\"explanation\":\"Prevents overwriting others' work\",\"source\":\"regex-pattern\"}]}"
}]
}
}
get_policy
Retrieve the current shellfirm configuration and active policy.
Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "get_policy",
"arguments": {}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"content": [{
"type": "text",
"text": "{\"challenge\":\"Math\",\"active_groups\":[\"aws\",\"azure\",\"base\",\"database\",\"docker\",\"fs\",\"gcp\",\"git\",\"heroku\",\"kubernetes\",\"mongodb\",\"mysql\",\"network\",\"psql\",\"redis\",\"terraform\"],\"active_checks_count\":87,\"min_severity\":null,\"audit_enabled\":true,\"agent_config\":{\"auto_deny_severity\":\"High\",\"require_human_approval\":false},\"session_id\":\"abc-123\"}"
}]
}
}
explain_risk
Get a detailed explanation of why a command is risky.
Request:
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "explain_risk",
"arguments": {
"command": "rm -rf /"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [{
"type": "text",
"text": "{\"command\":\"rm -rf /\",\"risky\":true,\"allowed\":false,\"severity\":\"Critical\",\"risk_level\":\"Normal\",\"context\":{\"risk_level\":\"Normal\",\"labels\":[]},\"matched_rules\":[{\"id\":\"fs:recursively_delete\",\"description\":\"Recursive delete can destroy files irreversibly\",\"severity\":\"High\",\"group\":\"fs\"}],\"alternatives\":[],\"explanation\":\"- [HIGH] fs:recursively_delete: Recursive delete can destroy files irreversibly\"}"
}]
}
}
Protocol details
The MCP server implements the following JSON-RPC 2.0 methods:
| Method | Type | Description |
|---|---|---|
initialize | Request | Returns server capabilities and version info |
notifications/initialized | Notification | Client acknowledgment (no response) |
tools/list | Request | Returns the list of available tools |
tools/call | Request | Invokes a tool by name with arguments |
Protocol version: 2024-11-05
Error handling
Tool errors are returned as content with isError: true rather than as JSON-RPC errors. This follows the MCP convention:
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"content": [{
"type": "text",
"text": "Error: Missing 'command' parameter"
}],
"isError": true
}
}
JSON-RPC level errors (parse errors, unknown methods) use standard error codes:
-32700-- Parse error (invalid JSON)-32601-- Method not found