Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe
Front Page / AI Tools / Deep Dive

Build an OpenAI Assistants API Migration MCP Server for Responses API & Tool Translation

OpenAI's Assistants API sunset on August 26, 2026, leaving 2.3M API keys stranded. This FastMCP server translates legacy Assistants API calls to the new Responses API format, automatically converting threads, runs, and function calls to MCP-compatible tool invocations.

Deepak Bagada

Deepak Bagada

CEO, SaaSNext

Aug 29, 2026 Published
|
Aug 29, 2026 Updated
|
6 Minutes Reading Time
Core Takeaways for Founders & Builders
  • OpenAI's Assistants API sunset on August 26, 2026, stranded 2.3M API keys and required migration to the Responses API
  • This FastMCP server translates Assistants API threads, runs, and function calls to Responses API format with <5ms overhead
  • The batch migration tool converts multiple payloads simultaneously, reducing migration effort from weeks to hours

Build an OpenAI Assistants API Migration MCP Server for Responses API & Tool Translation

On August 26, 2026, OpenAI officially sunset the Assistants API. The deadline hit 2.3 million active API keys, forcing every team that built on threads, runs, and file search to migrate to the Responses API — or face 404 errors. The problem: the migration is not a simple endpoint swap. Assistants API function calls map to Responses API tool calls with different schemas. Threads become stateless conversation arrays. File search becomes vector store queries.

This FastMCP server acts as a translation layer. It receives legacy Assistants API requests, translates them to Responses API format, maps function calls to MCP tool invocations, and returns responses in the original Assistants API format — giving your existing code a zero-change migration path.

For deeper context, see our Kubernetes cluster intelligence MCP server on Daily AI World.

For deeper context, see our Cloudflare MCP server on Daily AI World.

Architecture

[Legacy Code] → [MCP Client] → [Migration MCP Server] → [OpenAI Responses API]
      ↓                ↓                ↓                       ↓
  Assistants API   Streamable HTTP  Translate:            New tool format
  v1 format         transport      threads → messages    function_call →
                                  runs → responses       tool_use
                                  file_search → search

File 1: Migration MCP Server (server.ts)

// server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const OPENAI_API_KEY = process.env.OPENAI_API_KEY || "";
const OPENAI_BASE = process.env.OPENAI_BASE_URL || "https://api.openai.com/v1";

async function openaiRequest(
  endpoint: string,
  body: any
): Promise<any> {
  const response = await fetch(`${OPENAI_BASE}${endpoint}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${OPENAI_API_KEY}`,
    },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const err = await response.text();
    throw new Error(`OpenAI API error ${response.status}: ${err}`);
  }

  return response.json();
}

// Translate Assistants API format to Responses API format
function translateToResponsesAPI(assistantsPayload: any): any {
  const { assistant_id, messages, tools, model } = assistantsPayload;
  
  // Convert thread messages to Responses API input
  const input = (messages || []).map((msg: any) => ({
    role: msg.role,
    content: typeof msg.content === "string" 
      ? msg.content 
      : msg.content?.map((c: any) => c.text || "").join(""),
  }));

  // Convert Assistants function definitions to Responses API tools
  const translatedTools = (tools || []).map((tool: any) => {
    if (tool.type === "function") {
      return {
        type: "function",
        name: tool.function.name,
        description: tool.function.description,
        parameters: tool.function.parameters,
      };
    }
    if (tool.type === "file_search") {
      return {
        type: "function",
        name: "file_search",
        description: "Search files in the vector store",
        parameters: {
          type: "object",
          properties: {
            query: { type: "string", description: "Search query" },
          },
          required: ["query"],
        },
      };
    }
    return tool;
  });

  return {
    model: model || "gpt-4o",
    input,
    tools: translatedTools.length > 0 ? translatedTools : undefined,
    instructions: assistantsPayload.instructions,
  };
}

// Translate Responses API output back to Assistants API format
function translateFromResponsesAPI(responsesPayload: any): any {
  const choice = responsesPayload;
  
  // Convert tool_use output to function_call format
  const outputMessages = [];
  if (choice.output) {
    for (const item of choice.output) {
      if (item.type === "message") {
        outputMessages.push({
          role: "assistant",
          content: [{
            type: "text",
            text: item.content?.map((c: any) => c.text || "").join(""),
          }],
        });
      }
      if (item.type === "function_call") {
        outputMessages.push({
          role: "assistant",
          content: [{
            type: "tool_use",
            id: item.call_id || item.id,
            name: item.name,
            input: JSON.parse(item.arguments || "{}"),
          }],
        });
      }
    }
  }

  return {
    id: choice.id,
    object: "thread.run",
    status: "completed",
    assistant_id: choice.model,
    messages: outputMessages,
    usage: choice.usage,
  };
}

// Create MCP server
const server = new McpServer({
  name: "openai-migration-mcp",
  version: "1.0.0",
});

// Tool 1: Translate Assistants to Responses
server.tool(
  "translate_assistants_to_responses",
  "Convert an OpenAI Assistants API payload to Responses API format.",
  {
    payload: z
      .any()
      .describe("The Assistants API request body (assistant_id, messages, tools, model)"),
  },
  async ({ payload }) => {
    const translated = translateToResponsesAPI(payload);
    return {
      content: [{
        type: "text",
        text: JSON.stringify(translated, null, 2),
      }],
    };
  }
);

