CASE FILE#4842INFOFiled 2026-06-16

MCP Tool-Call Governance: Putting Guardrails on MCP Servers

When your AI coding agent connects to an MCP server, every tool that server exposes becomes a live action the agent can take. SSG evaluates MCP tool calls the same way it evaluates native ones -- before they execute, in under 2ms.

Case ID
#4842
Severity
INFO
Decision
BLOCK
Agent
All Agents
Category
Governance

What MCP is and why it matters for security

The Model Context Protocol (MCP) is the standard that lets AI coding agents -- Claude Code, Cursor, VS Code Copilot, and others -- connect to external servers and use their tools. An MCP server might expose tools to query a database, call an API, search a file system, or execute shell commands.

When your agent connects to an MCP server, every tool that server exposes becomes a live action the agent can take. The agent sees the tool's description, decides when to call it, and calls it -- with arguments it constructed from your prompt and its current context.

That is a much larger attack surface than it looks.

The risk of an untrusted MCP server

An MCP server you install is code running on your machine (or on a remote host you trust). Most MCP servers are legitimate and useful. But the model connecting to them does not verify the server's identity -- it reads the server's self-reported tool descriptions and acts on them.

A malicious or compromised MCP server can:

  • Describe a tool as doing one thing while doing another (prompt injection via tool description)
  • Expose tools with broad filesystem or shell access that the agent will use freely
  • Exfiltrate context by having the agent call a logging or webhook tool with sensitive data
  • Trigger actions in other connected systems when the agent uses the tool

None of this requires the model to behave unexpectedly. The model is doing exactly what it was asked to do. The risk is that "what it was asked to do" was defined by a server you do not fully control.

How SSG governs MCP tool calls

SSG governs AI agent tool calls at the point where the agent makes them -- before they execute. For MCP tool calls, this means SSG evaluates the call at the agent's hook layer, the same way it evaluates native shell commands, file reads, and file writes.

The MCP tool call arrives as a structured JSON payload: the server name, the tool name, and the arguments. SSG evaluates this payload against your rules and returns a decision before the call reaches the MCP server.

Agent decides to call MCP tool
         |
         v
SSG hook (PreToolUse / MCP middleware)
         |
    Rule evaluation (~0.3ms round-trip)
         |
    ALLOW / DENY / ASK / FORCE
         |
         v
MCP server receives the call (or not)

FORCE refuses the original risky action and returns a safe substitute or required safer path for the agent to use next, so MCP governance can redirect an unsafe tool call instead of only blocking or asking.

This works regardless of which MCP server you are talking to, and regardless of whether the server is local or remote.

A real example: an MCP server with shell access

The filesystem and shell MCP servers are commonly installed for development. The filesystem server exposes tools like read_file, write_file, and list_directory. The shell server exposes run_command.

Without governance, the agent has unrestricted access to these tools. With SSG, you write rules that scope what the agent can do through each server.

Add to .sigmashake/rules/mcp.rules:

rule mcp-no-shell-destructive {
  enabled true
  priority 100
  severity critical
  DENY execution
  IF server EQUALS "shell"
  AND tool EQUALS "run_command"
  AND arguments.command REGEX "rm\\s+-[a-zA-Z]*r[a-zA-Z]*f"
  MESSAGE "Recursive force-delete via the shell MCP server is blocked."
}

rule mcp-no-secret-file-read {
  enabled true
  priority 100
  severity critical
  DENY execution
  IF server EQUALS "filesystem"
  AND tool EQUALS "read_file"
  AND arguments.path GLOB "**/.env*"
  OR arguments.path GLOB "**/*.pem"
  OR arguments.path GLOB "**/id_rsa"
  MESSAGE "Secret file read via the filesystem MCP server is blocked."
}

rule mcp-ask-unknown-server {
  enabled true
  priority 80
  severity warning
  ASK execution
  IF server NOT IN ["filesystem", "shell", "github", "postgres"]
  MESSAGE "Tool call from an unrecognized MCP server requires human approval."
}

The third rule is the important one: any tool call from a server not on your explicit allowlist goes to a human for approval. This catches newly added servers, servers the agent installs on its own, and any server with an unexpected name.

Scoping by server and tool

The server and tool fields in the rule DSL let you write fine-grained policies:

rule mcp-github-read-only {
  enabled true
  priority 90
  severity error
  DENY execution
  IF server EQUALS "github"
  AND tool IN ["create_repository", "delete_repository", "push_files"]
  MESSAGE "Write operations on the GitHub MCP server are not allowed. Use the terminal for git operations."
}

rule mcp-db-no-write {
  enabled true
  priority 90
  severity error
  DENY execution
  IF server EQUALS "postgres"
  AND tool IN ["query"]
  AND arguments.sql REGEX "(?i)\\b(INSERT|UPDATE|DELETE|TRUNCATE)\\b"
  MESSAGE "Write queries via the Postgres MCP server are blocked. The agent has read-only access."
}

These rules let the agent use the GitHub MCP server to read issues, pull requests, and repository metadata -- but block any write operations. The Postgres rule lets the agent run SELECT queries but blocks any statement that modifies data.

Why you should maintain an explicit server allowlist

The mcp-ask-unknown-server rule above is a useful baseline, but a stricter approach is to deny unknown servers by default and require explicit opt-in for each one:

rule mcp-deny-unknown-server {
  enabled true
  priority 75
  severity error
  DENY execution
  IF server NOT IN ["filesystem", "shell", "github", "postgres", "brave-search"]
  MESSAGE "MCP server is not on the allowlist. Add it to mcp.rules before using it."
}

This means a newly added MCP server -- one that appears in your .mcp.json or mcpServers config but has not been reviewed -- cannot be used until you explicitly add it to the rule. The agent will see the block message and you will know to review the server.

What the audit log shows

Every MCP tool call evaluated by SSG appears in the audit log with full context:

[ALLOW] mcp:filesystem/read_file  path=src/utils.ts             (8us)
[ALLOW] mcp:github/get_issue      number=42                     (11us)
[BLOCK] mcp:filesystem/read_file  path=.env                     (9us)
        rule: mcp-no-secret-file-read
[ASK]   mcp:unknown-server/exec   cmd=ls -la                    (14us)
        rule: mcp-ask-unknown-server -- pending approval

This gives you a complete record of what the agent did through each MCP server, which lets you audit for unexpected tool usage, spot servers the agent connected to that you did not configure, and verify that sensitive operations were either blocked or explicitly approved.

Deploying MCP governance today

# macOS / Linux - free installer
curl -fsSL https://install.sigmashake.com | sh

# Windows (PowerShell)
# iwr -useb https://install.sigmashake.com/install.ps1 | iex

# Initialize (wires the MCP middleware automatically for supported clients)
ssg init --client=claude
ssg init --client=cursor
ssg init --client=vscode

# Pull the MCP governance ruleset from the Hub
ssg hub pull rules-mcp

# Start the daemon
ssg daemon &

# Open the dashboard (ASK decisions from unrecognized servers queue here)
ssg serve

After initialization, every MCP tool call from the configured agent goes through SSG before it reaches the server. The first time the agent tries to read .env through the filesystem server, you will see:

[BLOCK] mcp:filesystem/read_file -- rule: mcp-no-secret-file-read (9us)

That block is the whole point. The server never received the call.

MCP governance is one piece of a larger system: see how policy, enforcement, ASK approvals, and audit combine in the control plane for AI agents.

Links: Download · Docs · Playground · Hub

Filed by All Agents
Engine ssg v1 · 2026-06-16
End of case file

Stop reading. Start governing.

Test a rule against any tool call right now. No install required.