DEV Community

The Seventeen
The Seventeen

Posted on

You Can Build on AgentSecrets

Most developers who find AgentSecrets use it as a tool. They install the CLI, store their credentials, start the proxy, and their agents stop holding API key values. That is a real problem solved.

But there is a second way to use it that most people miss: building on top of it.

AgentSecrets has an SDK. When you build a tool, an MCP server, or an agent integration on that SDK, the zero-knowledge credential guarantee is part of what you ship. Your users get it without configuring anything. The protection is in the architecture of what you built, not in what they chose to set up.

This article is about that second use. What the SDK does, what you can build with it, and why the infrastructure model matters more than any individual feature.


The Problem with Solving Credentials in Your Tool

When you publish an MCP server, a LangChain tool, or any kind of agent integration today, you have to make a decision about credentials. How does this thing authenticate to the APIs it calls?

The standard answers all look like variations of the same thing:

The developer who installs your tool puts a token in an environment variable. It shows up in their MCP config, their .env file, their shell profile. The token is accessible to any process that can read those locations. When your tool runs, the token enters the agent's execution context. It is there for the duration of the call. If something in that context is compromised — a malicious document, a prompt injection payload, a rogue plugin — the token is reachable.

The problem is not that developers are careless. The problem is that every approach available today puts the value somewhere. The only question is how hard it is to get to.


What Changes When You Build on AgentSecrets

The SDK's core guarantee is structural, not policy-based.

Your code never calls get() because the SDK has no get() method. There is no retrieve. The only operation available is call() — make an authenticated HTTP request — or spawn() — start a process with credentials injected as environment variables. The credential value resolves from the OS keychain inside the proxy process, gets injected at the transport layer, and is never passed back to your code.

from agentsecrets import AgentSecrets

client = AgentSecrets()

response = client.call(
    "https://api.stripe.com/v1/balance",
    bearer="STRIPE_KEY"
)
Enter fullscreen mode Exit fullscreen mode

Your code sent a key name. It received an API response. The value sk_live_... existed transiently inside the proxy process during the request. It never crossed into your code, your agent's memory, or any log.

That guarantee is not something you implement. You import the library and it is true.


Six Injection Styles

The SDK covers every REST and OAuth pattern with six injection styles. You are not going to find an API that does not fit one of them.

# Bearer token — Stripe, OpenAI, GitHub
client.call(url, bearer="STRIPE_KEY")

# Custom header — SendGrid, Twilio, API Gateway
client.call(url, header={"X-Api-Key": "SENDGRID_KEY"})

# Query parameter — Google Maps, legacy APIs
client.call(url, query={"key": "GMAP_KEY"})

# Basic auth — Jira, internal REST APIs
client.call(url, basic="JIRA_CREDS")

# JSON body injection
client.call(url, method="POST", body_field={"client_secret": "SECRET"})

# Form field
client.call(url, method="POST", form_field={"api_key": "API_KEY"})
Enter fullscreen mode Exit fullscreen mode

You can combine them in a single call when an API requires multiple forms of authentication.


What You Can Build

MCP Servers That Do Not Store Credentials

This is the most immediate use case. The MCP ecosystem is growing fast and the default credential pattern — token in the env block of claude_desktop_config.json — is the exact problem AgentSecrets exists to solve.

When you build an MCP server on the SDK, the tool methods look like this:

import fastmcp
from agentsecrets import AgentSecrets

mcp = fastmcp.FastMCP("my-integration")
client = AgentSecrets()

@mcp.tool()
async def get_balance() -> str:
    response = await client.async_call(
        "https://api.stripe.com/v1/balance",
        bearer="STRIPE_KEY"
    )
    return response.json()
Enter fullscreen mode Exit fullscreen mode

The claude_desktop_config.json for this server has no env block. No token. Nothing to steal. Developers who install your server clone the repo, add their key to their AgentSecrets project with one CLI command, and the server works.

The Zero-Knowledge MCP repository is a working template built exactly this way. Clone it, add your tools, publish. Zero credential storage from line one.

LangChain Tools

The same pattern applies to LangChain tools, CrewAI agents, or anything that calls external APIs. Your tool makes the call through the SDK. The LLM orchestrating the agent sees the API response. The credential value is never in the agent's context.

from langchain.tools import BaseTool
from agentsecrets import AgentSecrets

class StripeTool(BaseTool):
    name = "check_stripe_balance"
    description = "Check the Stripe account balance"
    client: AgentSecrets = AgentSecrets()

    def _run(self, query: str) -> str:
        response = self.client.call(
            "https://api.stripe.com/v1/balance",
            bearer="STRIPE_KEY"
        )
        return str(response.json())
Enter fullscreen mode Exit fullscreen mode

The agent using this tool never had a chance to hold the key. There was no step in the execution where that was possible.

Multi-Tenant Tools

The SDK includes a scoped workspace context that lets you build tools handling multiple clients without global state changes and without any credential value existing in your code:

