Skip to main content

DeepAgents

Connect a DeepAgents agent to Civic using langchain-mcp-adapters, which bridges DeepAgents' tool interface with Civic's Streamable HTTP MCP transport.

Prerequisites

Installation

Using uv (recommended):

uv add deepagents langchain-mcp-adapters langchain-anthropic fastapi uvicorn python-dotenv

Or with pip:

pip install deepagents langchain-mcp-adapters langchain-anthropic fastapi uvicorn python-dotenv

Environment Variables

# Civic token generated from app.civic.com → Install → MCP URL
CIVIC_TOKEN=your-civic-token

# API key for your chosen LLM provider
ANTHROPIC_API_KEY=your-anthropic-key # or OPENAI_API_KEY, etc.
Get Your Credentials

How to generate a Civic token and configure toolkit URL parameters

Connecting to Civic

Use MultiServerMCPClient to connect to the Civic MCP Hub during app startup, then pass the discovered tools to create_deep_agent:

import os
from contextlib import asynccontextmanager
from fastapi import FastAPI
from deepagents import create_deep_agent
from langchain_mcp_adapters.client import MultiServerMCPClient

mcp_client = None
agent = None

@asynccontextmanager
async def lifespan(app: FastAPI):
global mcp_client, agent

mcp_client = MultiServerMCPClient({
"civic-nexus": {
"transport": "streamable_http",
"url": "https://app.civic.com/hub/mcp",
"headers": {"Authorization": f"Bearer {os.environ['CIVIC_TOKEN']}"},
}
})

tools = await mcp_client.get_tools()

agent = create_deep_agent(
model="anthropic:claude-sonnet-4-6", # or "openai:gpt-4o", etc.
tools=tools,
system_prompt="You are a helpful assistant with access to calendar and email tools.",
)

yield

await mcp_client.__aexit__(None, None, None)

app = FastAPI(lifespan=lifespan)

Running the Agent

from fastapi import FastAPI
from pydantic import BaseModel

class ChatRequest(BaseModel):
message: str
thread_id: str = "default"

@app.post("/chat")
async def chat(request: ChatRequest):
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": request.message}]},
config={"configurable": {"thread_id": request.thread_id}},
)
return {"response": result["messages"][-1].content}

Start the server:

uv run uvicorn main:app --reload

Production Configuration

Lock to a Toolkit

For production agents, scope to a specific toolkit by adding profile to the MCP URL:

mcp_client = MultiServerMCPClient({
"civic-nexus": {
"transport": "streamable_http",
"url": f"https://app.civic.com/hub/mcp?profile={os.environ['CIVIC_PROFILE_ID']}",
"headers": {"Authorization": f"Bearer {os.environ['CIVIC_TOKEN']}"},
}
})

When a profile is specified, the session is locked by default — the agent cannot switch toolkits or modify its own guardrails. This prevents prompt injection attacks from escaping the defined tool scope.

Environment Variable Reference

VariableDescription
CIVIC_TOKENCivic token from app.civic.com → Install → MCP URL
ANTHROPIC_API_KEYAPI key for your LLM provider (e.g., Anthropic, OpenAI)

Reference Implementation

deepagents-reference-implementation-civic

Complete implementation with FastAPI server, streaming chat UI, and production patterns

Next Steps