Semantic Kernel with Caddey
Integrate Caddey tools into a Semantic Kernel agent using MCP and OAuth 2.0 Device Code flow.
Caddey exposes app features as tools, and Semantic Kernel agents can dynamically discover and invoke these tools via the Model Context Protocol (MCP). This guide demonstrates how to build a Python-based Semantic Kernel agent that connects to Caddey’s MCP endpoint, authenticates users, and executes tools seamlessly.
This example uses the OAuth 2.0 Device Code Flow, ideal for CLI-based agents and environments where browser redirects aren’t feasible. If your agent runs inside a web app 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
- Semantic Kernel, Requests, and python-dotenv
pip install semantic-kernel[mcp] 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 another device (like a phone or browser) while your CLI agent waits for authorization.
It’s perfect for headless or console-based Semantic Kernel agents.
Complete Integration Script
The script below performs three key tasks:
- Authenticates the user via the OAuth 2.0 Device Code Flow
- Connects to Caddey’s MCP endpoint
- Creates a Semantic Kernel agent that can invoke Caddey tools
import os, time, asyncio, requests
from semantic_kernel import Kernel
from semantic_kernel.connectors.mcp import MCPClient
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.agents import 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 Semantic Kernel to Caddey MCP ---
async def main():
kernel = Kernel()
# Create an MCP client to connect to Caddey’s MCP endpoint
mcp_client = MCPClient(
server_url="https://api.caddey.ai/mcp",
transport="streamable_http",
headers={"Authorization": f"Bearer {CADDEY_TOKEN}"},
)
# Register Caddey MCP tools as kernel functions
await mcp_client.connect()
caddey_tools = await mcp_client.get_tools()
for tool in caddey_tools:
kernel.add_function(tool.as_kernel_function())
# Add an OpenAI LLM
llm = OpenAIChatCompletion(model="gpt-4o-mini", temperature=0)
kernel.add_text_completion_service("openai", llm)
# Create a simple Semantic Kernel agent
agent = Agent(kernel=kernel, name="CaddeyAgent")
# Example interaction
result = await agent.complete_chat("List my available tools.")
print(result)
await mcp_client.disconnect()
asyncio.run(main())
Using Your Agent
Once authenticated and connected, you can interact with your Semantic Kernel agent using natural language prompts.
The agent automatically discovers and invokes the appropriate Caddey tools through MCP.
Examples:
- List all available tools in my Caddey account.
- Create a new calendar event tomorrow at 10 AM titled “Team Sync.”
- Send a message to Alice with the note “The report is ready.”
The Semantic Kernel handles tool discovery, schema mapping, and invocation automatically via MCP.
Important Notes
- The Device Code Flow (RFC 8628) is designed for public clients and works seamlessly in CLI or server 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 web-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
- Semantic Kernel MCP Documentation
- Authlib Documentation
- OAuth 2.0 Device Authorization Grant (RFC 8628)
- MCP Specification
Need help? Visit the Support Section.