with client.workspace("Client A") as ws:
    response = ws.call(
        "https://api.stripe.com/v1/balance",
        bearer="STRIPE_KEY"
    )

with client.workspace("Client B") as ws:
    response = ws.call(
        "https://api.stripe.com/v1/balance",
        bearer="STRIPE_KEY"
    )
Enter fullscreen mode Exit fullscreen mode

Each workspace context is isolated. When you exit the block, the context is gone. Your code is building a tool that handles multiple clients and at no point does it hold a credential value from any of them.

Agents That Manage Their Own Credentials

The SDK exposes the full management layer programmatically. An agent can check whether its credentials are in sync, detect drift between local and cloud state, and trigger a sync all without ever seeing a credential value:

diff = client.secrets.diff()

if diff.has_drift:
    client.secrets.sync()
    print(f"Synced: {diff.out_of_sync}")
Enter fullscreen mode Exit fullscreen mode

An agent can manage its own credential lifecycle. It can audit what calls it has made, check what domains are authorized, log what it has done. Every operation works with key names. No operation returns a value.


Testing

The SDK ships with MockAgentSecrets for testing. The zero-knowledge guarantee holds in test mode — call records have no value field even when you supply mock secret values.

from agentsecrets.testing import MockAgentSecrets

mock = MockAgentSecrets(secrets={"STRIPE_KEY": "sk_test_mock"})

response = mock.call(
    "https://api.stripe.com/v1/balance",
    bearer="STRIPE_KEY"
)

assert mock.calls[0].url == "https://api.stripe.com/v1/balance"
assert mock.calls[0].bearer == "STRIPE_KEY"
# mock.calls[0].value does not exist
# even in test mode, the guarantee is structural
Enter fullscreen mode Exit fullscreen mode

Error Handling

Every exception from the SDK is actionable. The error tells you what went wrong and exactly what command fixes it.

from agentsecrets import (
    AgentSecretsNotRunning,
    DomainNotAllowed,
    SecretNotFound,
)

try:
    response = client.call(url, bearer="STRIPE_KEY")
except AgentSecretsNotRunning:
    # Includes full setup instructions
    raise
except DomainNotAllowed as e:
    print(f"Run: agentsecrets workspace allowlist add {e.domain}")
except SecretNotFound as e:
    print(f"Run: agentsecrets secrets set {e.key}=<value>")
Enter fullscreen mode Exit fullscreen mode

This matters more than it sounds. Tools break in production. When your tool surfaces an error that tells the developer exactly what to run, they fix it in sixty seconds instead of opening a GitHub issue.


The Structural Argument

There is a difference between a policy-based guarantee and a structural one.

A policy-based guarantee says: we do not log credential values. The system could. Whether it does depends on configuration and discipline.

A structural guarantee says: the log struct has no value field. The system cannot log a credential value regardless of configuration or what an AI agent instructs it to do.

AgentSecrets makes the structural guarantee at every layer. The proxy returns only the API response, no credential field in the response object. The SDK has no get() method. The audit log has no value field. The mock testing client has no value field in call records. You cannot break this guarantee by misconfiguring something because the architecture gives the value nowhere to go.

When you build a tool on this infrastructure, your tool inherits that guarantee. The developers who install what you built do not need to understand the architecture. The protection is already in place.


Getting Started

Install the CLI first:

brew install The-17/tap/agentsecrets
agentsecrets init
agentsecrets proxy start
Enter fullscreen mode Exit fullscreen mode

Then the SDK:

pip install agentsecrets
Enter fullscreen mode Exit fullscreen mode

Then build something. The Zero-Knowledge MCP template is the fastest way to see the pattern in action, it is a working MCP server built on the SDK with real GitHub tools, full documentation, and the claude_desktop_config.json already written with no env block.

AgentSecrets SDK
Zero-Knowledge MCP template
Documentation


What Comes Next

The cloud resolver is on the roadmap. When it ships, the SDK will work in serverless environments, Lambda, Vercel, Cloudflare Workers, anywhere a persistent local proxy cannot run. The zero-knowledge guarantee holds. The credential resolves and injects in the cloud resolver process and is never returned to your function.

AgentSecrets Connect will follow. It is the platform layer, a set of APIs that let SaaS products provision AgentSecrets workspaces for their users during onboarding. A developer installs your MCP server, your onboarding flow provisions their workspace silently, and they get zero-knowledge credential management without ever knowing AgentSecrets exists. The protection propagates without friction.

Both are in development. Everything that exists today — the CLI, the proxy, the SDK, the MCP template is free and open source, and will stay that way.


The MCP ecosystem is early. The credential defaults being established now will be the ones that persist. If zero-knowledge becomes the starting point, if the pattern developers copy when they build something new is one where the key never enters agent memory, the ecosystem inherits a fundamentally different security posture.

That is the goal. Build on it.

AgentSecrets is open source and MIT licensed. The SDK is at github.com/The-17/agentsecrets-sdk. The Zero-Knowledge MCP template is at github.com/The-17/zero-knowledge-mcp.

Top comments (0)