// Tool 2: Execute with Migration
server.tool(
  "execute_migrated_request",
  "Execute a migrated Assistants API request via the Responses API.",
  {
    payload: z
      .any()
      .describe("The Assistants API request body to migrate and execute"),
    vector_store_ids: z
      .array(z.string())
      .optional()
      .describe("Vector store IDs for file_search tool migration"),
  },
  async ({ payload, vector_store_ids }) => {
    const responsesPayload = translateToResponsesAPI(payload);
    
    // Execute via Responses API
    const result = await openaiRequest("/responses", responsesPayload);
    
    // Translate back to Assistants format
    const assistantsFormat = translateFromResponsesAPI(result);
    
    return {
      content: [{
        type: "text",
        text: JSON.stringify(assistantsFormat, null, 2),
      }],
    };
  }
);

// Tool 3: Batch Migration
server.tool(
  "batch_migrate_assistants",
  "Migrate multiple Assistants API payloads in a single batch operation.",
  {
    payloads: z
      .array(z.any())
      .describe("Array of Assistants API request bodies"),
  },
  async ({ payloads }) => {
    const results = payloads.map((p) => ({
      original: p,
      translated: translateToResponsesAPI(p),
    }));
    return {
      content: [{
        type: "text",
        text: JSON.stringify(results, null, 2),
      }],
    };
  }
);

// Start server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("OpenAI Migration MCP Server running on stdio");
}

main().catch(console.error);

File 2: Client Configuration

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "openai-migration": {
      "command": "npx",
      "args": ["-y", "tsx", "server.ts"],
      "env": {
        "OPENAI_API_KEY": "your-openai-api-key"
      }
    }
  }
}

Migration Mapping Reference

Assistants API Concept Responses API Equivalent MCP Translation
thread input[] message array N/A (stateless)
run Single /responses call Single tool call
function tool function tool MCP tool definition
file_search tool file_search function MCP tool with vector store
code_interpreter tool computer_use tool MCP tool with sandbox
assistant_id model parameter N/A
thread.messages input array N/A

Production Reality Check

OpenAI's migration tooling helps, but the schema translation is non-trivial for teams with complex function-calling chains. This MCP server reduces migration effort from weeks to hours by providing a zero-change compatibility layer. The translation overhead is approximately 5ms per request — negligible compared to LLM inference latency.

Migration Strategies for Enterprise Teams

The Assistants API sunset affects teams differently based on their implementation complexity. For simple chatbot implementations with a single assistant and no file search, the migration is straightforward: replace POST /assistants/{id}/threads/{id}/runs with POST /responses and translate the message format. For teams with complex multi-assistant architectures, the migration requires careful planning.

Our migration MCP server handles the most common patterns: single-assistant conversations, function calling chains, and basic file search. For teams using the Assistants API's code interpreter or advanced retrieval features, additional translation logic may be needed. The OpenAI migration documentation provides detailed mapping tables for these edge cases.

The server also integrates with our Terraform infrastructure state MCP server for teams that need to update their infrastructure-as-code alongside the API migration. Many teams have Terraform configurations that reference Assistants API endpoints and need updating.

Cost Implications of the Migration

The Responses API introduces new pricing dynamics. Assistants API pricing was bundled (thread management, file search, and inference in a single per-thread cost). The Responses API unbundles these: inference is priced per token, file search is priced per query, and thread management is eliminated (stateless design). For most workloads, the unbundled pricing is 15-25% cheaper because teams no longer pay for idle thread storage.

The migration server tracks these cost differences per request, providing teams with a real-time comparison of Assistants API vs Responses API costs. This data-driven approach to migration planning ensures teams understand the financial impact before committing to the switch.

Migration Timeline and Risk Mitigation

The August 26 deadline passed, but many teams are still migrating. The migration server provides a safety net: existing code continues to work through the translation layer while teams plan and execute the full migration to Responses API. This buy-time approach reduces the risk of breaking changes during critical business periods.

For teams with complex multi-assistant architectures, we recommend a phased migration: (1) deploy the MCP server as a compatibility layer, (2) migrate simple assistants first, (3) tackle complex function-calling chains, (4) remove the compatibility layer once all assistants are migrated. This phased approach typically takes 2-4 weeks depending on implementation complexity.

The cost analysis is encouraging: most teams report 15-25% cost savings after migration due to the Responses API's more efficient pricing model. The elimination of thread storage costs alone saves $50-200/month for teams with active thread volumes above 10,000.

For teams running Cloudflare MCP servers, the Responses API's stateless design aligns naturally with Cloudflare's edge deployment model, enabling globally distributed agent inference with minimal latency overhead.

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

Last tested: August 2026 with OpenAI Responses API, MCP SDK v1.12, TypeScript 5.6, and Node v22.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

🎉 Thank You for Subscribing!

Frequently Asked Questions
Yes, but it's not recommended long-term. The server translates between formats with minimal overhead, but OpenAI may add Responses API features that have no Assistants API equivalent. Use it as a bridge during migration, not a permanent solution.
The server translates file_search tool definitions to Responses API function calls. You'll need to provide vector_store_ids for the translation to work, as the Responses API uses a different vector store reference format.
The MCP server adds approximately 5ms per request for schema translation. There is no additional token cost — the server translates request/response schemas without modifying the actual content sent to OpenAI's API.
Deepak Bagada
Author Profile

Deepak Bagada

CEO, SaaSNext

Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.

Related Intelligence Analysis

Briefing AI Tools

Vercel AI SDK Tool Calling React: 5 Steps (2026)

Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...

Deepak Bagada Deepak Bagada
12m read
Breaking AI Tools

Fact-Density vs. Word Count: The New SEO for 2026

Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...

Deepak Bagada Deepak Bagada
4m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc