MCP Guard SDK
Scan MCP servers for security vulnerabilities. Provides sync (MCPGuardClient) and async (AsyncMCPGuardClient) clients.
Installation
pip install agentsuite-sdk
Configuration
| Variable | Description |
|---|---|
VIRTUE_API_KEY | VirtueAI API key (sk-vai-...) |
MCP_GUARD_BASE_URL | MCP Guard service base URL |
Scanning
From GitHub
Submit a GitHub repository for source-code security analysis:
with MCPGuardClient() as client:
handle = client.scans.create_from_github(
github_url="https://github.com/example-org/my-mcp-server",
revision="main",
)
result = client.scans.wait(handle.scan_id)
if result.result_data and result.result_data.summary:
print(f"Security: {result.result_data.summary.security.level}")
From MCP Config
Submit one or more servers using the same config format as Claude or VS Code:
config = {
"mcpServers": {
"my-server": {"url": "https://my-mcp-server.example.com/mcp"}
}
}
with MCPGuardClient() as client:
batch = client.scans.create_from_mcp_config(config)
for handle in batch.scans:
result = handle.wait()
print(f"{handle.scan_id}: {result.status}")
From Tool Descriptions
Submit tool descriptions directly — useful when you already have the tool list from an MCP server. Returns a success/failure response (no per-tool results):
with MCPGuardClient() as client:
response = client.scans.create_from_tools(
server_name="my-server",
tools=[
{
"tool_name": "read_file",
"tool_description": "Read the contents of a file",
"input_schema": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"],
},
},
{
"tool_name": "execute_command",
"tool_description": "Execute a shell command on the host system.",
},
],
)
if not response.issuccess:
print(f"Failed: {response.failed_reason}")
Results
wait() polls until the scan completes. get() returns the current state without blocking.
# Wait for completion
result = client.scans.wait(scan_id)
if result.status == "completed" and result.result_data:
findings = result.result_data.summary
if findings:
print(f"Security: {findings.security.level}")
print(f"Complexity: {findings.complexity.level}")
print(f"Sensitivity: {findings.sensitivity.level}")
for v in result.result_data.vulnerabilities:
print(f" {v.vulnerability_type} — {v.description}")
# Get current state without waiting
result = client.scans.get(scan_id) # pending / running / completed / failed
# List recent scans
recent = client.scans.list(limit=10)
for scan in recent.scans:
print(f"{scan.id} {scan.status} {scan.upload_time}")
# Retry a failed scan
handle = client.scans.retry(scan_id)
result = client.scans.wait(handle.scan_id)
Async Client
Same interface, all methods are awaitable:
from agentsuite import AsyncMCPGuardClient
async with AsyncMCPGuardClient() as client:
handle = await client.scans.create_from_github(
github_url="https://github.com/example-org/my-mcp-server",
)
result = await client.scans.wait(handle.scan_id)
if result.result_data and result.result_data.summary:
print(f"Security: {result.result_data.summary.security.level}")
Error Handling
All SDK errors are subclasses of GuardError:
| Exception | When raised |
|---|---|
GuardConfigError | Missing or invalid api_key / base_url at construction |
GuardAPIStatusError | API returned a non-2xx HTTP response; carries status_code and response |
GuardTimeoutError | Request timed out |
GuardConnectionError | Server unreachable (DNS, network, bad URL) |
ScanFailedError | Scan reached failed terminal state (raised by wait()); carries scan_id |