Guard SDK
Embed live Safeguard policy enforcement directly into your MCP server or AI agent process with the Guard SDK for Python, TypeScript, and Go.
Guard SDK
The Guard SDK lets you enforce your organization's Safeguard security policy directly inside your own MCP server or AI agent process. Once configured, it continuously pulls your live policy in the background and applies it to every request — no manual policy files to write, no service restarts to roll out an update, and no separate proxy to run. You get consistent, up-to-date guardrails wherever your agents run, with a couple of lines of setup.
Generate a Secret Key
The Guard SDK authenticates using a secret key tied to your organization.
- Navigate to Settings
- Click the Developer tab
- Click Generate Secret Key
- Copy the key and store it somewhere safe — it is only shown once
Treat this key like a credential. Anyone with it can pull your organization's policy, so store it in a secrets manager or inject it via an environment variable rather than committing it to source control.
Install the SDK
| Language | Package | Install |
|---|---|---|
| Python | safeguard-sh-guard | pip install safeguard-sh-guard |
| TypeScript / JavaScript | @safeguard-sh/guard-sdk | npm install @safeguard-sh/guard-sdk |
| Go | github.com/safeguard-sh/guard-sdk | go get github.com/safeguard-sh/guard-sdk |
The Python and TypeScript packages manage a small local process automatically behind the scenes — you never need to run or configure anything yourself beyond the steps below. That process ships as a pure Go binary cross-compiled for five platforms (Linux, macOS, and Windows on amd64/arm64 as applicable), so installing the Python or TypeScript package never requires a Go toolchain on your machine. See How the Python and TypeScript SDKs work below for details.
Configure the SDK
Set the secret key as an environment variable named SG_SECRET_KEY, then initialize the SDK. It handles the rest — fetching your policy, keeping it current, and enforcing it on every call.
import os
from safeguard_sh_guard import Guard
guard = Guard(secret_key=os.environ["SG_SECRET_KEY"], guard_base_url="https://guard.safeguard.sh")
# Analyze a request before it executes
result = guard.analyze_request(request_body_bytes)
if result["action"] == "block":
raise PermissionError(result["reason"])import { Guard } from "@safeguard-sh/guard-sdk";
const guard = await Guard.create({
secretKey: process.env.SG_SECRET_KEY,
guardBaseUrl: "https://guard.safeguard.sh",
});
// Analyze a request before it executes
const result = await guard.analyzeRequest(requestBody);
if (result.action === "block") {
throw new Error(result.reason);
}import (
"context"
"github.com/safeguard-sh/guard-sdk"
)
client, err := sdk.NewClient(context.Background(), sdk.ClientConfig{
SecretKey: os.Getenv("SG_SECRET_KEY"),
GuardBaseURL: "https://guard.safeguard.sh",
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Analyze a request before it executes
result := client.Guard().AnalyzeRequest(context.Background(), requestBody)
if result.Blocked() {
// handle result.Reason
}Once initialized, the SDK keeps your policy in sync automatically. When you update rules in Safeguard, the change applies to every running instance of your agent within moments — no redeploy or restart required.
How the Python and TypeScript SDKs work
The Go SDK embeds the Guard analysis engine directly in your process — there's no separate component involved. The Python and TypeScript packages take a different approach: they're thin clients around a small local sidecar process, a pure-Go binary that exposes an HTTP facade over that same underlying Guard analysis engine used natively in Go. In other words, Python and TypeScript callers get identical analysis behavior to Go, just reached over a local HTTP connection instead of an in-process function call.
You never interact with the sidecar directly — the Guard client in each SDK manages its entire lifecycle transparently:
- On initialization, the SDK starts the sidecar binary as a child process, passing it your configuration (secret key or OAuth credentials, tenant, and Guard base URL) and waiting for it to report that it's ready to accept requests.
- If startup fails — the binary can't start, exits early, or doesn't become ready in time — the SDK kills the process immediately rather than leaving an orphaned process running in the background, and it surfaces the failure to you right away as an error from your
Guardinitialization call, instead of failing silently and leaving your application running without enforcement. - While your process is running, every
analyze_*/analyze*call is forwarded to the sidecar over a local connection and the result is returned through the same SDK API shown above — the request/response shapes you work with are identical whether you're on Python, TypeScript, or Go.
Because a failed startup surfaces as a normal exception/error from initialization rather than a delayed or silent failure, handle it the same way you'd handle any other setup error:
try:
guard = Guard(secret_key=os.environ["SG_SECRET_KEY"], guard_base_url="https://guard.safeguard.sh")
except Exception as exc:
# The sidecar failed to start, exited early, or never reported ready.
# Guard already killed the process — there's nothing orphaned to clean up,
# but your own process should still fail its startup here too.
raise SystemExit(f"Guard failed to initialize: {exc}")try {
const guard = await Guard.create({
secretKey: process.env.SG_SECRET_KEY,
guardBaseUrl: "https://guard.safeguard.sh",
});
} catch (err) {
// The sidecar failed to start, exited early, or never reported ready.
// Guard already killed the process — there's nothing orphaned to clean up,
// but your own process should still fail its startup here too.
throw new Error(`Guard failed to initialize: ${err}`);
}Because the sidecar binary is pure Go with no C dependencies, it's cross-compiled ahead of time for five platform/architecture combinations and bundled with the Python and TypeScript packages, so nothing further needs to be installed or built on your machine.
If you're troubleshooting SDK startup and want to point at a custom or locally-built sidecar binary (for example, in CI or a sandboxed environment), both SDKs support overriding the binary location via an environment variable. This is an advanced/testing option — most integrations should just let the SDK manage the bundled binary.
Tool-poisoning detection
Beyond evaluating individual requests, the Guard SDK can also analyze an MCP tool's own definition — its name and description — for tool poisoning: cases where a tool's metadata appears to contain instructions aimed at manipulating the calling agent rather than informing it. This covers things like hidden or disguised prompt-injection phrasing embedded in a tool's description, unusually long or obfuscated tool descriptions, and suspicious formatting (such as hidden or invisible characters) used to smuggle instructions past a human reviewer while still being read by the agent.
This is a separate analysis call from analyze_request / analyzeRequest shown above — it's scoped to a tool's definition rather than to an individual request, so look for a distinct tool-analysis entry point in your installed SDK rather than expecting a poisoning finding to show up on every analyze_request result. A related check applies similar scrutiny to a tool call's response, flagging content that tries to redirect the calling agent after the fact — that's its own analysis call too, with its own result shape.
The exact shape of these findings (call names, field names, severity levels, and how results are nested) is defined by each SDK's own types. Consult your installed SDK's type definitions (TypeScript), docstrings/type hints (Python), or generated docs for the precise call signatures and fields — treat the description above as the concept, not a literal API reference.
Performance
The Guard SDK is built to sit directly in the hot path of your agent or MCP server, so per-request overhead matters. Policy decisions are evaluated entirely against a copy of your policy held in memory locally — there is no network round-trip to Safeguard on the request path — and are designed and benchmarked to complete well under 10ms per call.
The only network traffic to Safeguard's servers happens on a periodic background sync that refreshes your policy (this is the same sync described above that keeps rule changes rolling out automatically). If that background refresh fails — due to a network blip, for instance — the SDK keeps enforcing the last policy it successfully fetched rather than blocking or slowing down in-flight requests while it retries.
If you want to confirm the overhead in your own environment rather than take the sub-10ms figure on faith, wrap a call with a timer — actual numbers will vary with your host machine and policy size, but there should be no network round-trip in the critical path:
import time
start = time.perf_counter()
result = guard.analyze_request(request_body_bytes)
elapsed_ms = (time.perf_counter() - start) * 1000const start = performance.now();
const result = await guard.analyzeRequest(requestBody);
const elapsedMs = performance.now() - start;OAuth Login
If your team prefers not to manage a static secret key, the Guard SDK also supports an OAuth-based login flow. This is useful for shared or interactive environments where you want individual developer identity attached to policy pulls instead of a single shared key.
guard = Guard(oauth_token=token, tenant_id=tenant_id, guard_base_url="https://guard.safeguard.sh")const guard = await Guard.create({ oauthToken: token, tenantId: tenantId, guardBaseUrl: "https://guard.safeguard.sh" });client, err := sdk.NewClient(context.Background(), sdk.ClientConfig{
OAuthToken: token,
TenantID: tenantID,
GuardBaseURL: "https://guard.safeguard.sh",
})Both authentication methods grant the same runtime behavior — the only difference is how the SDK identifies itself to Safeguard.
FAQ & Troubleshooting
What happens if my network can't reach Safeguard? The SDK keeps enforcing the last policy it successfully retrieved and automatically retries in the background. Your agent keeps running under known-good rules rather than failing open or blocking entirely.
My secret key stopped authenticating and the SDK can't refresh its policy anymore. A secret key doesn't expire on its own, so a sudden authentication failure almost always means the key was revoked or deleted from Settings → Developer on the Safeguard side — treat it as expected behavior rather than an outage. Generate a new key and reconfigure the affected instance(s). See RBAC & Teams for how keys are scoped and revoked.
My Python or TypeScript app fails to initialize with a sidecar-related error.
This means the bundled sidecar binary couldn't start, exited early, or didn't report ready in time. The SDK already killed the process for you — there's no orphaned process to clean up — but the failure is surfaced to you immediately as an error from your Guard(...) / Guard.create(...) call, so treat it as something to fix before your app starts, not a transient condition to retry around. See How the Python and TypeScript SDKs work.
Can I point the SDK at a custom or locally-built sidecar binary? Yes, via an environment variable override in both the Python and TypeScript SDKs — meant for CI, sandboxed environments, or testing against a locally-built binary. Most integrations should leave this unset and let the SDK manage the bundled binary. See the callout in How the Python and TypeScript SDKs work.
How quickly do policy changes take effect? Within moments of being published — the SDK pulls updates continuously in the background, so there's no need to restart your service.
A request was allowed (or denied) differently than I expected — how do I see why?
Every request Guard evaluates is written to an append-only audit trail, including which rule matched and why. Check Audit Trail & Alerts for the specific rule_id / rule_name / deny_reason behind a decision, and Guard Policies for how rule priority and first-match-wins evaluation work — a common cause of surprising results is a higher-priority rule matching before the one you expected to apply.
Can I use the Guard SDK alongside the main Safeguard SDK? Yes. The Guard SDK is focused on policy enforcement inside agent processes, while the main SDKs cover the broader REST API (findings, SBOMs, remediation, and more). They can be used together in the same project.
Do I need to configure a policy manually? No. The Guard SDK pulls whatever policy is currently live for your organization in Safeguard. Manage the policy itself from your Safeguard workspace; the SDK stays in sync automatically.
Which languages are supported? Python, TypeScript/JavaScript, and Go are supported today.
Related
- Guard Policies — the allow/deny/monitor rules your
analyze_request/analyzeRequestcalls evaluate against. - Guard Proxy — enforce the same policy in front of MCP servers you don't control the code of, instead of (or alongside) embedding the SDK.
- Audit Trail & Alerts — every decision the SDK makes is logged here, with rollups and alert rules for jailbreak/anomaly spikes.
- Guard Webhooks — get notified when an alert rule tied to jailbreak, anomaly, or blocked-request signals fires.
- RBAC & Teams — generate, scope, and revoke the organization secret key the SDK authenticates with.
- SDKs — the general-purpose Safeguard SDKs for the REST API.
- MCP Integrations — connect an AI assistant to Safeguard directly.