> ## 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.

# OpenAI SDK (Agents)

> Use Civic with OpenAI Agents SDK using the hosted MCP tool approach

## Overview

Integrate Civic with the OpenAI Agents SDK using `hostedMcpTool()` — the simplest way to use Civic with OpenAI. No manual tool looping or schema conversion required.

<Note>
  For the older manual function calling approach, see [OpenAI SDK (Node.js)](/civic/recipes/openai-sdk).
</Note>

## Prerequisites

* Civic account at [app.civic.com](https://app.civic.com) with at least one MCP server connected
* OpenAI API key from [platform.openai.com](https://platform.openai.com)

## Installation

```bash theme={null}
npm install @openai/agents
```

The `openai` package is bundled as a dependency — no need to install it separately.

## Authentication

<Tabs>
  <Tab title="Backend / Script (Civic Token)">
    For autonomous agents and server-side scripts — use a Civic token directly.

    ### Generate a Civic Token

    1. Log in to [app.civic.com](https://app.civic.com)
    2. Click your account name in the bottom left
    3. Go to **[Install → MCP URL](https://app.civic.com/web/install/mcp-url)**
    4. Click **Generate Token** and copy it immediately — it won't be shown again

    <Warning>
      Never commit your token to source control. Store it in environment variables or a secrets manager. Tokens expire after 30 days.
    </Warning>

    ### Set Environment Variables

    ```bash theme={null}
    CIVIC_TOKEN=your-civic-token-here
    CIVIC_URL=https://app.civic.com/hub/mcp
    ```

    For production agents, lock to a specific toolkit by appending a `profile` parameter:

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

    ### Use the Token

    Pass the token as a Bearer token in the `Authorization` header:

    ```python theme={null}
    headers = {"Authorization": f"Bearer {os.environ['CIVIC_TOKEN']}"}
    ```

    ```typescript theme={null}
    headers: { Authorization: `Bearer ${process.env.CIVIC_TOKEN}` }
    ```

    <Card title="Full credentials guide" icon="key" href="/civic/quickstart/credentials">
      Token generation, URL parameters, OAuth vs token comparison
    </Card>

    ```bash theme={null}
    # .env
    OPENAI_API_KEY=your_openai_api_key
    CIVIC_TOKEN=your-civic-token-here
    CIVIC_URL=https://app.civic.com/hub/mcp
    ```
  </Tab>

  <Tab title="Next.js App (Civic Auth)">
    For web apps where each user has their own Civic session.

    Install the additional auth package:

    ```bash theme={null}
    npm install @civic/auth
    ```

    **Why Civic Auth?** Civic needs to identify which user is accessing tools and authorize their permissions. Civic Auth provides the secure access token. (Support for additional identity providers coming soon.)

    <Tabs>
      <Tab title="1. next.config.ts">
        ```ts theme={null}
        import { createCivicAuthPlugin } from "@civic/auth/nextjs"
        import type { NextConfig } from "next";

        const nextConfig: NextConfig = {};
        const withCivicAuth = createCivicAuthPlugin({ clientId: "YOUR_CLIENT_ID" });
        export default withCivicAuth(nextConfig)
        ```
      </Tab>

      <Tab title="2. API Route">
        **File:** `src/app/api/auth/[...civicauth]/route.ts`

        ```ts theme={null}
        import { handler } from "@civic/auth/nextjs"
        export const GET = handler()
        export const POST = handler()
        ```
      </Tab>

      <Tab title="3. Middleware">
        **File:** `src/middleware.ts`

        ```ts theme={null}
        import { authMiddleware } from "@civic/auth/nextjs/middleware"
        export default authMiddleware();
        export const config = { matcher: ['/((?!_next|favicon.ico|.*\\.png).*)',] };
        ```
      </Tab>

      <Tab title="4. Get Token">
        ```ts theme={null}
        import { getTokens } from "@civic/auth/nextjs";
        const { accessToken } = await getTokens();
        // Use in headers:
        headers: { Authorization: `Bearer ${accessToken}` }
        ```
      </Tab>
    </Tabs>

    <CardGroup cols={2}>
      <Card title="Full Integration Guide" icon="book" href="/integration/nextjs">
        Complete Next.js setup with frontend components, configuration options, and deployment details
      </Card>

      <Card title="AI Prompt for Next.js" icon="robot" href="/ai-prompts/nextjs">
        Use Claude, ChatGPT, or other AI assistants to automatically set up Civic Auth
      </Card>
    </CardGroup>

    <Note>
      Get your Client ID at [auth.civic.com](https://auth.civic.com)
    </Note>

    ```bash theme={null}
    # .env.local
    OPENAI_API_KEY=your_openai_api_key
    CIVIC_AUTH_CLIENT_ID=your_client_id  # from auth.civic.com
    ```
  </Tab>
</Tabs>

## Basic Setup

<Tabs>
  <Tab title="Backend / Script">
    ```typescript theme={null}
    import { Agent, hostedMcpTool, run } from '@openai/agents';

    const agent = new Agent({
      name: 'Civic Assistant',
      model: 'gpt-4o-mini',
      instructions: 'You are a helpful assistant with access to external tools through Civic.',
      tools: [
        hostedMcpTool({
          serverLabel: 'civic',
          serverUrl: process.env.CIVIC_URL!,
          authorization: process.env.CIVIC_TOKEN!, // plain token string
        }),
      ],
    });

    async function main() {
      const result = await run(agent, 'List my GitHub repositories');
      console.log(result.finalOutput); // the agent's final text response
    }

    main().catch(console.error);
    ```
  </Tab>

  <Tab title="Next.js API Route">
    ```typescript theme={null}
    // app/api/agent/route.ts
    import { NextRequest, NextResponse } from 'next/server';
    import { Agent, hostedMcpTool, run } from '@openai/agents';
    import { getTokens } from '@civic/auth/nextjs';

    export async function POST(req: NextRequest) {
      const { message } = await req.json();
      const { accessToken } = await getTokens();
      // getTokens() exchanges the user's Civic Auth session for a hub access token

      if (!accessToken) {
        return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
      }

      const agent = new Agent({
        name: 'Civic Assistant',
        model: 'gpt-4o-mini',
        instructions: 'You are a helpful assistant with access to external tools through Civic.',
        tools: [
          hostedMcpTool({
            serverLabel: 'civic',
            serverUrl: 'https://app.civic.com/hub/mcp',
            authorization: accessToken, // plain token string
          }),
        ],
      });

      const result = await run(agent, message);
      return NextResponse.json({ response: result.finalOutput });
    }
    ```
  </Tab>
</Tabs>

The Agent automatically discovers available Civic tools, selects the right one, calls it, and returns the result.

## Streaming

```typescript theme={null}
const result = await run(agent, 'Your question here?', { stream: true });

for await (const event of result) {
  if (event.type === 'response.output_text.delta') {
    process.stdout.write(event.delta);
  }
}

console.log(`Final result: ${result.finalOutput}`);
```

## Tool Approval

Control which tools require human approval before execution:

```typescript theme={null}
hostedMcpTool({
  serverLabel: 'civic',
  serverUrl: process.env.CIVIC_URL!,
  authorization: process.env.CIVIC_TOKEN!,
  requireApproval: {
    never: { toolNames: ['github__list_repos', 'slack__search_messages'] },
    always: { toolNames: ['github__delete_repo'] },
  }
})
```

## Strict Mode

<Warning>
  Not all Civic tool schemas are compatible with OpenAI's `strict: true` structured outputs. Set `strict` to `false` on the Responses API when using Civic tools.
</Warning>

## Comparison

| Feature              | OpenAI Agents SDK (hostedMcpTool) | OpenAI SDK (function calling) | Vercel AI SDK |
| -------------------- | --------------------------------- | ----------------------------- | ------------- |
| **Setup Complexity** | Low                               | Medium                        | Medium        |
| **Tool Looping**     | No (automatic)                    | Yes (manual)                  | Yes (manual)  |
| **Tool Conversion**  | No                                | Yes                           | Yes           |
| **Best For**         | Agents and scripts                | Full control                  | Next.js apps  |
| **Streaming**        | Yes                               | Yes                           | Yes           |

<CardGroup cols={2}>
  <Card title="OpenAI Agents SDK Docs" icon="robot" href="https://openai.github.io/openai-agents-js/guides/mcp/">
    Official OpenAI Agents SDK MCP guide
  </Card>

  <Card title="Get Help" icon="slack" href="https://join.slack.com/t/civic-developers/shared_invite/zt-37tv9fyo7-aDT43mUjOFQwdQFmfZLTRw">
    Developer Slack
  </Card>
</CardGroup>
