If you are building AI agents in 2026, you are probably also building MCP servers. Maybe one for GitHub so your agent can list repositories. One for Salesforce so it can read contacts. One for Google Calendar so it can schedule things. This is not controversial — MCP has become the standard transport between AI clients and the tools agents use. The ecosystem is maturing fast and teams are committing to it.
Here is the part that does not get talked about as much: every one of those MCP servers needs auth. And right now, most teams are solving that the same way they solved every auth problem before MCP existed — environment variables, a refresh helper they wrote themselves, and a quiet prayer that nothing rotates while production is running.
That is the gap the three new Nexus SDKs are designed to close. Not just "auth for your agent" in the abstract, but specifically the auth layer for the MCP servers Python and TypeScript developers are shipping right now. Let me walk through why this matters and what it actually looks like in practice.
The MCP Auth Problem Is Worse Than It Looks
When you write a standard MCP server on stdio transport, your process has one responsibility above all others: only write valid JSON-RPC to stdout. Nothing else. Not a debug log, not a startup banner, not an error message. The MCP client on the other end is reading stdout as a protocol stream. Anything unexpected breaks the connection, silently, in ways that are nearly impossible to debug.
Now add OAuth to that picture. You need a token before you can call the upstream API. You fetch it at server startup or on first use. You cache it. You handle refresh. You do all of this inside a process where your logging options are severely constrained. The standard approach — console.log() your way through it — is exactly wrong.
This is not a hypothetical. It is the first thing every developer who ships an MCP server with OAuth runs into. And it compounds with every provider you add. One provider is manageable. Three providers means three OAuth implementations, three refresh loops, three sets of environment variables living in the same server process, and three ways to accidentally write something to stdout during an error path.
What the SDKs Actually Give You
The TypeScript SDK was built from the ground up for MCP servers on stdio. Its internal logger is hardwired to console.error. Not configurable. Not a setting you can get wrong. The SDK never writes to stdout under any circumstances, including during token resolution failures, cache misses, and retry loops. That is a deliberate design constraint, not a default.
The integration looks like this:
import { NexusClient } from '@dromos/nexus-sdk';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const nexus = new NexusClient({ gatewayUrl: process.env.NEXUS_GATEWAY_URL! });
const fetcher = nexus.createFetcher({
workspaceId: process.env.WORKSPACE_ID!,
provider: 'github',
});
server.setRequestHandler(CallToolRequestSchema, async (req) => {
if (req.params.name === 'list_repos') {
const resp = await fetcher('https://api.github.com/user/repos?per_page=10');
const repos = await resp.json() as any[];
return { content: [{ type: 'text', text: repos.map(r => r.full_name).join('
') }] };
}
});
The createFetcher call returns a function with the same signature as the native fetch API. You call it exactly like you would call fetch. Inside, it calls GET /v1/resolve on the Nexus Gateway with the workspace ID and provider name, caches the result in a TokenManager keyed by that pair, evicts 30 seconds before actual expiry to avoid serving stale tokens, and injects the correct auth header based on whatever strategy the broker reports for that provider.
That last point matters. The SDK does not assume OAuth2. The broker returns a strategy field with every token response: type: "oauth2" sets Authorization: Bearer <token>, but type: "header" with a custom header_name sets whatever the broker specifies, and a value_prefix of empty string means the token is injected raw. An MCP server built today against a GitHub OAuth connection will work tomorrow against an internal API key provider with zero code changes.
The Python SDK works the same way, and because Python's async story for stdio MCP servers is different, the injection API is synchronous:
from nexus_sdk import NexusClient, NexusClientOptions, TokenCache
nexus = NexusClient(NexusClientOptions(gateway_url=GATEWAY_URL))
cache = TokenCache() # 30s safety buffer, thread-safe
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == 'list_repos':
status, headers, body = nexus.authenticated_fetch(
cache, WORKSPACE_ID, 'github',
'https://api.github.com/user/repos?per_page=10',
)
repos = json.loads(body)
return [TextContent(type='text', text='
'.join(r['full_name'] for r in repos))]
The Python TokenCache is thread-safe with a reentrant lock. The buffer logic is identical to the TypeScript SDK: the cache checks time.time() > (token.expires_at - buffer_seconds) and evicts before the upstream token expires. The Python SDK has zero runtime dependencies. It uses only the standard library — urllib.request, json, threading, time. For teams running agents in constrained environments, every transitive dependency is a supply chain question. We removed the question.
The Game Changer: Credentials Never Leave the Broker
MCP auth solved with environment variables has a problem that goes beyond refresh loops and missing tokens. The credentials live in the agent process. The agent process runs LLM-generated code. If the agent is compromised — through prompt injection, tool misuse, or a model vulnerability — the attacker is inside a process that holds a Salesforce client secret and a GitHub OAuth refresh token.
Nexus is built around the opposite architecture. The Broker holds the client secrets and refresh tokens. The agent process never sees them. The Gateway exposes a resolve endpoint that takes a workspace ID and provider name, asks the Broker for a fresh access token, and returns only that. The access token has a TTL measured in minutes. The refresh token stays encrypted in the Broker's PostgreSQL store, never transmitted to the agent.
Your MCP server calls GET /v1/resolve. It gets a short-lived access token. It uses it. When it expires, it calls resolve again. At no point does your server process hold anything that would be useful to an attacker beyond the current request window.
This separation also means that when a provider rotates a client secret — which Salesforce does periodically and Google recommends — you update it in the Broker once. Every agent and every MCP server continues working without a restart, a redeployment, or an ops incident.
The Infra Layer and the Client Layer
Part of what makes this composable is the clean split between what we think of as the infrastructure layer and the client layer.
The infrastructure layer is the Broker, the Gateway, and the Bridge. The Broker is the vault — it stores tokens, manages refresh, handles OIDC discovery. The Gateway is the public proxy — it is what your agent actually talks to. The Bridge is for Go agents that need persistent WebSocket or gRPC connections with automatic credential injection and reconnection with exponential backoff. These components are infrastructure. You deploy them. You do not embed them in your agent code.
The SDKs are the client layer. They are thin HTTP clients for the Gateway API. You install them. You call them. They carry none of the infrastructure complexity. The Go SDK is 600 lines. The Python SDK is 450 lines. The TypeScript SDK compiles to a dist/ directory you can inspect in full in an afternoon.
The separation means you can use the SDKs without understanding how the Broker works internally. You point them at a Gateway URL, give them a workspace ID and provider name, and call one function. The infrastructure complexity is contained behind the Gateway API contract.
The Go SDK: When Your Server Is the Infrastructure
For teams building Go services that sit between the Gateway and upstream providers, the Go SDK's AuthenticatedHTTPClient is the right tool. It returns a standard *http.Client with a custom RoundTripper that resolves tokens and injects headers on every request:
nexus := oauthsdk.New(os.Getenv("NEXUS_GATEWAY_URL"))
cache := oauthsdk.NewTokenCache(30 * time.Second)
// This is a standard *http.Client. Pass it to any library that accepts one.
ghClient := nexus.AuthenticatedHTTPClient(cache, workspaceID, "github")
resp, err := ghClient.Get("https://api.github.com/user/repos?per_page=10")
// Authorization header is injected by the RoundTripper
The RoundTripper clones the request before modifying it, which is the correct behavior for an HTTP middleware. It does not mutate the caller's request. The TokenCache is concurrent-safe with a read-write mutex. Multiple goroutines can call through the same *http.Client simultaneously without data races.
The Identity Horizon
The SDKs today solve credential retrieval: your agent or MCP server can get a valid token for any provider without holding the underlying credentials. That is a meaningful improvement over the environment variable approach, and it is what ships now.
The next problem — which we have already designed and are building — is credential authorization. Right now, any process that calls GET /v1/resolve with a valid workspace ID and provider name gets a token. There is no record of which agent made the request, no enforcement of what it is allowed to request, and no time limit on how long an agent can operate.
Agent identity as a first-class concept in Nexus means agents will register with declared scope boundaries. They will request short-lived sessions rather than resolving tokens directly. An agent registered with ["crm:contacts:read"] will not be able to request crm:contacts:write even if the underlying connection has that scope. The broker enforces the intersection — the token allows it is not the same as the agent is allowed to do it.
For internal business operations that do not map to any OAuth provider — acme:gliding, pipeline:trigger, reports:export — custom scopes will work the same way. An agent that can trigger pipelines cannot export reports unless both scopes are in its registration. And for operations that require human delegation, On-Behalf-Of sessions will stamp the authorizing user's identity and permission level onto every action the agent takes during that session.
The SDKs you install today will gain these methods without breaking changes. The method signatures for agent sessions and OBO are additive. If you are integrating Nexus now, the surface you build on is stable.
Why This Matters If You Are Already Using MCP
If you are building MCP servers and handling auth yourself today, the calculation is straightforward. The Nexus SDKs remove the OAuth implementation, the refresh loop, the token storage, the credential rotation handling, the strategy branching, the stdio safety concern, and the TTL caching. What remains is your tool logic.
And if you are building multiple MCP servers — one per provider — those servers can all point at the same Nexus Gateway. The workspace ID is the tenant boundary. The provider name is the connection identifier. One deployment of the Nexus infrastructure serves every MCP server in your stack. You stop rebuilding the same auth primitives in each server and start sharing them.
The SDK documentation, MCP integration walkthroughs, and the full API reference are at nexus.developers.prescottdata.io/sdks.