Python - Barndoor Documentation
Barndoor SDK
A lightweight, framework-agnostic Python client for the Barndoor Platform REST APIs and Model Context Protocol (MCP) servers.The SDK removes boiler-plate around:
- Secure, offline-friendly authentication to Barndoor (interactive PKCE flow + token caching).
- Server registry – list, inspect and connect third-party providers (Salesforce, Notion, Slack …).
- Managed Connector Proxy – build ready-to-use connection parameters for any LLM/agent framework (CrewAI, LangChain, custom code …) without importing Barndoor-specific adapters.
Download here: https://pypi.org/project/barndoor/
How it works
The SDK orchestrates a multi-step flow to connect your code to third-party services:
You → Barndoor Auth (get JWT) → Registry API (with JWT) → MCP Proxy (with JWT) → Third-party service
- Authentication: You log in via Barndoor to get a JWT token
- Registry API: Using the JWT, query available MCP servers and manage OAuth connections
- MCP Proxy: Stream requests through Barndoor’s proxy with the JWT for authorization
- Third-party service: The proxy forwards your requests to Salesforce, Notion, etc.
This architecture provides secure, managed access to external services without handling OAuth flows or storing third-party credentials in your code.
Installation
pip install barndoor-sdk # coming soon – for now use an editable install
# or, inside this repo
pip install -e libs/barndoor[dev]
Python ≥ 3.10 is required.
Local development with uv
For the fastest install and reproducible builds you can use uv instead of pip.
# 1) (one-off) install uv
brew install uv # or follow the install script on Linux/Windows
# 2) create an isolated virtual environment in the repo
uv venv .venv
source .venv/bin/activate
# 3) install the SDK in editable mode plus the example extras
uv pip install -e '.[examples]'
# 4) install MCP support for CrewAI examples
uv pip install 'crewai-tools[mcp]'
# 5) copy the environment template and add your credentials
cp env.example .env
# Edit .env to add AGENT_CLIENT_ID, AGENT_CLIENT_SECRET, and OPENAI_API_KEY
# 6) run the interactive login utility once (opens browser)
uv run python -m barndoor.sdk.cli_login
# 7) kick off the Notion sample agent
uv run python examples/sample_notion_agent.py
Note: The OAuth default callback uses port 52765. Make sure this is registered in your Barndoor Agent as:
http://localhost:52765/cb
Using a custom OAuth callback port
If port 52765 is blocked (or you prefer another), you can:
- Register the new callback URL in your Barndoor Agent application, e.g.
http://localhost:60000/cb
- Run the login helper with the matching port
# CLI
uv run python -m barndoor.sdk.cli_login --port 60000
# In code
sdk = await bd.login_interactive(port=60000)
The SDK will spin up the local callback server on that port and embed the new URL in the request. The examples expect a .env file next to each script containing:
# Copy env.example → .env and add your credentials
Authentication workflow
Barndoor APIs expect a JWT issued by your Barndoor tenant. The SDK offers three ways to obtain such a token:
| Option | Command | When to use |
|---|---|---|
| Interactive CLI | python -m barndoor.sdk.cli_login (alias: barndoor-login) |
One-time setup on laptops / CI machines |
| In-code helper | await barndoor.sdk.login_interactive() |
Notebooks or scripts where you do not want a separate login step |
| Client credentials | await BarndoorSDK.from_client_credentials(...) |
Headless / machine-to-machine workloads (backend services, scheduled jobs) where no user is present |
The interactive variants:
- Spin up a tiny localhost callback server.
- Open the system browser to Barndoor.
- Exchange the returned code for a JWT.
- Persist the token to
~/.barndoor/token.json(0600 permissions).
Environment variables (or a neighbouring .env file) must define the Agent OAuth application:
AGENT_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxx
AGENT_CLIENT_SECRET=yyyyyyyyyyyyyyyyyyyy
# optional overrides
# See `internal_dev_env_setup` guide for local/dev options
The cached token is auto-refreshed on every run; if it is expired or revoked a new browser flow is launched.
Machine-to-machine (client credentials)
For headless services with no user present, use the standard OAuth 2.0 client-credentials grant. This requires a Barndoor OAuth application configured for the client-credentials grant type. The SDK exposes a one-call factory, BarndoorSDK.from_client_credentials(...), that fetches the initial JWT, refreshes it automatically as it nears expiry, and transparently retries once on 401 Unauthorized.
import asyncio
from barndoor.sdk import BarndoorSDK
async def main():
async with await BarndoorSDK.from_client_credentials(
"https://api.barndoor.host",
client_id="YOUR_M2M_CLIENT_ID",
client_secret="YOUR_M2M_CLIENT_SECRET",
audience="https://barndoor.ai/",
issuer="https://auth.barndoor.ai/realms/barndoor",
) as sdk:
servers = await sdk.list_servers()
print([s.slug for s in servers])
asyncio.run(main())
Prefer the issuer= keyword argument (OIDC discovery finds the token endpoint automatically). The legacy domain= keyword is retained for backwards compatibility and posts directly to https://{domain}/oauth/token. If you only need the raw access token (e.g. to inject it into another HTTP client), use the lower-level helpers re-exported from barndoor.sdk:
from barndoor.sdk import (
get_client_credentials_token, # synchronous
get_client_credentials_token_async, # awaitable, non-blocking
)
token = await get_client_credentials_token_async(
client_id="...",
client_secret="...",
audience="https://barndoor.ai/",
issuer="https://auth.barndoor.ai/realms/barndoor",
)
These return only the access-token string and do not persist anything to ~/.barndoor/token.json. Use the from_client_credentials factory if you want the SDK to manage token lifetime for you. A complete runnable example is at examples/sample_m2m_client.py.
Quick-start in four lines
import barndoor.sdk as bd
sdk = await bd.login_interactive() # 1️⃣ ensure valid token
await bd.ensure_server_connected(sdk, "salesforce") # 2️⃣ make sure OAuth is done
params, _public_url = await bd.make_mcp_connection_params(sdk, "salesforce")
params is a plain dict with url, headers and (optionally) transport – ready to plug into any HTTP / SSE / WebSocket client. See the examples below for CrewAI & LangChain usage.
Using the Registry API
# List all MCP servers available to the current user
servers = await sdk.list_servers()
print([s.slug for s in servers]) # ['salesforce', 'notion', ...]
# Get detailed metadata
details = await sdk.get_server(server_id=servers[0].id)
print(details)
Additional helpers:
await sdk.initiate_connection(server_id)– returns an OAuth URL the user must visit.await bd.ensure_server_connected(sdk, "notion")– combines status polling + browser launch.
Model Context Protocol Connection
Once a server is connected you can stream requests through Barndoor’s proxy edge.
params, public_url = await bd.make_mcp_connection_params(sdk, "notion")
print(params["url"]) # http(s)://…/mcp/notion
print(params["headers"]) # {'Authorization': 'Bearer ey…', 'x-barndoor-session-id': …}
API Documentation
The complete API specification is available in barndoor/sdk/docs/openapi.yaml. This covers all endpoints currently used by the SDK including:
- Server listing and details
- OAuth connection initiation
- Connection status checking
The spec can be viewed with tools like Swagger UI or Redoc.