Skip to main content

Overview

Build AI applications with Civic Nexus and Vercel AI SDK v5. Your AI agents can access external tools and services through MCP (Model Context Protocol) - interact with GitHub, Slack, Dropbox, and more.
Framework: This guide is written for Next.js projects. The core MCP client setup works with any JavaScript framework, but authentication setup uses Next.js-specific APIs.

Quick Start

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

AI Chatbot Starter

Clone our Next.js + Vercel AI SDK template with Nexus pre-configured. Includes authentication, streaming, and tool calling out of the box.
git clone https://github.com/civicteam/ai-chatbot.git
cd ai-chatbot
npm install

# Copy the example env file and add your keys
cp .env.example .env.local
# Edit .env.local with your CIVIC_AUTH_CLIENT_ID and AI provider keys

npm run dev
CIVIC_AUTH_CLIENT_ID=your_client_id_here
OPENAI_API_KEY=your_openai_key  # or ANTHROPIC_API_KEY
Get your Civic Client ID at auth.civic.com
Updated for AI SDK v5: This guide uses Vercel AI SDK v5 with convertToCoreMessages() for message handling and toUIMessageStreamResponse() for streaming compatibility with @ai-sdk/react.

Build From Scratch

Want to integrate Nexus into an existing Next.js project? Follow the guide below.
Prerequisites:
  1. Next.js 14+ project with App Router (Pages Router also supported)
  2. Civic account - Create account
  3. Connect services at nexus.civic.com (GitHub, Slack, etc.)
  4. Node.js 18+ installed
  5. Complete Civic Auth setup (see Access Token Setup below)

Access Token Setup (Next.js + Civic Auth)

Why Civic Auth? Nexus 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.)
  • 1. next.config.ts
  • 2. API Route
  • 3. Middleware
  • 4. Get Token
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)
Get your Client ID at auth.civic.com

Environment Variables

Create a .env.local file in your project root:
# Get your Client ID at https://auth.civic.com
CIVIC_AUTH_CLIENT_ID=your_client_id_here

# AI Provider API key from Vercel AI Gateway
AI_GATEWAY_API_KEY=your_api_key
Getting your API keys:
  1. Civic Client ID: Visit auth.civic.com, create a new application, and copy the Client ID
  2. AI Gateway API Key: Visit vercel.com/ai-gateway to get your API key for AI providers

Installation

Install the required packages:
pnpm install ai @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/react @modelcontextprotocol/sdk @civic/auth

Basic Setup

Create Nexus Tools Helper

import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { getTokens } from "@civic/auth/nextjs";
import { experimental_createMCPClient as createMCPClient } from "ai";

export const getNexusTools = async () => {
  const { accessToken } = (await getTokens()) ?? {};
  if (!accessToken) {
    // Return empty tools if no access token (Nexus is optional)
    return {};
  }

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

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

Complete Example: App Router API route

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

export async function POST(request: Request) {
  try {
    const { messages } = await request.json();

    if (!messages || !Array.isArray(messages)) {
      return new Response(
        JSON.stringify({ error: 'Invalid request: messages array required' }),
        { status: 400, headers: { 'Content-Type': 'application/json' } }
      );
    }

    // Convert UI messages to core messages
    const coreMessages = convertToCoreMessages(messages);

    // Get Nexus tools
    const nexusTools = await getNexusTools();

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

    // Use toUIMessageStreamResponse() for @ai-sdk/react compatibility
    return result.toUIMessageStreamResponse();
  } catch (error) {
    console.error('Chat error:', error);
    const errorMessage = error instanceof Error ? error.message : 'Failed to process request';

    return new Response(
      JSON.stringify({ error: errorMessage }),
      { status: 500, headers: { 'Content-Type': 'application/json' } }
    );
  }
}
Using Anthropic/Claude? Replace the model with:
import { anthropic } from '@ai-sdk/anthropic';

const result = streamText({
  model: anthropic('claude-sonnet-4-5-20250929'),
  messages: coreMessages,
  tools: nexusTools,
});

Nexus Authentication

headers: {
  Authorization: `Bearer ${accessToken}`,
  'Content-Type': 'application/json'
}
import { getTokens } from "@civic/auth/nextjs";
const { accessToken } = await getTokens();
https://nexus.civic.com/hub/mcp

Next Steps

1

Try the Starter Template

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

Connect Your Services

Visit nexus.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 with one click - all environment variables are pre-configured
I