OpenAI + Claude Code Integration Guide
What is the OpenAI API?
Multi-modal stateless API with tools, structured outputs, and a realtime channel.
GPT-5 / GPT-4o / o-series live behind a single API. Use `response_format: { type: "json_schema", schema: ... }` for guaranteed-shape outputs — no Zod re-parsing. Tools are first-class: `tools: [{ type: "function", function: {...} }]` with parallel calls. The Realtime API streams bidirectional audio over WebRTC/WebSocket for voice agents. For multi-step jobs, the Assistants API gives you durable threads + file search. For codeAmani, OpenAI is the structured-output and function-calling specialist; Claude takes the harder reasoning.
Five OpenAI primitives
Same API surface across models. Pick the right tier and the right output mode.
██████╗ ██████╗ ███████╗███╗ ██╗ █████╗ ██╗
██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔══██╗██║
██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████║██║
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██╔══██║██║
╚██████╔╝██║ ███████╗██║ ╚████║██║ ██║██║
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝OpenAI + Claude Code Integration Guide
Focus: Integrating OpenAI models and APIs alongside Claude Code workflows — dual-provider pipelines, MCP access to OpenAI assistants, and cross-model automation.
Overview
Claude Code and OpenAI are complementary. OpenAI's Assistants, Files, Fine-tuning, and Responses APIs can be consumed inside Claude Code via the openai SDK, or accessed through an MCP server that exposes OpenAI account resources as tools. This lets you build hybrid workflows — e.g., route code tasks to Claude, creative/vision tasks to GPT-4o, all from one Claude Code session.
Here is the simple mental model of where OpenAI sits as the secondary provider — reach for it when structured output or function calling matters, while Claude stays primary for reasoning.
Official Documentation
| Resource | URL |
|---|---|
| OpenAI API Reference | https://platform.openai.com/docs/api-reference |
| OpenAI Node SDK | https://github.com/openai/openai-node |
| OpenAI Python SDK | https://github.com/openai/openai-python |
| OpenAI MCP Adoption Announcement | https://openai.com/blog/openai-adopts-model-context-protocol |
| MCP + Responses API | https://platform.openai.com/docs/guides/tools |
MCP Server Setup
openai-mcp — Access OpenAI Account via MCP
The openai-mcp server exposes your OpenAI account (models, assistants, files, threads, fine-tuning jobs) as MCP tools.
npm install -g openai-mcp.mcp.json Configuration
{
"mcpServers": {
"openai": {
"command": "npx",
"args": ["-y", "openai-mcp"],
"env": {
"OPENAI_API_KEY": "${OPENAI_API_KEY}"
}
}
}
}Add via Claude Code CLI:
claude mcp add openai -- npx -y openai-mcpAvailable MCP Tools
| Tool | Description |
|---|---|
list_models | List all available OpenAI models |
create_chat_completion | Call any OpenAI chat model |
list_assistants | List your Assistants |
create_assistant | Create a new Assistant |
upload_file | Upload a file to OpenAI Files API |
list_files | List uploaded files |
create_fine_tuning_job | Start a fine-tuning run |
get_fine_tuning_job | Check fine-tuning status |
CLI Integration
OpenAI CLI (Python)
pip install openai# List models
openai api models.list
# Create a chat completion
openai api chat.completions.create \
-m gpt-4o \
-g user "Explain this TypeScript error: ..."
# Check fine-tuning job
openai api fine_tuning.jobs.retrieve -i <job_id>One-liner from Claude Code
Inside a Claude Code session you can run shell commands:
# Pipe Claude Code output to OpenAI for a second opinion
echo "Review this code for memory leaks" | openai api chat.completions.create -m gpt-4o -g user -OpenAI SDK Integration
You are about to wire up the core request flow — here is how a chat completion travels from your app through the SDK to the model and back.
Node.js / TypeScript
npm install openaiimport OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// GPT-4o chat completion
const completion = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{ role: "system", content: "You are a TypeScript expert." },
{ role: "user", content: "Convert this class to use composition over inheritance." },
],
});
console.log(completion.choices[0].message.content);Python
pip install openaifrom openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Generate unit tests for this function."}],
)
print(response.choices[0].message.content)Structured output & function calling
This is the reason OpenAI earns its place as the secondary provider. When you need the model to return data your code can trust — not prose you have to regex — reach for Structured Outputs. The Node SDK ships a client.chat.completions.parse() helper plus two Zod adapters from openai/helpers/zod: zodResponseFormat() constrains the whole response to a schema, and zodFunction() does the same for a tool's arguments. With strict: true (which zodFunction() sets for you), the model is guaranteed to emit JSON that matches your schema, and the SDK hands you a fully typed parsed object — no JSON.parse, no validation boilerplate.
Here is the flow: you define a Zod schema, the SDK ships it as a strict JSON schema, the model is constrained to match, and you get a typed object back.
(a) Structured output via a Zod schema
Use this when you want the model's answer shaped to a schema — extraction, classification, form-filling. The parsed field is typed as z.infer<typeof Schema>.
import OpenAI from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
// e.g. extract structured order data from a free-text M-Pesa SMS
const OrderExtraction = z.object({
amount_kes: z.number().int(), // Daraja amounts are integer KES
phone: z.string(), // normalise to 254XXXXXXXXX downstream
reference: z.string(),
confidence: z.enum(["high", "medium", "low"]),
});
const completion = await client.chat.completions.parse({
model: "gpt-4o-2024-08-06",
messages: [
{ role: "system", content: "Extract the payment fields from the message." },
{ role: "user", content: "Got KES 1500 from 0712345678 ref INV-204" },
],
response_format: zodResponseFormat(OrderExtraction, "order_extraction"),
});
const order = completion.choices[0].message.parsed;
if (order) {
console.log(order.amount_kes, order.phone, order.confidence); // fully typed
}(b) Tool / function call
Use this when you want the model to decide which function to call and with what arguments. zodFunction() builds the tool definition (with strict: true), and the parsed arguments arrive on tool_calls[].function.parsed_arguments.
import OpenAI from "openai";
import { zodFunction } from "openai/helpers/zod";
import { z } from "zod";
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const StkPushArgs = z.object({
amount_kes: z.number().int(),
phone: z.string(),
account_ref: z.string(),
});
const completion = await client.chat.completions.parse({
model: "gpt-4o-2024-08-06",
messages: [
{ role: "user", content: "Charge 0712345678 KES 500 for order INV-9" },
],
tools: [zodFunction({ name: "initiate_stk_push", parameters: StkPushArgs })],
});
const toolCall = completion.choices[0].message.tool_calls?.[0];
if (toolCall) {
const args = toolCall.function.parsed_arguments as z.infer<typeof StkPushArgs>;
// now call your real lib/mpesa-stk.ts with typed, schema-validated args
console.log(args.amount_kes, args.phone, args.account_ref);
}Gotcha: Structured Outputs requires a recent snapshot — use
gpt-4o-2024-08-06or newer (not the oldergpt-4o-2024-05-13), or the request will error. Also, every field in a strict schema is required by default; to make a field optional, model it asz.union([T, z.null()])(a nullable field) rather than.optional(), since strict mode does not allow omitted keys.
Environment Variables
# Required
OPENAI_API_KEY=sk-proj-...
# Optional
OPENAI_ORG_ID=org-...
OPENAI_PROJECT_ID=proj_...
OPENAI_BASE_URL=https://api.openai.com/v1 # default; change for Azure OpenAIStore in .env and load with dotenv or python-dotenv.
Automation Workflows
Dual-Provider Review Hook
Use a Claude Code Stop hook to send the session summary to OpenAI for a cross-model review:
.claude/settings.json:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "node scripts/openai-second-opinion.js"
}
]
}
]
}
}scripts/openai-second-opinion.js:
import OpenAI from "openai";
import { readFileSync } from "fs";
const client = new OpenAI();
const sessionLog = readFileSync(".claude/session.log", "utf-8");
const result = await client.chat.completions.create({
model: "gpt-4o",
messages: [
{ role: "system", content: "Review this Claude Code session for potential issues." },
{ role: "user", content: sessionLog },
],
});
console.log("GPT-4o review:", result.choices[0].message.content);Slash Command: Route to GPT-4o
.claude/commands/gpt.md:
Use the Bash tool to call OpenAI's GPT-4o API with this prompt: $ARGUMENTS
Command:
```bash
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o","messages":[{"role":"user","content":"'"$ARGUMENTS"'"}]}'
Usage: `/project:gpt "What are the tradeoffs of this architecture?"`
### CI/CD: OpenAI Code Quality Gate
```yaml
# .github/workflows/ai-review.yml
name: AI Code Review
on: [pull_request]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get diff
run: git diff origin/main...HEAD > diff.txt
- name: OpenAI review
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
pip install openai
python scripts/review.py diff.txtCommon Use Cases
| Use Case | Approach |
|---|---|
| Vision-based UI review | Send screenshots to GPT-4o via Files API |
| Embeddings for code search | text-embedding-3-small on your codebase |
| Fine-tuning for style | Train GPT-4o-mini on your code patterns |
| Assistants for long tasks | Use Assistants API with file_search tool |
| Cross-model validation | Claude drafts, GPT-4o validates |
Troubleshooting
| Issue | Fix |
|---|---|
openai-mcp not found | Run npm install -g openai-mcp first |
| 401 Unauthorized | Check OPENAI_API_KEY value and project permissions |
| Model not available | Check model access in platform.openai.com/settings |
| Rate limits | Use exponential backoff; check tier limits |
| Azure OpenAI endpoint | Set OPENAI_BASE_URL=https://<resource>.openai.azure.com |