> ## Documentation Index
> Fetch the complete documentation index at: https://docs.civic.com/llms.txt
> Use this file to discover all available pages before exploring further.

# DSPy

> Connect a DSPy agent to Civic's MCP Hub using streamable HTTP transport

Connect a [DSPy](https://dspy.ai/) agent to Civic by wrapping MCP tools as Python callables and passing them to `dspy.ReAct`. DSPy v2.6 does not include a built-in MCP client, so tools are discovered via the raw `mcp` package.

## Prerequisites

* Python 3.11+
* A Civic account at [app.civic.com](https://app.civic.com) with a configured toolkit
* A Civic token and an Anthropic API key

## Installation

```bash theme={null}
pip install dspy mcp python-dotenv
```

## Environment Variables

```bash theme={null}
CIVIC_URL=https://app.civic.com/hub/mcp?profile=your-toolkit
CIVIC_TOKEN=your-civic-token
ANTHROPIC_API_KEY=your-anthropic-key
```

<Card title="Get Your Credentials" icon="key" href="/civic/quickstart/credentials">
  How to generate a Civic token and configure toolkit URL parameters
</Card>

## Connecting to Civic

Discover tools via the raw `mcp` client and wrap each one as a Python callable for DSPy:

```python theme={null}
import os
import asyncio
from dotenv import load_dotenv
import dspy
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession

load_dotenv()

CIVIC_URL = os.environ["CIVIC_URL"]
CIVIC_TOKEN = os.environ["CIVIC_TOKEN"]

async def call_tool(name: str, args: dict) -> str:
    """Call a single MCP tool and return the result as a string."""
    headers = {"Authorization": f"Bearer {CIVIC_TOKEN}"}
    async with streamablehttp_client(CIVIC_URL, headers=headers) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.call_tool(name, args)
            return str(result.content)

async def get_civic_tools():
    """Discover all Civic tools and wrap them as Python callables."""
    headers = {"Authorization": f"Bearer {CIVIC_TOKEN}"}
    async with streamablehttp_client(CIVIC_URL, headers=headers) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.list_tools()

            def make_tool(name: str, desc: str):
                def tool_fn(**kwargs):
                    return asyncio.run(call_tool(name, kwargs))
                tool_fn.__name__ = name
                tool_fn.__doc__ = desc or f"Call the {name} tool"
                return tool_fn

            return [make_tool(t.name, t.description or "") for t in result.tools]

# Configure DSPy with Claude
dspy.configure(lm=dspy.LM("anthropic/claude-sonnet-4-6"))

# Discover and wrap tools
tools = asyncio.run(get_civic_tools())
print(f"{len(tools)} tools loaded")

# Create a ReAct agent
react = dspy.ReAct(signature="question -> answer", tools=tools)
```

## Running the Agent

```python theme={null}
result = react(question="What events do I have today?")
print(result.answer)
```

<Note>
  DSPy v2.6 has no built-in MCPClient. This pattern uses the raw `mcp` package for discovery and wraps each tool as a Python callable. Each tool call opens a new MCP connection — for production use, consider connection pooling.
</Note>

## Production Configuration

For production agents, lock to a specific toolkit using the `profile` URL parameter:

```bash theme={null}
CIVIC_URL=https://app.civic.com/hub/mcp?profile=your-production-toolkit
```

## Reference Implementation

<Card title="dspy-reference-implementation-civic" icon="github" href="https://github.com/civicteam/dspy-reference-implementation-civic">
  Complete implementation with FastAPI chat UI and deployment guide
</Card>

## Next Steps

<CardGroup cols={2}>
  <Card title="Agent Deployment" icon="robot" href="/civic/quickstart/clients/agents">
    Production deployment guide: profile locking, URL params, authentication
  </Card>

  <Card title="Guardrails" icon="shield" href="/civic/concepts/guardrails">
    Constrain what tools your agent can call
  </Card>

  <Card title="Audit Trail" icon="list-check" href="/civic/concepts/audit">
    Query what your agent did via Civic Chat
  </Card>

  <Card title="Get Credentials" icon="key" href="/civic/quickstart/credentials">
    Token generation and URL parameter reference
  </Card>
</CardGroup>
