AgentStack
MCP verified MIT Self-run

ChatGPT Web2API

mcp-octo-lex-chatgpt-web2api · by Octo-Lex

OpenAI-compatible API proxy for ChatGPT web — expose ChatGPT as an MCP server, REST API, and OpenAI SDK endpoint via CDP-driven browser automation

No reviews yet
0 installs
6 views
0.0% view→install

Install

$ agentstack add mcp-octo-lex-chatgpt-web2api

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution Used
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of ChatGPT Web2API? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

ChatGPT-Web2API

Turn ChatGPT into an API. No API key. No token extraction. No sentinel solving.

One command starts a Chrome browser, logs into ChatGPT, and exposes an OpenAI-compatible API + MCP server.

[](https://github.com/Elephant-Rock-Lab/ChatGPT-Web2API/actions/workflows/ci.yml) [](https://github.com/Elephant-Rock-Lab/ChatGPT-Web2API/releases) [](LICENSE) [](https://www.python.org/downloads/) [](https://github.com/Elephant-Rock-Lab/ChatGPT-Web2API/actions)


Why This Exists

You have a ChatGPT Plus subscription but want to use it programmatically:

  • Build AI agents that chat with ChatGPT via MCP (Model Context Protocol)
  • Use the OpenAI Python SDK against your ChatGPT account — no separate API key
  • Access ChatGPT Projects for persistent memory and custom instructions
  • Manage memories, conversations, and projects from code

Other reverse proxies require token extraction, sentinel challenge solving, or cookie management. This one drives a real Chrome browser — anti-bot challenges (Turnstile, PoW) are handled automatically.

Demo

$ pip install chatgpt-web2api
$ chatgpt-web2api
✓ Chrome launched on port 9222
✓ Navigating to chatgpt.com...
✓ Ready on http://localhost:8080

$ curl -s http://localhost:8080/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{"model":"auto","messages":[{"role":"user","content":"What is 8+7?"}]}'
{"choices":[{"message":{"content":"8 + 7 = 15"},"finish_reason":"stop"}]}
# OpenAI Python SDK — drop-in replacement
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8080/v1", api_key="not-needed")
print(client.chat.completions.create(
    model="auto",
    messages=[{"role": "user", "content": "What is 8+7?"}]
).choices[0].message.content)
# → "8 + 7 = 15"

How It Works

┌──────────────┐   OpenAI API   ┌──────────────┐   CDP    ┌──────────────┐
│  Your code   │ ──────────────► │  API Server  │ ────────► │    Chrome     │
│  SDK / curl  │ ◄────────────── │  or MCP      │ ◄──────── │  chatgpt.com  │
│  MCP client  │   JSON / SSE    │  Server      │  events   │  (logged in)  │
└──────────────┘                 └──────────────┘           └──────────────┘

The proxy types messages, clicks send, and reads responses — exactly like a human. The browser handles all anti-bot challenges transparently.

Quick Start

pip install chatgpt-web2api

# Start — opens Chrome, waits for login on first run
chatgpt-web2api

# Then use it:
curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","messages":[{"role":"user","content":"What is 2+2?"}]}'
# → {"choices":[{"message":{"content":"4"}}]}

That's it. One install, one command, one endpoint.

What You Get

🌐 OpenAI-Compatible REST API

Drop-in replacement for api.openai.com:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8080/v1", api_key="not-needed")

response = client.chat.completions.create(
    model="auto",
    messages=[{"role": "user", "content": "Hello!"}],
    stream=True,
)
for chunk in response:
    print(chunk.choices[0].delta.content or "", end="")

⏱️ Rate Limits & Agent Retry

ChatGPT occasionally shows a "Too many requests" pop-up when conversations are accessed rapidly. ChatGPT-Web2API turns this from a silent failure into a practical, agent-friendly signal — so autonomous workflows back off and recover instead of breaking.

Transparent by default. When the pop-up appears, the server dismisses it (clicks "Got it") and retries your request with exponential backoff — up to 3 attempts. A transient limit is invisible: your agent gets a normal successful response and never knows it happened.

A clean pause signal when it persists. If the limit survives all retries, the server surfaces a standard OpenAI 429 that every major agent framework already knows how to handle — with zero client-side integration:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
{"error": {"type": "rate_limit_exceeded", "code": "rate_limit_exceeded", ...}}

The OpenAI SDK, LangChain, LlamaIndex, and similar frameworks auto-retry on 429 + Retry-After by default. The wait (Retry-After) is parsed from the pop-up text when ChatGPT gives an exact number, otherwise a conservative 60s.

MCP clients (Claude Desktop, Cursor) get the same signal semantically: a CallToolResult with isError=True and a machine-readable structuredContent payload an agent can read to decide "pause, then retry this tool":

{"rate_limited": true, "retry_after": 60, "error": "rate_limit_exceeded"}

> Streaming caveat: a 429 can be sent before streaming begins (a pre-flight > check), but a limit that appears mid-stream (after the 200 is committed) is > surfaced as an inline [Error: rate_limit_exceeded — retry in Ns] chunk, > since the HTTP status can no longer change. Non-streaming requests are > unaffected.

🩺 Troubleshooting API/UI Drift

ChatGPT changes its web API over time, which can silently break driver functions (the unit-test mocks can't detect this). ChatGPT-Web2API ships a reactive diagnostic that captures evidence at the moment a function breaks, plus a doctor command that auto-discovers the breakage and prints the evidence for fast repair.

Enable capture (off by default) so breakage in the wild is recorded:

W2A_DIAGNOSE=1 chatgpt-web2api start

When a function returns a broken shape, a redacted artifact is written to ~/.chatgpt-web2api/diagnostics/--.json with the exact request, live response, expected-vs-actual mismatch (secrets stripped).

Auto-discover + diagnose:

chatgpt-web2api doctor               # which functions have captured breakage?
chatgpt-web2api doctor create_project# print the captured evidence for one
chatgpt-web2api doctor --verify get_models   # re-run a read function live to test a fix

doctor (no args) auto-discovers which functions are broken — no human needs to name them. It then prints the evidence an AI coding agent (or you) reads to propose the corrected payload/selector/parse. --verify confirms a read-path fix against the live account before you commit it. No AI is bundled — the project captures deterministic evidence; the fix is human-applied.

🤖 MCP Server (16 Tools for AI Agents)

Expose ChatGPT to Claude Desktop, Cursor, Craft Agent, or any MCP client. Two transports are supported — SSE is recommended for persistent clients like ZCode; stdio is kept as a compatibility/dev mode.

SSE transport (persistent server; single active session until B1)

SSE is useful for one long-lived MCP server, but current master does not yet provide per-client tab/session isolation inside one SSE process. Multiple MCP clients may attach to the same SSE endpoint, but they share one MCP server, one CDPDriver, one Chrome tab, and one browser conversation surface. Running parallel agent sessions through the same SSE server can cause cross-session interference: one session may navigate, continue, or mutate the browser state expected by another.

Until the B1 MCP session-affine tab pool is implemented and enabled, use SSE for a single active agent session at a time. For parallel agent sessions today, use separate MCP processes with parallel_tabs=true and tab_mode=owned, and ensure the Chrome-owning chatgpt-web2api REST process is started with the same parallel config or is not serving REST traffic on that CDP port. Otherwise, wait for B1.

Start it (in a dedicated terminal — Chrome must already be running with an authenticated session, i.e. chatgpt-web2api started first):

chatgpt-web2api-mcp --transport sse --port 8090

Then add the client config:

{
  "mcpServers": {
    "chatgpt-web2api-sse": {
      "type": "sse",
      "url": "http://localhost:8090/sse"
    }
  }
}

Every client session that attaches to that URL currently shares the single MCP server and Chrome connection. This avoids per-session process growth, but it is not safe for parallel independent agent sessions until B1's session-affine driver/tab pool is available and explicitly enabled.

> Multi-session warning: A2 prevents stale-return by anchoring responses to > the submitted turn, but it does not isolate multiple MCP SSE clients from each > other. Shared SSE remains a single browser-control surface today.

Alternative: stdio transport (per-session, dev/debug)

Stdio spawns one MCP child process per client session, so it is not recommended for many concurrent ZCode sessions. It is useful for single-client setups, local development, and debugging (logs go straight to stderr):

{
  "mcpServers": {
    "chatgpt": {
      "command": "chatgpt-web2api-mcp",
      "args": ["--cdp-port", "9222"]
    }
  }
}

16 tools give the agent full control:

| Tool | What it does | |------|-------------| | chat_completion | Send message, get response (multi-turn, streaming) | | list_models | 17 live model slugs (GPT-5.5, 5.4 Thinking, etc.) | | list_projects | ChatGPT projects with persistent memory | | create_project | Create isolated workspace with dedicated memory | | delete_project | Permanently remove a project (gated: W2A_ENABLE_DESTRUCTIVE) | | list_conversations | Recent chats with pagination | | get_conversation | Full message history | | archive_conversation | Archive/unarchive (reversible) | | delete_conversation | Delete permanently | | list_memories | Facts ChatGPT remembers (41 found in testing) | | create_memory | Tell ChatGPT to remember something | | delete_memory | Remove a memory | | list_gpts | Discover Custom GPTs | | chat_with_gpt | Chat with a specific Custom GPT | | update_project_instructions | Change project system prompt | | list_project_files | Files in a project's knowledge base |

Every tool includes rich descriptions with domain knowledge, Pydantic-validated input, structured output schemas, and proper ToolAnnotations — agents understand how and when to use each one without prompting.

🔒 MCP Tool Access Control

The MCP server has no authentication of its own — any client that can reach it can call its tools. Since several tools mutate or delete data on your real ChatGPT account, tools are gated by risk tier so the dangerous ones are never exposed by accident:

| Tier | Tools | Exposed when | |------|-------|--------------| | Safe (always visible) | chat_completion, chat_with_gpt, list_models, list_projects, list_conversations, get_conversation, list_memories, list_gpts, list_project_files | Out of the box | | Write (account mutation) | create_project, update_project_instructions, create_memory, archive_conversation | W2A_ENABLE_WRITE=1 | | Destructive (irreversible) | delete_conversation, delete_memory | W2A_ENABLE_DESTRUCTIVE=1 |

# Default: safe reads + core chat only — nothing can mutate your account
chatgpt-web2api-mcp

# Enable project/memory/archive creation
W2A_ENABLE_WRITE=1 chatgpt-web2api-mcp

# Full surface (also exposes deletes)
W2A_ENABLE_WRITE=1 W2A_ENABLE_DESTRUCTIVE=1 chatgpt-web2api-mcp

Gated tools are hidden from list_tools and refused at call time — a client that calls a gated tool by name gets an error result rather than silent execution. Binding the SSE transport to a non-loopback address with no api_keys configured logs a prominent warning.

🔌 ZCode Hook: One-Line Bootstrap with ensure

Instead of manually starting REST and SSE in separate terminals, run a single command that reconciles both and exits — ideal for a ZCode session-start hook:

chatgpt-web2api ensure

ensure is point-in-time reconciliation, not a supervisor: it checks REST (/health) and SSE, starts whichever is missing, verifies SSE with a real MCP handshake, and exits 0 when both are ready (nonzero with a diagnostic if not). If a service dies later, re-run ensure from the next hook/session.

# Reconcile REST on 8080 + SSE on 8090 (defaults)
chatgpt-web2api ensure

# Custom ports / config (propagated to the child processes)
chatgpt-web2api ensure --rest-port 8081 --mcp-sse-port 8091 --config ~/.my-config.json

Degraded-REST policy: ensure does not restart REST immediately on degraded (Chrome alive, driver disconnected) — it polls for up to 20s first, since that may be a transient CDP reconnect. Only missing or broken trigger an immediate (re)start. This avoids a destructive Chrome bounce on transients.

🔧 Three Interfaces, One Chrome Session

# Terminal 1: Start Chrome + API
chatgpt-web2api

# Terminal 2: MCP server (SSE recommended for ZCode; stdio also supported)
chatgpt-web2api-mcp --transport sse --port 8090
# or: chatgpt-web2api-mcp             # stdio (one MCP child per client)

# Terminal 3: Any OpenAI SDK, curl, or HTTP client
curl http://localhost:8080/v1/chat/completions ...

What Makes This Different

| | ChatGPT-Web2API | chat2api | ChatGPTReversed | Official API | |---|---|---|---|---| | Anti-bot handling | ✅ Automatic (CDP) | ❌ Manual (PoW/Turnstile) | ❌ Manual | N/A | | Token extraction | ❌ None needed | ✅ Required | ✅ Required | N/A | | Project memory | ✅ Full CRUD | ❌ | ❌ | ❌ | | MCP server | ✅ 16 tools | ❌ | ❌ | ❌ | | ChatGPT memories | ✅ List/create/delete | ❌ | ❌ | ❌ | | Custom GPTs | ✅ Chat with any GPT | ❌ | ❌ | ❌ | | OpenAI SDK compat | ✅ Drop-in | ✅ | ❌ | ✅ (native) | | Streaming | ✅ SSE | ✅ | ❌ | ✅ | | Multi-turn | ✅ Auto-continue | ✅ | ❌ | ✅ | | Installation | pip install | Docker | npm | pip install openai | | Cost | Free (uses your subscription) | Free | Free | Pay-per-token |

Key insight: Other proxies fight the anti-bot system. This one uses the browser as the solution — Chrome handles Turnstile, PoW, and session management automatically.

MCP Tools in Action

An AI agent connected via MCP can:

# Create an isolated project with dedicated memory
create_project(name="Python Async Specialist", memory_scope="project_v2")

# Chat within the project (persistent memory across conversations)
chat_completion(message="What are Python coroutines?", project_id="g-p-abc123")

# Manage memories
list_memories()  # → 41 facts ChatGPT remembers
create_memory(content="Always use type hints in Python code")
delete_memory(memory_id="abc-123")

# List and manage conversations
list_conversations(limit=10)
archive_conversation(conversation_id="xyz", archive=True)

# Chat with a Custom GPT
chat_with_gpt(gpt_id="g-hkJGhxxx", message="Analyze this data")

Configuration

CLI Flags

| Flag | Default | Description | |------|---------|-------------| | --port | 8080 | API server port | | --cdp-port | 9222 | Chrome debugging port | | --headless | false | Run Chrome headless (may trigger detection) | | --log-level | INFO | DEBUG, INFO, WARNING, ERROR |

Config File (config.json)

{
  "port": 8080,
  "host": "127.0.0.1",
  "cdp_port": 9222,
  "headless": false,
  "default_model": "auto",
  "default_project_id": null,
  "tab_mode": "owned",
  "parallel_tabs": false,
  "api_keys": [],
  "request_timeout": 120
}

See [config.example.json](config.example.json) for all available keys.

MCP Session Pool (B1 — experimental, default off)

When mcp_session_pool_enabled=true, the MCP SSE server does not connect to Chrome at startup. Instead, each MCP client session gets its own owned CDPDriver/Chrome tab on first request (lazy materialization). Different sessions get different tabs, capped by pool size. This enables parallel multi-session use of one shared SSE endpoint.

Requires parallel_tabs=true + tab_mode=owned (validated at load).

{
  "parallel_tabs": true,
  "tab_mode": "owned",
  "mcp_session_pool_enabled": true,
  "mcp_session_pool_siz

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Octo-Lex](https://github.com/Octo-Lex)
- **Source:** [Octo-Lex/ChatGPT-Web2API](https://github.com/Octo-Lex/ChatGPT-Web2API)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.