Free guide · December 11, 2026
Migrate custom GPT actions to MCP.
When you migrate a custom GPT to a ChatGPT plugin, instructions and files come along. Custom actions don't. This guide shows how to rebuild an action from its OpenAPI schema as a remote MCP server, host it, and connect it in ChatGPT. Every claim about ChatGPT links to OpenAI's own pages, all accessed November 13, 2026.
OpenAI's retirement and migration FAQ: "GPT custom actions do not transfer through the migration workflow. Features that depend on them will not work in the plugin until you set up a replacement. [...] Rebuilding the connection may require a custom MCP server and technical setup." The scheduled retirement is December 11, 2026 (February 11, 2027 for FedRAMP workspaces and Enterprise workspaces with an approved deferral). Check the notice in your own account.
What carries over, and what doesn't.
From OpenAI's FAQ:
| Part of your GPT | After migration |
|---|---|
| Instructions | Carries over, as a skill within the new plugin |
| Knowledge files | Carries over, copied into the plugin's reference files |
| Connected apps | Carries over, added to the plugin as apps |
| Custom actions | Don't transfer. You need a replacement, which may be a custom MCP server |
| Selected model | Doesn't carry over |
| Sharing / audience | Not automatic. The plugin starts private, and existing GPT users don't get access automatically |
| Drafts and unpublished edits | Don't transfer. Migration uses the latest published version |
| Existing conversations | Stay accessible after retirement |
The FAQ also says the original GPT becomes read-only after migration, so finish edits and copy your action schema first.
Seven steps from schema to a working plugin tool.
- Check that your plan can use a custom MCP server
- Export the action's OpenAPI schema
- Convert the schema into an MCP server
- Put secrets in environment variables
- Host it on a public HTTPS endpoint
- Connect it in ChatGPT
- Test it against your old prompts
Step 1. Check that your plan can use a custom MCP server
OpenAI's help article says custom MCP server connections and full MCP support are available for ChatGPT Business and Enterprise/Edu on ChatGPT web, and that Pro users can connect custom MCP servers with read/fetch permissions.
Plan details from OpenAI's Connecting custom MCP servers in ChatGPT:
- Business. Full MCP, including write and modify actions. Only admins and owners can create and publish plugins for custom MCP servers.
- Enterprise/Edu. Full MCP. Admins and owners create and test connections and can grant members permission with role-based access control. Only admins and owners publish for the workspace.
- Pro. "Pro users can connect custom MCP servers with read/fetch permissions." Full MCP is "only available to Business and Enterprise/Edu users, currently."
- Plus and other plans. The article doesn't mention them. If you don't see Add custom MCP server under Plugins, your account can't do this step in ChatGPT.
- It's web only. The article's answer for mobile is "No - web only."
- Deep research can use custom apps for read/fetch actions only, not write actions.
The same MCP server also works in other MCP clients, so a rebuilt action isn't wasted if your ChatGPT plan can't use it yet.
Step 2. Export the action's OpenAPI schema
Before you migrate, open your GPT in the editor, open the action, and copy everything in its Schema box into a file. Note which authentication it uses: None, API Key, or OAuth.
In the GPT editor, copy the full OpenAPI schema from the Schema box into a file, for example action.json or action.yaml. OpenAI's GPT Actions guide describes this as the box where you "paste in your Open API schema". Repeat for each action. Write down:
- The authentication type. OpenAI's action authentication docs list three options: None, API Key or OAuth. The key or client secret itself isn't shown in the schema. You'll need it from the API provider.
- The
serversURL at the top of the schema. If it's relative (for example/api/v3), you'll need the full base URL. - Your GPT's instructions that mention the action by its operation name. Tool names in the rebuilt server come from the schema's
operationIds when present, so those references still make sense.
Do this before you migrate. After migration, the original GPT becomes read-only.
Step 3. Convert the schema into an MCP server
Run the converter on the schema file. It writes a self-contained server.mjs, a tools.json manifest, a .env.example and a README with tools, auth variables and warnings.
Our converter is free to use. It's two files, with no npm install needed. It needs Node.js 20.6 or newer. Keep both files in the same folder.
node convert.mjs action.yaml -o my-action
# relative server URL in the schema? pass the real base:
node convert.mjs action.yaml -o my-action --base-url https://api.example.com/v1
# only some operations, and a display name:
node convert.mjs action.yaml -o my-action --ops getThing,createThing --name "My API"
The input can be a JSON or YAML file, or an https URL to the schema. Tool names come from this function in the converter. If the operation has no operationId, a path like GET /v1/forecast becomes the tool get_v1_forecast:
function toolName(op, method, p, used) {
let base = op.operationId || `${method}_${p.replace(/\{([^}]+)\}/g, "by_$1")}`;
base = base
.replace(/[^A-Za-z0-9_-]+/g, "_")
.replace(/^_+|_+$/g, "")
.replace(/_+/g, "_")
.slice(0, 60) || `${method}_root`;
let n = base, i = 2;
while (used.has(n)) n = `${base}_${i++}`;
used.add(n);
return n;
}
The output folder contains:
server.mjs: the MCP server runtime (streamable HTTP, stateless, at/mcpby default, with health at/healthz).tools.json: one MCP tool per API operation. Each tool's input schema is the operation's parameters plus abodyargument when there is one. GET, HEAD and OPTIONS tools are marked read-only. DELETE tools are marked destructive..env.example: the settings and oneGAR_AUTH_<SCHEME>line per auth scheme in the schema.README.md: the tool list, auth variables and any conversion warnings. Read these first. They tell you what didn't convert.
It accepts OpenAPI 3.0 and 3.1 with local $refs, and path, query, header and cookie parameters with JSON or form bodies. Swagger 2.0 is rejected with a message, so convert it to OpenAPI 3 first.
Step 4. Put secrets in environment variables
Copy .env.example to .env and fill in the GAR_AUTH_ variables. The server adds the key or token to upstream requests and never sends it to the MCP client.
cd my-action
cp .env.example .env
# edit .env: fill in e.g. GAR_AUTH_APIKEYAUTH=... (never commit this file)
node --env-file=.env server.mjs
- API key (header, query or cookie), bearer and basic schemes are added server-side from
GAR_AUTH_<SCHEME>. For basic auth, the value isuser:password. - Other settings:
PORT,HOST,MCP_PATH,RATE_LIMIT_PER_MIN(per IP, 0 = off),UPSTREAM_TIMEOUT_MS(default 30000),MAX_RESPONSE_BYTES(default 100000),TRUST_PROXY=1behind a reverse proxy, and an optionalMCP_BEARER_TOKEN. - If a secret is missing, the tool returns a clear error instead of calling your API without it. Logs record only the tool name, upstream status and timing, not arguments or IPs.
Check it locally before hosting it. OpenAI's Connect and test your plugin page suggests MCP Inspector:
npx @modelcontextprotocol/inspector --cli http://127.0.0.1:8080/mcp --transport http --method tools/list
Step 5. Host it on a public HTTPS endpoint
Run server.mjs on a machine with Node 20.6 or newer behind a reverse proxy that serves HTTPS, so ChatGPT can reach the /mcp path. Or use Secure MCP Tunnel for a private server.
OpenAI's Connect and test your plugin page says the server must be reachable "through a public HTTPS endpoint or Secure MCP Tunnel", and that a public endpoint "supports streamable HTTP, typically at /mcp". Options:
- A small VPS or any always-on machine with Node 20.6+, running
server.mjsunder a process manager (for example systemd), behind a reverse proxy that serves HTTPS. SetHOST=127.0.0.1andTRUST_PROXY=1. - Any host that runs a long-lived Node process and gives it an HTTPS URL. The server keeps no state between requests and needs no database.
- Secure MCP Tunnel, if the server must stay on a private network. Its
tunnel-clientmakes outbound connections only. It needs OpenAI Platform tunnel permissions, which are separate from ChatGPT workspace permissions. OpenAI notes it doesn't support public plugin submission.
Without OAuth, the URL is the only protection. Set MCP_PATH to a long random path (for example /mcp/ plus 32 random hex characters), because anyone who has the URL can call the tools with your stored key. That's only acceptable for read-only or low-risk actions. MCP_BEARER_TOKEN works for other MCP clients, not ChatGPT (see Step 6).
Step 6. Connect it in ChatGPT
In ChatGPT on the web, go to Plugins, select the plus button, then Add custom MCP server. Enter the URL including the /mcp path, configure authentication, accept the risk warning, and select Create as a plugin.
From OpenAI's help article and Connect and test your plugin:
- On ChatGPT web, go to Plugins.
- Select the plus button, then Add custom MCP server.
- Enter a name and, optionally, a description.
- Under Connection, enter your public HTTPS MCP URL, including the
/mcppath (or your randomMCP_PATH). Or select Tunnel. - Configure authentication for your server.
- Review the risk warning and select "I understand and want to continue".
- Select Create as a plugin, then review the tools ChatGPT discovered.
No Developer Mode step is needed. The help article says: "In the current Plugins experience, add a custom MCP server directly from Plugins. You don't need to turn on Developer Mode first." Account and workspace policies still apply.
OpenAI's authentication guide says many MCP servers "can operate in a read-only, anonymous mode", and that anything exposing customer-specific data or write actions should authenticate users with OAuth 2.1. It also says ChatGPT "does not support machine-to-machine OAuth grants such as client credentials, service accounts, or JWT bearer assertions, nor can it present custom API keys". If you use OAuth, the help article warns that ChatGPT may lose access when the original authorization expires unless your provider issues refresh tokens (for OpenID Connect, the offline_access scope).
After you change the server (tool names, descriptions, schemas), open the connection in Plugins and select Refresh, per the connect guide. In Business and Enterprise/Edu workspaces, ChatGPT uses a frozen snapshot of the tools approved by an admin, and calls can error if the live server no longer matches until an admin refreshes it.
OpenAI's pages describe packaging a plugin "with its skills, manifest, and MCP server connection". We haven't found a step-by-step for adding a server to an already-migrated plugin, so follow the in-product options you see.
Step 7. Test it against your old prompts
Install the resulting plugin, start a new conversation, type @ to select it, and rerun the prompts you used with the GPT, including at least one harder case.
OpenAI's FAQ says a migrated plugin may respond differently and that a rebuilt integration "should not be assumed to provide every capability of the original action". Keep a few familiar prompts and one harder case, and check that the right tool is called with the right arguments. Per OpenAI's help article, ChatGPT may ask you to confirm write actions, so a pending confirmation can look like a call that silently failed.
Want to try it without your own API first? Our live demo server, a public weather API rebuilt with this converter, no auth, rate-limited, is at https://gptrescue.pages.dev/mcp. See the demo section.
Common failures, and what to do.
| Symptom | Cause and fix |
|---|---|
| OAuth-only operations (the action used "Sign in with ...") | The converter warns: per-user OAuth is not proxied. It can only send one static token from GAR_AUTH_<SCHEME> as a bearer, like a service account or long-lived token. A real per-user sign-in needs an OAuth 2.1 authorization server that meets the MCP authorization spec. OpenAI's auth guide lists PKCE with S256, protected resource metadata, and client registration via CIMD, DCR or a predefined client. MCP connections use different redirect URIs from the old action callback. Copy the exact one shown on the MCP server's management page. |
| File uploads missing | Operations with multipart/*, application/octet-stream or image/* request bodies are skipped and listed in the warnings. Keep those as a separate flow, or change the API to accept a URL or base64 JSON field. |
Relative server URL (servers: - url: /api/v3) | The converter warns that the server URL is relative and to pass --base-url. Rerun with --base-url https://your-api.example.com. If you pass the schema as an https URL, relative servers resolve against it. |
| ChatGPT can't connect | Check the URL includes /mcp and is HTTPS, then run MCP Inspector against the public URL. The server answers POST only, so a browser GET on /mcp returns 405, which is expected. |
| You want ChatGPT to send an API key or bearer token | It can't. Keep the upstream key in .env and use no auth on a random path for low-risk tools, or OAuth. |
| Read tools work but write tools don't | On Pro, custom MCP servers are read/fetch only, and deep research is read/fetch only. Also check for a pending confirmation prompt. |
| Tools stopped working after you edited the server | Refresh the connection in Plugins. In workspaces, an admin must refresh the approved snapshot. |
Swagger 2.0 is not supported | Convert the schema to OpenAPI 3 first. |
| Upstream returns an error | The tool returns the HTTP status and body as an error result, so you can see it in ChatGPT or Inspector. Test the same call with curl to rule out the API itself. |
Also not supported by the converter: external $ref files, streaming responses, and per-user state.
Straight answers.
Do custom GPT actions transfer when I migrate my GPT to a plugin?
No. OpenAI's FAQ says GPT custom actions do not transfer through the migration workflow, and that rebuilding the connection may require a custom MCP server and technical setup.
When do custom GPTs retire?
OpenAI's FAQ gives December 11, 2026 as the scheduled retirement date. FedRAMP workspaces and affected Enterprise workspaces with a qualifying, approved deferral have February 11, 2027. Follow the notice in your own account.
Do I need Developer Mode to add a custom MCP server?
No. OpenAI's help article says that in the current Plugins experience you add a custom MCP server directly from Plugins and don't need to turn on Developer Mode first. You acknowledge a risk warning for each server instead.
Can ChatGPT send my API key to the MCP server?
No. OpenAI's authentication guide says ChatGPT cannot present custom API keys. Keep the API key on the MCP server as an environment variable, and use OAuth or no authentication between ChatGPT and the server.
Can I connect a custom MCP server on ChatGPT mobile?
No. OpenAI's help article answers that connecting custom MCP servers is web only.
What we checked, and when.
All accessed November 13, 2026. We only state what these pages said on that date. ChatGPT changes often, so check them again.
- OpenAI Help Center, Custom GPT retirement and migration FAQ
- OpenAI Help Center, Connecting custom MCP servers in ChatGPT
- OpenAI Developers, Connect and test your plugin
- OpenAI Developers, Authentication (Apps SDK)
- OpenAI Developers, Secure MCP Tunnel
- OpenAI Platform docs, Getting started with GPT Actions and GPT Action authentication
Want it done for you?
We rebuild and host the action from your schema, test it against your real API, and help you connect it. We'll tell you whether it fits before you pay anything. Scope and price · northlab.research@outlook.com