使用说明
APS-MCP: Security Profile for Model Context Protocol
The first formal security standard for MCP tool integrations
Why This Matters
The Model Context Protocol (MCP) gives AI agents the ability to invoke external tools — databases, file systems, APIs, code execution environments. There is currently no formal security standard governing these integrations.
This means:
- No tool allowlisting. Agents can call any tool on any MCP server with no declared permission boundary.
- No egress control. MCP tools can make arbitrary outbound network requests, enabling data exfiltration.
- No data classification. Sensitive data (PII, credentials, financials) flows through tools with no tracking or enforcement.
- No server verification. Agents trust MCP servers blindly — no attestation, no hash verification, no supply-chain integrity.
- No audit trail. Tool invocations are not logged in a tamper-evident, standardized format.
- No exfiltration detection. There are no rate limits, volume caps, or pattern detection for data leaving the agent.
APS-MCP closes every one of these gaps with a single, machine-readable security policy that travels with the agent.
Quick Start
Add an mcp_security object to your agent passport's Security Envelope:
{
"security_envelope": {
"mcp_security": {
"profile_version": "1.0.0",
"mcp_tools_allowed": [
{
"server_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"tool_name": "read_file",
"version": ">=1.0.0 <2.0.0",
"data_classification_max": "internal"
}
],
"egress_policy": {
"default": "deny",
"allow": []
},
"data_classification_default": "restricted",
"io_validation": {
"max_input_bytes": 1048576,
"max_output_bytes": 10485760
},
"exfiltration_guards": {
"max_tool_calls_per_minute": 60,
"response_action": "suspend"
}
}
}
}
Validate against the schema:
# Using ajv-cli
ajv validate -s mcp-security-profile.schema.json -d your-policy.json
Integration Examples
Filesystem MCP Server
Lock an agent to read-only file access with no network egress:
{
"profile_version": "1.0.0",
"mcp_tools_allowed": [
{
"server_hash": "a1b2c3...64hex",
"tool_name": "read_file",
"version": ">=1.0.0 <2.0.0",
"data_classification_max": "internal",
"description": "Read files from project directory only"
},
{
"server_hash": "a1b2c3...64hex",
"tool_name": "list_directory",
"version": ">=1.0.0 <2.0.0",
"data_classification_max": "public",
"description": "List directory contents"
}
],
"egress_policy": { "default": "deny", "allow": [] },
"data_classification_default": "restricted",
"io_validation": { "max_input_bytes": 1048576, "max_output_bytes": 10485760 },
"exfiltration_guards": { "max_tool_calls_per_minute": 30, "response_action": "suspend" }
}
PostgreSQL MCP Server
Allow read-only database queries with egress limited to the database host:
{
"profile_version": "1.0.0",
"mcp_tools_allowed": [
{
"server_hash": "d4e5f6...64hex",
"tool_name": "query",
"version": "2.1.0",
"data_classification_max": "confidential",
"description": "Read-only SQL against analytics DB",
"input_schema": {
"type": "object",
"required": ["sql"],
"properties": { "sql": { "type": "string", "maxLength": 4096 } },
"additionalProperties": false
}
}
],
"egress_policy": {
"default": "deny",
"allow": [
{
"host": "analytics-db.internal.example.com",
"ports": [5432],
"protocol": "tcp",
"justification": "PostgreSQL analytics database"
}
]
},
"data_classification_default": "restricted",
"io_validation": { "max_input_bytes": 524288, "max_output_bytes": 5242880, "max_nesting_depth": 16 },
"exfiltration_guards": {
"max_egress_bytes_per_hour": 5242880,
"max_unique_domains_per_hour": 1,
"response_action": "terminate"
}
}
GitHub MCP Server
Allow issue management with egress limited to GitHub API:
{
"profile_version": "1.0.0",
"mcp_tools_allowed": [
{
"server_hash": "b2c3d4...64hex",
"tool_name": "get_issues",
"version": ">=1.0.0 <2.0.0",
"data_classification_max": "internal"
},
{
"server_hash": "b2c3d4...64hex",
"tool_name": "create_comment",
"version": ">=1.0.0 <2.0.0",
"data_classification_max": "internal"
}
],
"egress_policy": {
"default": "deny",
"allow": [
{
"host": "api.github.com",
"ports": [443],
"protocol": "tcp",
"justification": "GitHub REST API"
}
]
},
"data_classification_default": "restricted",
"io_validation": { "max_input_bytes": 1048576, "max_output_bytes": 10485760 },
"exfiltration_guards": {
"max_unique_domains_per_hour": 1,
"max_tool_calls_per_minute": 30,
"response_action": "suspend"
}
}
Specification
1. Tool Allowlist
An agent passport MUST declare an explicit allowlist of MCP tools the agent is permitted to invoke via the mcp_tools_allowed array.
Each entry MUST contain:
| Field | Type | Required | Description |
|---|---|---|---|
server_hash |
string | MUST | SHA-256 hex hash of the MCP server attestation bundle |
tool_name |
string | MUST | Exact tool name as registered on the MCP server |
version |
string | MUST | Semver version or range (e.g., ">=1.0.0 <2.0.0") |
data_classification_max |
string | SHOULD | Maximum data classification level. Defaults to "public" |
description |
string | MAY | Human-readable description of permitted use |
Enforcement rules:
- The runtime MUST reject any tool invocation not in
mcp_tools_allowed - The runtime MUST verify
server_hashmatches the responding server before dispatch - An empty array means the agent MUST NOT invoke any MCP tools
2. Egress Policy
All outbound network access from MCP tool executions is deny-by-default.
{
"egress_policy": {
"default": "deny",
"allow": [
{
"host": "api.example.com",
"ports": [443],
"protocol": "tcp",
"justification": "Required API endpoint"
}
]
}
}
Each allowed target specifies:
| Field | Type | Required | Description |
|---|---|---|---|
host |
string | MUST | FQDN, IP, or CIDR. Wildcards (*.example.com) for subdomains only |
ports |
array | SHOULD | Permitted ports. Defaults to [443] |
protocol |
string | SHOULD | "tcp", "udp", or "any". Defaults to "tcp" |
restricted_allowed |
boolean | MAY | If true, restricted-classified data may traverse this target |
justification |
string | SHOULD | Human-readable reason |
Enforcement: Network-layer enforcement (iptables, eBPF, sandbox firewall). DNS resolution must be restricted to prevent rebinding attacks.
3. Data Classification
Four levels, ordered by increasing sensitivity:
| Level | Tag | Description |
|---|---|---|
| 0 | public |
Non-sensitive, freely distributable |
| 1 | internal |
Organization-internal, not for public release |
| 2 | confidential |
Sensitive, requires access controls and encryption |
| 3 | restricted |
Highly sensitive (PII, credentials, financial). Strict need-to-know |
Key rules:
- If no classification tag is present, the runtime MUST treat data as
restricted(fail-secure) - Tools MUST NOT emit output at a level higher than their
data_classification_max restricteddata MUST NOT traverse egress targets unlessrestricted_allowed: true
4. MCP Server Attestation
Before invoking any tool, the runtime MUST verify the server's attestation bundle:
| Component | Description |
|---|---|
binary_hash |
SHA-256 of the MCP server executable / container image |
config_hash |
SHA-256 of server config (RFC 8785 canonicalized) |
version |
Semver version reported by the server |
tls_fingerprint |
SHA-256 of the server's TLS certificate |
attestation_signature |
Ed25519 signature over the canonicalized bundle |
The server_hash is: sha256(canonicalize({binary_hash, config_hash, version}))
Attestation bundles SHOULD be refreshed every 24 hours. A trust_on_first_use mode MAY exist for development but MUST NOT be enabled in production.
5. Input/Output Validation
| Constraint | Default | Description |
|---|---|---|
max_input_bytes |
1 MiB | Maximum single tool call input |
max_output_bytes |
10 MiB | Maximum single tool call output |
max_batch_bytes |
100 MiB | Maximum aggregate per rolling hour |
max_nesting_depth |
32 | Maximum JSON nesting depth |
Injection detection is mandatory. Implementations MUST detect:
- Prompt injection — attempts to override agent instructions via tool inputs
- Command injection — shell metacharacters, path traversal (
../), null bytes - Serialization attacks — malformed JSON, excessive nesting, duplicate keys
6. Exfiltration Guards
| Threshold | Default | Description |
|---|---|---|
max_egress_bytes_per_hour |
10 MiB | Outbound volume per rolling hour |
max_egress_bytes_per_day |
100 MiB | Outbound volume per rolling 24h |
max_unique_domains_per_hour |
10 | Distinct egress domains per hour |
max_tool_calls_per_minute |
60 | Tool invocations per rolling minute |
Monitored patterns:
- Encoding escalation (plaintext → base64/compressed before egress)
- Chunked exfiltration (many small payloads to same destination)
- Classification escalation (outputs higher than inputs)
- Temporal anomaly (burst activity outside normal patterns)
Response actions: log, suspend, terminate, or notify
7. Audit Trail
Every MCP tool invocation produces a tamper-evident log entry:
| Field | Description |
|---|---|
timestamp |
ISO 8601, millisecond precision, UTC |
event_id |
UUID v4 |
agent_did |
Invoking agent's DID |
tool_name |
MCP tool invoked |
server_hash |
Server that handled the call |
input_hash / output_hash |
SHA-256 of canonicalized payloads |
input_classification / output_classification |
Data classification tags |
duration_ms |
Wall-clock duration |
status |
success, error, blocked, or timeout |
security_events |
Security event tags triggered |
Entries are Ed25519-signed and hash-chained (prev_entry_hash). Retention: 90 days minimum (1 year for confidential/restricted data).
8. Profile Hash & Versioning
mcp_security_hash = sha256(canonicalize(mcp_security))
This hash is included in the Security Envelope's snapshot.hash. Changes to the MCP Security Profile increment the envelope version. Current profile version: 1.0.0.
Example Policies
| File | Use Case | Description |
|---|---|---|
examples/minimal-mcp-policy.json |
Getting started | Bare minimum — single read-only tool, no egress |
examples/strict-mcp-policy.json |
Production | Full lockdown — attestations, input schemas, ledger anchoring, terminate on alert |
examples/development-mcp-policy.json |
Development | Permissive limits, log-only response, local services allowed |
Schema
The full JSON Schema (draft 2020-12) is available at mcp-security-profile.schema.json.
Validate your policy:
# npm install -g ajv-cli
ajv validate -s mcp-security-profile.schema.json -d examples/strict-mcp-policy.json
# Or with Python jsonschema
pip install jsonschema
python -c "
import json, jsonschema
schema = json.load(open('mcp-security-profile.schema.json'))
policy = json.load(open('examples/strict-mcp-policy.json'))
jsonschema.validate(policy, schema)
print('✓ Valid')
"
Part of the Agent Passport Standard
APS-MCP is §17 of the Agent Passport Standard — a comprehensive identity, security, and accountability framework for AI agents.
The MCP Security Profile integrates with:
- Security Envelope (§3) —
mcp_securityis a child object of the envelope - Work Receipts (§2) — MCP tool calls can be referenced from job deliverables
- Federation (§16) — Peers exchange MCP Security Profiles during capability discovery
- Attestation Exchange (§13) — Server attestation bundles as third-party attestations
- Anchoring (§4) — Audit trail hashes anchored to immutable ledgers
License
Apache 2.0 — See LICENSE for details.