Skip to main content

OpenAI SDK

Overview

This recipe shows how to wire Civic MCP tools to the OpenAI Node SDK using manual function calling.

note

Want a simpler approach? The OpenAI Agents SDK recipe uses hostedMcpTool() — no manual tool looping required. Use this page if you need full control over the tool loop.

Prerequisites

Installation

pnpm add openai @civic/mcp-client

Authentication

Generate a Civic Token

  1. Log in to app.civic.com
  2. Click your account name in the bottom left
  3. Go to 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.

Set Environment Variables

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:

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:

headers = {"Authorization": f"Bearer {os.environ['CIVIC_TOKEN']}"}
headers: { Authorization: `Bearer ${process.env.CIVIC_TOKEN}` }
Full credentials guide

Token generation, URL parameters, OAuth vs token comparison

# .env
OPENAI_API_KEY=your_openai_api_key
CIVIC_TOKEN=your-civic-token-here

Create a Civic Client

import { CivicMcpClient } from '@civic/mcp-client';
import { openAIAdapter } from '@civic/mcp-client/adapters/openai';

function createCivicClient(token: string) {
return new CivicMcpClient({ auth: { token } });
}

Call with Tool Functions

import OpenAI from 'openai';

export async function chatWithTools(messages: any[], civicToken: string) {
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! });
const client = createCivicClient(civicToken);
const tools = await client.getTools(openAIAdapter());

// Multi-turn tool loop — runs until the model stops requesting tools
let response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages,
tools,
tool_choice: 'auto',
});

while (response.choices[0]?.finish_reason === 'tool_calls') {
const toolCalls = response.choices[0].message.tool_calls ?? [];
const toolResults = await Promise.all(
toolCalls.map(async (call) => {
const args = JSON.parse(call.function.arguments || '{}');
const result = await client.callTool(call.function.name, args);
return {
role: 'tool' as const,
tool_call_id: call.id,
content: JSON.stringify(result.content),
};
})
);

messages = [
...messages,
response.choices[0].message,
...toolResults,
];

response = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages,
tools,
});
}

await client.close();
return response;
}

Usage

// Backend / Script
const result = await chatWithTools(
[{ role: 'user', content: 'List my GitHub repositories' }],
process.env.CIVIC_TOKEN!
);
console.log(result.choices[0].message.content);

Next Steps