Connect Your Agent to PRECINCT
You have an agent. You have PRECINCT running. Here is how to connect them in four steps: register identity, register tools, write a policy, and route traffic through the gateway.
Three Integration Paths
How you connect depends on what your agent already speaks. Pick the path that matches your situation.
Path A: MCP-Native Agent
Your agent already speaks the Model Context Protocol. Integration is a one-line URL change: point your MCP client at the PRECINCT gateway instead of directly at the MCP server.
Effort: 1 line of configuration
Path B: SDK Integration
Your agent makes tool calls over HTTP but does not use MCP natively. Use the Python or Go SDK to route calls through the gateway with automatic SPIFFE identity injection.
Effort: 5–10 lines of code
Path C: Adapter Pattern
Your agent uses a proprietary protocol or cannot be modified at all. Write a thin adapter that translates your protocol into MCP calls through the gateway, the same pattern used in the adapter case study.
Effort: ~800 lines of adapter code
If your agent already uses an MCP client library, you are on Path A. If it makes direct HTTP calls to tools, Path B is your fastest route. If you cannot change the agent at all, Path C is always available. All three paths produce the same security outcome; the only difference is where the integration work happens.
Prerequisites
Before you begin, ensure:
-
PRECINCT stack is running, either via
Docker Compose or Kubernetes.
Verify with
curl http://localhost:9090/health. - Your agent is running and making tool calls. You should be able to see it calling tools successfully in its current (ungoverned) configuration.
-
agwCLI is available, the PRECINCT operations CLI. See the CLI Reference for installation.
Step 1: Register Your Agent's Identity
Every workload in PRECINCT is identified by a SPIFFE ID, a URI that cryptographically identifies who is making a request. Before your agent can talk to the gateway, it needs a registered identity.
Choose a SPIFFE ID
SPIFFE IDs follow the pattern
spiffe://<trust-domain>/<path>. The path
encodes the workload's role within your organization.
# Pattern
spiffe://<trust-domain>/agents/mcp-client/<agent-name>/<environment>
# Examples
spiffe://prod.example.com/agents/mcp-client/research-agent/prod
spiffe://poc.local/agents/mcp-client/my-agent/dev
Create the SPIRE registration entry
Docker Compose
In Docker Compose, registration entries are defined in the SPIRE configuration. Add your agent to the registration entries:
# Register your agent's workload identity
docker compose exec spire-server /opt/spire/bin/spire-server entry create \
-spiffeID spiffe://poc.local/agents/mcp-client/my-agent/dev \
-parentID spiffe://poc.local/spire-agent \
-selector docker:label:app=my-agent
Kubernetes
In Kubernetes, use the SPIRE server CLI or a
ClusterSPIFFEID CRD if you have the SPIFFE CSI driver
installed:
# Via SPIRE server CLI
kubectl exec -n spire spire-server-0 -- /opt/spire/bin/spire-server entry create \
-spiffeID spiffe://prod.example.com/agents/mcp-client/my-agent/prod \
-parentID spiffe://prod.example.com/k8s-node \
-selector k8s:pod-label:app=my-agent \
-selector k8s:ns:default
Verify registration
agw identity list
# Should show your new SPIFFE ID in the output
Step 2: Register Your Tools
The PRECINCT gateway only forwards requests to tools that are registered in the capability registry. Each tool entry includes a name, description, upstream URL, and a SHA-256 hash of the tool's definition for integrity verification.
Compute the tool hash
The hash is computed over the tool's canonical JSON definition (name + description + input schema). This prevents tool poisoning attacks. If the tool's definition changes upstream, the hash will no longer match and the gateway will reject the request.
# Compute the SHA-256 hash of your tool's definition
echo -n '{"name":"my_tool","description":"Does something useful","inputSchema":{"type":"object","properties":{"query":{"type":"string"}}}}' \
| shasum -a 256 | cut -d' ' -f1
Add to the capability registry
Add your tool to config/capability-registry-v2.yaml:
tools:
- name: my_tool
description: "Does something useful"
upstream: "http://my-tool-server:8080"
hash: "a1b2c3d4e5f6..." # SHA-256 from the previous step
risk_level: medium # low | medium | high | critical
input_schema:
type: object
properties:
query:
type: string
Verify registration
agw inspect tools
# Should list your tool with its hash and risk level
The risk_level field directly affects the session
context engine (layer 8) and step-up gating (layer 9). Tools
classified as critical (like shell execution)
will trigger step-up authorization requirements. Choose
the level that matches the tool's actual blast radius.
Step 3: Write a Policy
OPA policies (written in Rego) define what each agent identity is allowed to do. At minimum, you need a policy that permits your agent to call your registered tools.
Minimal policy
Create a new Rego file in config/opa/policies/:
# config/opa/policies/my_agent.rego
package precinct.authz
import rego.v1
# Allow my-agent to call my_tool
allow if {
input.caller_spiffe_id == "spiffe://poc.local/agents/mcp-client/my-agent/dev"
input.tool_name == "my_tool"
}
# Allow my-agent to list tools
allow if {
input.caller_spiffe_id == "spiffe://poc.local/agents/mcp-client/my-agent/dev"
input.method == "tools/list"
}
Test before deploying
# Evaluate the policy against a sample input
agw policy eval \
--caller "spiffe://poc.local/agents/mcp-client/my-agent/dev" \
--tool "my_tool" \
--method "tools/call"
# Expected: ALLOW
# Test a denial
agw policy eval \
--caller "spiffe://poc.local/agents/mcp-client/my-agent/dev" \
--tool "bash" \
--method "tools/call"
# Expected: DENY (no policy permits this combination)
Hot-reload the policy
After writing or modifying a policy, reload it without restarting the gateway:
agw policy reload
# Policies are now active. No gateway restart required.
Rego policies are version-controlled alongside your infrastructure. Every policy change is a git commit with a clear diff. This gives auditors a complete history of who was allowed to do what, and when those permissions changed.
Step 4: Route Traffic Through the Gateway
The final step depends on which integration path you chose.
Path A: MCP-Native Agent (1-line change)
If your agent already uses an MCP client, change the server URL to point at the PRECINCT gateway:
# Before: direct connection to MCP server
client = MCPClient(server_url="http://mcp-server:8080")
# After: routed through PRECINCT gateway
client = MCPClient(server_url="http://localhost:9090")
That is the entire change. The gateway speaks the same MCP protocol as the upstream server. Your agent does not know the difference.
Path B: SDK Integration (5–10 lines)
If your agent makes direct HTTP calls to tools, replace them with SDK calls through the gateway.
Python
# Before: direct HTTP to tool
import httpx
resp = httpx.post("http://my-tool:8080/search", json={"query": "AI security"})
result = resp.json()
# After: routed through PRECINCT gateway
from mcp_gateway_sdk import GatewayClient
client = GatewayClient(
gateway_url="http://localhost:9090",
spiffe_id="spiffe://poc.local/agents/mcp-client/my-agent/dev"
)
result = await client.call_tool("my_tool", {"query": "AI security"})
Go
// Before: direct HTTP to tool
resp, err := http.Post("http://my-tool:8080/search",
"application/json", bytes.NewReader(payload))
// After: routed through PRECINCT gateway
client, _ := mcpgateway.NewClient(
"http://localhost:9090",
mcpgateway.WithSPIFFEID("spiffe://poc.local/agents/mcp-client/my-agent/dev"),
)
result, err := client.CallTool(ctx, "my_tool", map[string]any{
"query": "AI security",
})
See the SDK documentation for the full API reference, error handling, and auto-discovery of SPIFFE identities.
Path C: Adapter Pattern
If your agent uses a proprietary protocol or cannot be modified, write an adapter that sits between the agent and the gateway. The adapter translates your application's native protocol into MCP JSON-RPC calls to the gateway.
The adapter contract is straightforward:
- Accept requests in the application's native protocol
- Map each request to an MCP
tools/callortools/listJSON-RPC call - Forward to the PRECINCT gateway with the agent's SPIFFE ID
- Translate the gateway response back to the application's expected format
The adapter case study is a complete worked example of this pattern, including HTTP and WebSocket adapters totaling ~800 lines of Go.
Verify It Works
After completing the four steps above, verify that your agent is governed by PRECINCT.
1. Make a governed request
Have your agent call a registered tool. Verify the call succeeds and check the audit trail:
# Search the audit log for your agent's requests
agw audit search --caller "spiffe://poc.local/agents/mcp-client/my-agent/dev"
# Should show the request with decision=ALLOW and all 13 layers logged
2. Trigger a policy denial
Intentionally call a tool that your policy does not permit. Verify the request is denied:
curl -s http://localhost:9090/ \
-H "Content-Type: application/json" \
-H "X-SPIFFE-ID: spiffe://poc.local/agents/mcp-client/my-agent/dev" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"bash","arguments":{"command":"whoami"}},"id":1}' \
| jq .
# Expected: error with code "authz_policy_denied"
3. Inspect the audit record
Every request, whether allowed or denied, generates a structured audit event that traverses all 13 layers:
agw audit search --last 1 | jq .
# Shows: decision_id, trace_id, spiffe_id, tool, decision,
# layers_traversed, timestamps, risk_score, hash chain
If the allowed request succeeds with an audit trail, and the denied request returns a structured policy denial, your agent is fully integrated with PRECINCT.
What Happens Next
With your agent connected, every request now passes through the full PRECINCT enforcement chain. Here is what you get automatically:
- Identity verification: SPIFFE-based mTLS authentication at layer 3
- Tool integrity: SHA-256 hash verification at layer 5
- Policy enforcement: fine-grained OPA authorization at layer 6
- DLP scanning: credential and PII detection at layer 7
- Session tracking: cumulative risk scoring at layer 8
- Step-up gating: human-in-the-loop for critical operations at layer 9
- Rate limiting: per-agent throughput control at layer 11
- Audit trail: tamper-evident, hash-chained logging at layer 4
- Dual observability: Phoenix for request-trace waterfalls and optional OpenSearch Dashboards for indexed audit/compliance investigations
- Late-binding secrets: credential substitution at layer 13
For regulated environments, you can collect compliance evidence directly from the
OpenSearch index using agw compliance collect --audit-source opensearch
with HTTPS and mTLS certificate flags.
For Auditors
Generate compliance evidence mapped to SOC 2, NIST 800-53, ISO 27001, and more.
Architecture
Understand the full security model: five governed planes, 13-layer chain, and threat model.
Case Study
See how a real application was secured with PRECINCT using the adapter pattern, without changing its code.