The No get() Principle
The AgentSecrets Python SDK has no get() method. This is not an oversight. It is the single most important design decision in the SDK, and understanding why it exists changes how you think about building on top of AgentSecrets.
Why the SDK has no get() method
A get() method would look like this:
# This method does not exist in AgentSecrets value = client.get("STRIPE_KEY") # value is now "sk_live_51H..." — in your process, in memory, accessible
If this method existed, every downstream use of the SDK would carry the same credential exposure risk as any other retrieval-based approach. The tool you use to avoid credential exposure would itself become a credential exposure path.
The absence of get() is not a convenience omission — it is the enforcement mechanism for the zero-knowledge guarantee at the SDK layer. You cannot retrieve a credential value into your calling code because the method to do so does not exist.
What this means for developers building on AgentSecrets
If you are building an MCP server, an agent tool, or any other system on top of AgentSecrets, the no get() constraint extends to everything you build. Your users' code cannot retrieve credential values through your tool because your tool cannot retrieve credential values itself.
This is the point. When you build on AgentSecrets, the zero-knowledge guarantee is inherited by everything downstream. An MCP server built on AgentSecrets cannot leak credentials to Claude regardless of what Claude is instructed to do, because there is no mechanism to retrieve the values in the first place.
The Zero-Knowledge MCP Template is built on this principle. Every MCP server scaffolded from it inherits the same structural protection.
How this changes how you design agent tools
Conventional tool design:
# Conventional — retrieves the value to use it def call_stripe_api(endpoint): key = secrets.get("STRIPE_KEY") # value retrieved into this function return requests.get(endpoint, headers={"Authorization": f"Bearer {key}"})
AgentSecrets tool design:
# AgentSecrets — passes the key name, never the value def call_stripe_api(endpoint): return client.call(endpoint, bearer="STRIPE_KEY") # proxy resolves STRIPE_KEY, injects it, returns API response # STRIPE_KEY value never exists in this function
client.call() accepts a key name, not a credential value. Your function never holds the value. If this function is called by a prompt-injected agent, there is nothing for the attacker to extract — the value was never here.
Common patterns that get() would enable and why they are excluded
1. Storing raw credentials in memory or configuration dictionaries:
# This pattern is not possible with AgentSecrets config = { "stripe_key": client.get("STRIPE_KEY"), "openai_key": client.get("OPENAI_KEY"), }
Configuration dictionaries and memory blocks holding raw credential values are a major source of accidental exposure — they get dumped into debugging logs, serialized across processes, or extracted by prompt-injected LLMs.
2. Returning raw credentials from agent tools:
# This pattern is not possible with AgentSecrets def get_api_key_for_agent(key_name): return client.get(key_name) # would give the agent the plaintext value
An agent tool that returns plaintext credential values is a direct credential exfiltration path. The tool cannot exist in AgentSecrets because the method it would call does not exist.
How to use third-party libraries without get()
A common question is: “If get() doesn't exist, how do I configure official client SDKs (like OpenAI, Stripe, Anthropic, or LangChain) that require an api_key parameter?”
The answer is Transparent HTTP Client Interception:
Instead of extracting raw secrets into your Python runtime, you initialize official SDKs using Zero-Knowledge Placeholders (via the credential helper or AS_SECRET_ strings):
import openai import stripe from agentsecrets import init, credential # 1. Initialize the transparent interceptor at application startup init() # 2. Pass zero-knowledge placeholders into vendor SDKs openai_client = openai.OpenAI(api_key=credential.OPENAI_API_KEY) stripe.api_key = credential.STRIPE_SECRET_KEY # 3. Use the SDKs normally — requests are automatically intercepted response = openai_client.chat.completions.create( model="gpt-4o", messages=[{"role": "user", "content": "Hello!"}] )
How this preserves the Zero-Knowledge Guarantee:
- Application Memory: Only holds the placeholder string
"AS_SECRET_OPENAI_API_KEY". Even if an attacker compromises the process, there are no secrets in RAM. - Network Layer Hook:
init()monkey-patchesrequestsandhttpxinternally. When the vendor SDK sends an HTTP request, the interceptor strips the placeholder and routes the call tohttp://localhost:8765/proxy. - Transport Boundary Injection: The local proxy checks the workspace allowlist, resolves the real credential from the OS Keychain via
keychain-auth, injects it directly into the outbound TLS stream to the vendor API, and returns the response safely.
The secure path is the only path
The SDK is designed so that the secure usage pattern is the only usage pattern available. The operations that exist are:
agentsecrets.init()— register transparent HTTP client interception for standard libraries (requests,httpx)client.call()/AsyncAgentSecrets.call()— make an authenticated HTTP request; the value is injected by the proxy at transport timeclient.spawn()/client.spawn_async()— start a process with credentials injected into child process memory with mandatory output stream maskingclient.secrets.list()— list key names; never valuesclient.secrets.check()— check whether keys exist; returns booleans, not valuesclient.secrets.pull()/client.secrets.push()/client.secrets.diff()— zero-knowledge sync operationsagentmodule — manage scoped agent identities, cryptographic tokens, and access capabilities
Every operation keeps the credential value out of your process memory and agent context. That is the complete design surface of the SDK.