LangChain with Caddey
Integrate Caddey tools into a LangChain Python agent using MCP and OAuth 2.0 Device Code flow.
Caddey exposes app features as tools, and LangChain agents can dynamically discover and invoke these tools via the Model Context Protocol (MCP). This guide demonstrates how to build a Python-based LangChain agent that connects to Caddey's MCP endpoint, authenticates users, and executes tools seamlessly.
This example uses the OAuth 2.0 Device Code Flow, which is ideal for CLI-based agents and environments where a browser redirect is not feasible. If your agent runs inside a web browser or UI, consider using the Authorization Code Flow instead.
Prerequisites
- Caddey OAuth Client ID (create a Public OAuth client in Caddey)
- Python 3.x and a virtual environment
- LangChain, LangChain MCP Adapters, OpenAI, Requests, and python-dotenv
pip install langchain langchain-mcp-adapters openai requests python-dotenv
Important: The OAuth 2.0 Device Code Flow (RFC 8628) only works with Public clients. When creating your OAuth client, you must select Public (not Confidential).
Confidential clients will receive an unauthorized_client error when attempting to use Device Authorization Grant.
OAuth 2.0 Device Code Flow
The Device Code Flow allows users to authenticate on a separate device (like a phone or browser) while your CLI agent waits for authorization. This is perfect for command-line tools and headless environments.
Complete Integration Script
The following script demonstrates the complete flow: authenticating the user via OAuth 2.0 Device Code Flow, connecting to Caddey's MCP endpoint, and creating a LangChain agent that can invoke Caddey tools.
import os, time, asyncio, requests
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
# --- Step 1: User login via OAuth Device Code flow ---
DEVICE_URL = "https://auth.caddey.ai/realms/caddey/protocol/openid-connect/auth/device"
TOKEN_URL = "https://auth.caddey.ai/realms/caddey/protocol/openid-connect/token"
CLIENT_ID = os.getenv("CADDEY_CLIENT_ID")
# Request device and user codes
device_response = requests.post(DEVICE_URL, data={"client_id": CLIENT_ID})
device = device_response.json()
print("To sign in, open:", device["verification_uri_complete"])
print("Or visit", device["verification_uri"], "and enter code:", device["user_code"])
# Poll for access token
while True:
token_response = requests.post(
TOKEN_URL,
data={
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
"device_code": device["device_code"],
"client_id": CLIENT_ID,
},
)
token_data = token_response.json()
if "access_token" in token_data:
CADDEY_TOKEN = token_data["access_token"]
break
elif token_data.get("error") == "authorization_pending":
time.sleep(device.get("interval", 5))
else:
raise Exception(f"Token error: {token_data}")
print("✅ Logged in. Token acquired.")
# --- Step 2: Connect LangChain agent to Caddey MCP ---
async def main():
mcp = MultiServerMCPClient({
"caddey": {
"transport": "streamable_http",
"url": "https://api.caddey.ai/mcp",
"headers": {"Authorization": f"Bearer {CADDEY_TOKEN}"}
}
})
tools = await mcp.get_tools()
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
agent = create_agent(llm, tools)
result = await agent.ainvoke({
"messages": [
{"role": "user", "content": "List my tools."}
]
})
print(result)
asyncio.run(main())
Using Your Agent
Once authenticated and connected, you can interact with your LangChain agent using natural language prompts. The agent will automatically discover and invoke the appropriate Caddey tools based on your requests.
Examples:
- List all available tools in my Caddey account.
- Create a reminder to call Bob tomorrow at 3 PM.
- Send an email to [email protected] with subject "Project Update" and body "The report is ready."
The agent will automatically handle tool discovery, parameter validation, and execution through the MCP protocol.
Important Notes
- The Device Code Flow (RFC 8628) is designed for public clients and works seamlessly in CLI environments without requiring a web server for OAuth callbacks.
- Public clients do not require a client secret, making this flow ideal for devices that cannot securely store credentials.
- For browser-based agents that can handle redirects, use the Authorization Code Flow instead.
- Access tokens typically expire after 1 hour. Implement token refresh logic or re-run authentication when tokens expire.
- Store your
CADDEY_CLIENT_IDsecurely in environment variables.
Additional Resources
- LangChain MCP Documentation
- Authlib Documentation
- OAuth 2.0 Device Authorization Grant (RFC 8628)
- MCP Specification
Need assistance? Visit the Support Section.