Skip to main content

MCP Guard SDK

Scan MCP servers for security vulnerabilities. Provides sync (MCPGuardClient) and async (AsyncMCPGuardClient) clients.

Installation

pip install agentsuite-sdk

Configuration

VariableDescription
VIRTUE_API_KEYVirtueAI API key (sk-vai-...)
MCP_GUARD_BASE_URLMCP 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:

ExceptionWhen raised
GuardConfigErrorMissing or invalid api_key / base_url at construction
GuardAPIStatusErrorAPI returned a non-2xx HTTP response; carries status_code and response
GuardTimeoutErrorRequest timed out
GuardConnectionErrorServer unreachable (DNS, network, bad URL)
ScanFailedErrorScan reached failed terminal state (raised by wait()); carries scan_id