Observed since 20 Oct, 18:25 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
acrf-mcp-scan
MCP server inventory and risk scanner. Implements ACRF-03 defense pattern.
MCP server inventory and risk scanner. Implements the ACRF-03 (MCP Server Sprawl) defense pattern.
Part of the ACRF framework: https://github.com/kannasekar-alt/ACRF PyPI: https://pypi.org/project/acrf-mcp-scan/ Presented at RSA Conference 2026.
No Docker. No setup. Just Python 3.10+.
Step 1 - Install:
pip install acrf-mcp-scan
Step 2 - Scan your MCP config file:
from acrf_mcp_scan import MCPScanner
scanner = MCPScanner()
inventory = scanner.scan_config_file("mcp_config.json")
for server in inventory.suspicious_servers():
print(f"WARNING {server.name}: {server.risk_summary()}")
Step 3 - Scan a directory of MCP servers:
inventory = scanner.scan_directory("/opt/mcp-servers")
Step 4 - Compare against your approved inventory:
from acrf_mcp_scan import MCPServerInventory
trusted = MCPServerInventory.load("approved_mcp.json")
diff = inventory.diff(trusted)
for unauthorized in diff.added:
print(f"UNAUTHORIZED: {unauthorized.name}")
for missing in diff.removed:
print(f"MISSING APPROVED: {missing.name}")
If anything is unauthorized or anything has changed in command/args/version, your application can fail closed and refuse to start.
MCP server registries make it trivial to install third-party agent capabilities. That trivial install is also an unbounded attack surface. Antiy CERT 2025 documented over 1,000 malicious MCP servers in public registries, including postmark-mcp which silently exfiltrated email content for months before being noticed.
This is ACRF-03: MCP server sprawl.
acrf-mcp-scan inventories every MCP server in your environment, flags suspicious ones with a configurable rule set, and lets you compare your running inventory against an approved baseline.
The scanner checks each MCP server for:
Configuration risks
Source code risks
Manifest risks
Each finding has a severity (low, medium, high, critical) and the server risk_level is the maximum severity of its findings.
Build an inventory:
acrf-mcp-scan inventory mcp_config.json --out current_inventory.json
Check what is suspicious without writing anywhere:
acrf-mcp-scan check mcp_config.json
Compare current state against an approved baseline:
acrf-mcp-scan compare current_inventory.json approved_mcp.json
Output when clean:
Scanned 4 server(s) at mcp_config.json
Risk: critical=0 high=0 medium=0 low=0 none=4
OK: no suspicious servers
Output when risky:
Scanned 5 server(s) at mcp_config.json
Risk: critical=1 high=0 medium=2 low=0 none=2
Suspicious (3):
[CRITICAL] TicketApp
- critical: auto_approve_destructive (autoApprove contains destructive ops: ["refund_all"])
[MEDIUM] EmailServer
- medium: auto_approve_present (autoApprove list has 3 entries)
[MEDIUM] Insights
- medium: dangerous_import:socket (source file main.py imports socket)
The scanner accepts a ScannerOptions object:
from acrf_mcp_scan import MCPScanner
from acrf_mcp_scan.scanner import ScannerOptions
scanner = MCPScanner(ScannerOptions(
allowed_publishers={"trusted-vendor", "internal-team"},
allowed_network_hosts={"api.acme-corp.com"},
require_signature=True,
scan_source_files=True,
))
When require_signature is true, an MCP server with no signature gets a high-severity finding. When you provide allowed_publishers, any server whose publisher is not in that set is flagged.
In CI for your AI platform:
from acrf_mcp_scan import MCPScanner, MCPServerInventory
from acrf_mcp_scan.scanner import ScannerOptions
import sys
scanner = MCPScanner(ScannerOptions(
allowed_publishers={"acme-internal"},
require_signature=True,
))
current = scanner.scan_config_file("config/mcp_config.json")
trusted = MCPServerInventory.load("config/approved_mcp.json")
if current.suspicious_servers():
for server in current.suspicious_servers():
print(f"FAIL {server.name}: {server.risk_summary()}")
sys.exit(1)
diff = current.diff(trusted)
if not diff.is_empty():
print(f"DRIFT: {diff.summary()}")
sys.exit(1)
print("OK: MCP inventory matches approved baseline")
Run that on every deployment. Block any release that introduces a new unapproved MCP server or a server with risky configuration.
SS-1 All installed MCP servers cataloged in an inventory
SS-2 Cryptographic verification of MCP server packages before installation
(acrf-mcp-scan flags missing signatures; pair with acrf-skill-verify
to actually enforce hash verification)
Out of scope (your runtime stack):
SS-3 Runtime monitoring of MCP server behavior for unexpected network calls
Runtime behavioral monitoring belongs in your observability stack, not in a static scanner.
It only ensures that you know exactly what MCP servers exist in your environment and that none of them have configuration or source code patterns commonly seen in malicious skills. That is the ACRF-03 defense pattern.
LangChain, CrewAI, AutoGen, MCP-based systems, custom agents. Anywhere you load third-party agent capabilities, you can use this scanner.
Ravi Karthick Sankara Narayanan, Kanna Sekar
Apache 2.0
Download counts and popularity will appear here as the collector receives them.
Declarations describe requirements; they are not a resolved dependency graph.
bdist_wheel · 12.51 KB · Python py3
sdist · 15.15 KB · Python source
Observed since 20 Oct, 18:25 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:ed251027667ccc63d880c3fbbcaea2d48218581cdb0fb81dbd2637cc59b3f875