Skip to main content

Overview

Build AI applications with Civic and the Vercel AI SDK. Your agents can access external tools via MCP — GitHub, Slack, Google Workspace, and more.
Framework: This guide is written for Next.js projects. The core MCP client setup works with any JavaScript framework, but the authentication examples below use Next.js-specific APIs.

Quick Start

The fastest way to get started is with the starter template:

AI Chatbot Starter

Clone our Next.js + Vercel AI SDK template with Civic pre-configured. Includes authentication, streaming, and tool calling out of the box.
git clone https://github.com/civicteam/ai-chatbot.git
cd ai-chatbot
pnpm install
cp .env.example .env.local
# Edit .env.local with your CIVIC_AUTH_CLIENT_ID and AI provider keys
pnpm dev

Build From Scratch

Prerequisites

  1. Next.js 14+ project with App Router
  2. Civic account at app.civic.com with at least one MCP server connected
  3. Node.js 18+

Installation

pnpm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/react @modelcontextprotocol/sdk @civic/auth
Vercel AI SDK version: experimental_createMCPClient ships in the ai package for AI SDK v5. If you’re on v6+, install @ai-sdk/mcp and import from there instead:
pnpm install @ai-sdk/mcp
// v6+
import { experimental_createMCPClient } from '@ai-sdk/mcp';
// v5
import { experimental_createMCPClient } from 'ai';

Authentication

Why user auth for tool calls? Civic needs to know which user’s toolkit and permissions to use. For multi-user apps, each user gets their own access token tied to their Civic account. 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.)
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)

Full Integration Guide

Complete Next.js setup with frontend components, configuration options, and deployment details

AI Prompt for Next.js

Use Claude, ChatGPT, or other AI assistants to automatically set up Civic Auth
Get your Client ID at auth.civic.com

Environment Variables

# .env.local
CIVIC_AUTH_CLIENT_ID=your_client_id  # from auth.civic.com
OPENAI_API_KEY=your_openai_key       # or ANTHROPIC_API_KEY

Create Civic Tools Helper

// lib/ai/tools/civic.ts
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { getTokens } from "@civic/auth/nextjs";
import { experimental_createMCPClient as createMCPClient } from "ai"; // use @ai-sdk/mcp for v6+

export const getCivicTools = async () => {
  const { accessToken } = (await getTokens()) ?? {};
  // getTokens() exchanges the user's Civic Auth session for a hub access token
  if (!accessToken) {
    return {}; // Return empty tools if user isn't authenticated
  }

  try {
    const transport = new StreamableHTTPClientTransport(
      new URL('https://app.civic.com/hub/mcp'), {
        requestInit: {
          headers: {
            Authorization: `Bearer ${accessToken}`
          }
        }
      }
    );

    const mcpClient = await createMCPClient({ transport });
    return mcpClient.tools();
  } catch (error) {
    console.warn('Failed to load Civic tools, continuing without them:', error);
    return {};
  }
}

App Router API Route

// app/api/chat/route.ts
import { convertToCoreMessages, streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { getCivicTools } from '@/lib/ai/tools/civic';

export async function POST(request: Request) {
  const { messages } = await request.json();
  const coreMessages = convertToCoreMessages(messages);
  const civicTools = await getCivicTools();

  const result = streamText({
    model: openai('gpt-4o'),
    messages: coreMessages,
    tools: civicTools,
  });

  // toUIMessageStreamResponse() returns a Response compatible with @ai-sdk/react useChat()
  return result.toUIMessageStreamResponse();
}
Using Anthropic/Claude? Replace the model:
import { anthropic } from '@ai-sdk/anthropic';
const result = streamText({
  model: anthropic('claude-sonnet-4-5-20250929'),
  messages: coreMessages,
  tools: civicTools,
});

Next Steps

1

Try the Starter Template

Clone ai-chatbot for a working example with UI, auth, and streaming
2

Connect Your Services

Visit app.civic.com to connect GitHub, Slack, Notion, and other services
3

Test Tool Calls

Run locally and ask your AI to “list my GitHub repos” or “search Slack messages”
4

Deploy to Production

Deploy to Vercel — all environment variables are pre-configured in the starter template

Starter Template

Full Next.js + Vercel AI SDK example with Civic integration

Get Help

Developer Slack