GPT Tools MCP Server
Drives ChatGPT (and Claude) through one shared Playwright browser so Codex or Claude Code can delegate web research and image generation without an API key.
gpt_search— send a research prompt to ChatGPT and get back cleaned markdown, optionally saved to a file instead of returned.JSON output mode — best-effort parse/repair of the response into normalized JSON (raw output preserved if repair fails).
gpt_search_batch— run multiple research prompts concurrently, each in its own ChatGPT tab, with per-item labels, files, and output options.gpt_image_gen— generate images from a prompt, save them to disk, and (optionally) return the image bytes inline for the caller to analyze.gpt_image_gen_batch— fan out many image prompts in parallel; failures are isolated per item.Concurrency control — capped at 3 ChatGPT tabs server-wide, with excess requests queued internally.
Context management —
return_output/embed_imagesflags let callers keep responses short when iterating.Persistent sessions — one-time ChatGPT/Claude login stored in a shared browser profile, reused across calls.
Two transports — stdio (one server per client session) or a long-lived HTTP service so multiple sessions share one browser for concurrent image gen.
Drives ChatGPT through a shared Playwright browser session, providing tools for web research (clean markdown or JSON output, optionally saved to disk) and image generation (saving generated images and returning them for the calling agent to analyze). Includes batch variants that run multiple prompts concurrently in separate ChatGPT tabs, using the user's existing ChatGPT subscription rather than an API key.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@GPT Tools MCP Serverresearch the latest AI news"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
GPT Tools MCP Server
MCP tools and a local batch interface that drive ChatGPT and Claude through one shared Playwright browser. The tools:
gpt_search— routes research queries through ChatGPT and returns clean markdown, or saves it directly to disk to keep the MCP client context light.gpt_image_gen— sends an image-gen prompt, saves the generated images to disk, and returns them so the calling agent can analyze the result.gpt_search_batch/gpt_image_gen_batch— run several prompts concurrently inside one MCP call, each in its own ChatGPT tab.provider_prompt_batch— writes raw ChatGPT or Claude responses for local structured-output pipelines such as Inloopd.
Why
Codex and Claude Code can use MCP tools. This lets either client delegate web research and image generation to ChatGPT, using your existing ChatGPT subscription instead of a separate API key.
Token efficiency (search)
When the calling agent does web research natively, it spends context and tokens on search results, page fetches, and reasoning about what it found. With this tool, ChatGPT handles that work and the caller gets back a clean result.
Design loop (image gen)
Image gen lets Codex or Claude iterate on visual designs without you having to shuttle screenshots manually. Generated images are embedded in the tool response so the caller can critique, suggest changes, and re-prompt.
The tradeoff with both is speed. Browser automation is slower than a direct API call. If you're multitasking, it doesn't matter — Claude kicks off the call and you come back to a finished result.
Related MCP server: Cloudflare Playwright MCP Example
Setup
pip install git+https://github.com/kev489/gpt-tool-use.git
playwright install chromiumOr clone and install locally:
git clone https://github.com/kev489/gpt-tool-use.git
cd gpt-tool-use
pip install .
playwright install chromiumIf you plan to run the launchd service, keep the clone outside ~/Desktop, ~/Documents, and ~/Downloads — see the TCC warning under "One-time setup".
Run once to log into ChatGPT (opens a browser window — sign in, then close the window):
gpt-tools-login # or: python login.py from a cloneLogin state for both ChatGPT and Claude is stored in chatgpt_profile/ next to the installed code (gitignored in a clone). The helper above signs into ChatGPT; the running service reveals its normally hidden browser when Claude needs its one-time sign-in. With the pip install, set GPT_TOOLS_HOME to a writable directory (e.g. ~/.gpt-tools) so the profile and debug screenshots don't land inside site-packages — set it both for the login command and in the MCP server's environment. You only need to log into each provider once per machine unless its session expires.
Then add to your Claude Code MCP config (~/.claude.json under mcpServers, or via claude mcp add):
{
"mcpServers": {
"gpt-tools": {
"command": "gpt-tools",
"args": []
}
}
}This is the stdio transport: Claude Code spawns one MCP server subprocess per session. Simple, but if you run multiple sessions at once, each spawns its own server, and they fight over the shared provider-profile lock — only one session can use image gen at a time. See "Running as a long-lived service" below for the multi-session setup.
Running as a long-lived service
If you have multiple Codex or Claude Code sessions open and want them all to use gpt_image_gen simultaneously, switch from stdio (one server per session) to HTTP (one shared server, all sessions are clients). The browser lives in the server, so there's only ever one Chromium accessing the profile.
One-time setup
1. Edit the launchd plist template. launchd.plist.template ships with placeholder paths and a generic Label — replace each one with values for your machine:
Label—com.example.gpt-tools→com.YOURNAME.gpt-tools(any reverse-DNS string; this is also the filename you'll use in step 2)ProgramArguments[0]—/PATH/TO/python3→ yourpython3absolute path (find withwhich python3). If you upgrade Python later, update this path and reload the plist (launchctl unload+launchctl load); otherwise the service silently fails to start at next login (visible only as a non-zero exit code inlaunchctl list | grep gpt-tools).ProgramArguments[1]—/PATH/TO/gpt_tool_use/mcp_server.py→ full path tomcp_server.pyWorkingDirectory,StandardOutPath,StandardErrorPath— replace/PATH/TO/gpt_tool_usewith the absolute path to this repo
TCC warning: the repo must live outside ~/Desktop, ~/Documents, and ~/Downloads. macOS blocks launchd background jobs from those folders, so the service dies at spawn with exit code 78 (EX_CONFIG) and empty logs — Python never starts. If launchctl list | grep gpt-tools shows 78, it's this or a stale Python path.
2. Install the plist. Use whatever you set for Label as the filename:
cp launchd.plist.template ~/Library/LaunchAgents/com.YOURNAME.gpt-tools.plist
launchctl load ~/Library/LaunchAgents/com.YOURNAME.gpt-tools.plistThe server will now start at login and stay running. Logs go to debug/launchd-stdout.log and debug/launchd-stderr.log inside the repo.
3. Switch your MCP config to HTTP.
Codex (~/.codex/config.toml, and any alternate CODEX_HOME such as ~/.codex-app-alt/config.toml):
[mcp_servers.gpt-tools]
url = "http://127.0.0.1:8788/mcp"
tool_timeout_sec = 1800
startup_timeout_sec = 120Claude Code:
{
"mcpServers": {
"gpt-tools": {
"type": "http",
"url": "http://127.0.0.1:8788/mcp"
}
}
}Restart the MCP client. All sessions now share the long-lived server. Multiple sessions can call gpt_image_gen / gpt_image_gen_batch at the same time.
Manual run (no launchd)
python mcp_server.py --transport http --port 8788Useful for testing the HTTP path before installing as a service. Avoid --headless for ChatGPT automation unless you have verified the account is not being stopped by browser verification.
Reverting to stdio
Unload the launchd agent (launchctl unload ~/Library/LaunchAgents/com.YOURNAME.gpt-tools.plist) and put back the original stdio config. No code changes needed — the server supports both transports.
How gpt_search works
Your query is sent directly to ChatGPT as a prompt (no system prompt — you control the output). You can pass the prompt directly as
query, or provideprompt_fileto read the prompt from a text file.Playwright waits for the response to finish streaming (up to 8 minutes)
JavaScript DOM evaluation strips citation buttons, SVGs, accordion dropdowns, and other UI artifacts
The cleaned HTML is converted to markdown via
markdownifyInline citation markers (
[1],[2], etc.) are stripped before returning to the MCP client or writing tooutput_file
With output_json=true, the tool treats JSON cleanup as a best-effort post-processing step. It does not change the prompt, and it reads the response through the raw text path instead of the markdown conversion path so JSON string escapes survive. If output_file is provided, the raw ChatGPT output is saved first; then the tool tries to extract, repair, parse, and format valid JSON. On success it overwrites the file with normalized JSON. On failure it leaves the raw output in place and reports that JSON post-processing did not succeed.
Parameters:
query(optional) — the full prompt to send to ChatGPTprompt_file(optional) — path to a text file containing the prompt. Use eitherqueryorprompt_file, not both.output_file(optional) — path where the cleaned markdown response should be saved. Parent directories are created automatically.return_output(optional) — whenFalse, the caller only gets a short saved-path summary. Defaults toTrueunlessoutput_fileis provided; withoutput_file, it defaults toFalseto avoid filling the caller's context with the full response.output_json(optional) — whenTrue, best-effort normalize the response to valid JSON after ChatGPT returns; if parsing/repair fails, leave the raw output unchanged.
Relative file paths resolve from the MCP server process working directory. Use absolute paths if the server is running as a long-lived HTTP/launchd service.
Example:
{
"prompt_file": "prompts/research.txt",
"output_file": "research/chatgpt-answer.md"
}JSON output example:
{
"query": "List three current low-cost index funds as an array of objects with ticker, fund_name, and expense_ratio.",
"output_file": "research/funds.json",
"output_json": true
}For multiple text prompts, use gpt_search_batch. Each request opens its own ChatGPT tab and runs concurrently inside one MCP call. This is the preferred way to batch text research because some MCP clients serialize multiple separate tool calls to the same server. The server runs at most 3 ChatGPT tabs at a time across all calls and sessions; larger batches queue internally. Each request also accepts an optional label, used as its heading in the combined response.
{
"requests": [
{
"prompt_file": "/absolute/path/prompts/topic-1.txt",
"output_file": "/absolute/path/outputs/topic-1.md"
},
{
"prompt_file": "/absolute/path/prompts/topic-2.txt",
"output_file": "/absolute/path/outputs/topic-2.json",
"output_json": true
}
]
}How gpt_image_gen works
Your prompt is sent to a fresh ChatGPT chat (each call resets — no context contamination across iterations)
Playwright waits up to 8 minutes for the stop button to disappear AND
<img>elements to settleImage URLs are downloaded via the browser's authenticated session (signed URLs work)
Files are saved to
<cwd>/generated/<prefix>.png(or<prefix>-1.png,<prefix>-2.png, ... for multiple)The tool returns a text summary with paths, plus (by default) the image bytes inline so Claude can see them
Concurrent calls are supported. All tools share a single Chromium context held in module state; each individual request gets its own page (= its own fresh ChatGPT tab/chat). The server caps itself at 3 concurrent ChatGPT tabs across all calls and sessions; anything beyond that queues internally.
To run multiple image-gen prompts in parallel, use gpt_image_gen_batch. Some MCP clients serialize several separate gpt_image_gen calls, but a batch call fans out internally with asyncio.gather, running up to 3 tabs at a time and queuing the rest. Pass requests=[{prompt, filename_prefix?, save_dir?}, ...]. Account-level rate limits may apply at high concurrency.
If ChatGPT or Claude shows a "Too many requests"/usage-limit modal, the browser automation saves a debug screenshot under debug/, clicks "Got it" (with OK/Dismiss fallbacks), and continues waiting for the response. It raises ChatGPTRateLimitError only if the dialog cannot be dismissed, persists after dismissal, or no usable response arrives afterward. Batch tools isolate the affected item.
Parameters:
prompt(required) — the full image-gen promptfilename_prefix(optional) — descriptive stem for saved files. Falls back to a hash if omitted.save_dir(optional) — overrides the default<cwd>/generated/embed_images(optional, defaultTrue) — whenFalse, the caller only gets the paths back. Use this during long iteration loops where embedded image bytes would flood the caller's context.
Files
File | Purpose |
| MCP server entry point (stdio or HTTP transport); registers the tools |
| Shared ChatGPT/Claude Playwright automation; text and ChatGPT image-gen flows |
| Standalone CLI wrapper (text only) |
| First-run helper for ChatGPT login |
| Unit tests for the JSON-normalization and prompt helpers |
| Unit tests for provider routing, rate-limit detection, and browser helpers |
Notes
The
chatgpt_profile/directory stores both provider sessions. It's gitignored — you need to log into ChatGPT and Claude once per machine.On macOS the browser launches minimized, runs headed for provider compatibility, and stays hidden for text/provider calls. Tabs are created through Chromium's background-target API because Playwright's ordinary
new_page()briefly foregrounds a hidden Chrome window. Manual login reveals and unminimizes it. Image generation temporarily makes it visible without making it frontmost—fully hiding the process suspends ChatGPT's image renderer—then hides it again when the final concurrent image call finishes.Without
save_dir,gpt_image_gensaves under<server-process-cwd>/generated/. For the long-lived HTTP service, pass an absolutesave_dirwhen files must land in a particular client project.Failures raise: send timeouts, stream timeouts, and rate-limit dead ends surface as tool-call errors (with a debug screenshot path under
debug/) instead of error text masquerading as a response.
Development
pip install -e ".[dev]"
python3 -m pytest tests/ -qThe tests cover pure helpers plus provider routing and rate-limit detection. Live browser UI flows still require verification against real ChatGPT and Claude.
Implementation notes (for maintainers)
The non-obvious mechanics and the failure modes that were hit for real. Rules and the live service wiring for the reference machine are in AGENTS.md.
USER_DATA_DIRinbrowser.pystores the persistent Chromium profile (ChatGPT and Claude login sessions). Gitignored. Both it andDEBUG_DIRdefault to the source dir; theGPT_TOOLS_HOMEenv var relocates them (set it when pip-installed so state doesn't land in site-packages — and set it for bothgpt-tools-loginand the server).All paths resolve via
__file__so the server works regardless of working directory.gpt_image_gendefaults to<server-process-cwd>/generated/. In HTTP mode that is the long-lived service's working directory, so callers must pass an absolutesave_dirwhen output belongs in a specific client project.Image download uses
page.request.get()(not raw httpx) so OpenAI-signed image URLs carry the browser session's cookies.Image-gen completion heuristic. Stop button gone AND the URL count is stable across two polls. The image search runs against
<main>(excludes sidebar/library) and requires both an OpenAI image-host URL pattern (backend-api/estuary/content,oaiusercontent.com, etc.) ANDaltcontaining "generated" — without thealtfilter we picked up stray library/sidebar thumbnails.Image-gen response startup can be slow. Allow up to 120 seconds for the first assistant turn to appear before declaring a send timeout. Image turns may use classic
[data-message-author-role="assistant"]markup or the current[data-turn="assistant"]wrapper, so_chatgpt_assistant_turn_count()supports both; the exactChatGPT said:heading remains a fallback. Debug screenshots use their own 5-second timeout so a wedged renderer cannot mask the underlying image-generation error.Current image-gen streaming control. ChatGPT labels the active-generation button
Stop answering, not onlyStop generating. Keep both selectors; missingStop answeringmakes the zero-image stability heuristic close the tab after four seconds and leaves the chat atStopped thinking.Zero image URLs is not completion by itself. After
Stop answeringdisappears, the generated<img>can still take several seconds to mount and load. With zero matching URLs, keep waiting on blank/Thinking/Generating imageturns; finish without an image only when_image_text_is_terminal_without_urls()sees a real terminal text response such as a refusal.Image rendering needs a visible macOS window. Hiding the entire Chrome-for-Testing process suspends ChatGPT's image workflow even though text calls continue to work.
_run_image_in_session()reference-countsreveal_for_rendering()/hide_after_rendering(): image calls make the service browser visible without making it frontmost, so it stays behind the user's active app, then hide it after the final concurrent image call finishes.Parallelism. Multiple concurrent tool calls each get their own
Pagefrom the sharedBrowserContext. They share login (one ChatGPT account) but are independent conversations (each navigates to?model=autowhich starts a new chat). The server caps itself at 3 concurrent tabs (MAX_CONCURRENT_CHATGPT_TABSinmcp_server.py, one lazily created module-level semaphore shared by all tools); excess requests queue. Account-level rate limits may still apply under sustained load.Failures raise.
stream_messageraises on send-timeout / stream-timeout / missing-DOM instead of yieldingError: ...strings, so tool calls fail loudly rather than saving error text tooutput_fileas if it were the answer. Both text and image streaming have an overall deadline (480s default).Enter alone does not reliably submit the composer. chatgpt.com has shipped composer states where
Enterinserts a newline instead of sending, stranding the prompt in the box. Nothing verified the send, so it surfaced 30s later asTimeout waiting for assistant message to appear—debug/debug_send.pngshowing text still in the composer with the submit button enabled is the tell, and it looks nothing like a login/Cloudflare failure. Bit for real 2026-08-22._submit_promptclicks the real send button (SEND_BUTTON_SELECTORS:[data-testid="send-button"],#composer-submit-button, thenaria-labelandtype=submitfallbacks), falls back toEnter, and in both paths confirms the composer emptied before returning. That empty-composer check is the only thing distinguishing a sent prompt from a stranded one — keep it when the selectors inevitably need updating. Failed submits screenshot todebug/debug_submit_failed.png; 3 attempts total.Prompt-input hydration race. Before React hydrates, chatgpt.com renders a plain fallback
<textarea placeholder="Ask anything">that gets swapped for the real#prompt-textareacontenteditable — a locator found pre-swap goes stale andfillhangs on a now-hidden element._send_promptretries up to 3 times with short per-action timeouts, re-finding the locator each attempt.ChatGPT's own error text must never be returned as the answer — and the detector must match the WHOLE message. ChatGPT intermittently replies with "Something went wrong. If this issue persists…" as the assistant message; that string used to pass straight back, so a caller with
output_filewould write OpenAI's error to disk as research, violating "Failures raise" above._detect_chatgpt_errornow raisesChatGPTResponseErrorand_run_search_in_sessionretries once in a fresh session (the errored tab usually stays broken; a new tab is a new conversation), raising only if it fails twice. The detector requires the normalized message to equal a known error string, tolerating trailing punctuation and a Retry/Regenerate affordance picked up byinner_text.startswithwas tried and is wrong: it hard-failed a valid answer opening with "There was an error generating a response. Users typically see it when…" — strictly worse than the bug it fixed. A real error has nothing after it; a real answer keeps going. Err toward passing text through, and assume any new matcher here is guilty until tested against an answer that discusses the error — same false-positive class as the rate-limit detector below. Added 2026-08-22.Rate-limit modal handling. ChatGPT and Claude rate-limit modals (including "Too many requests" and provider limit variants) are detected by phrase-matching, screenshotted to
debug/, and dismissed via "Got it"/"OK"/"Dismiss".ChatGPTRateLimitErroris raised only if dismissal fails or no usable response follows. The detector skips both providers' assistant messages and composers so a response discussing HTTP 429s is not mistaken for a modal, and it requires the candidate element to be visibly rendered because dismissed dialogs can remain in the DOM with matchinginnerText.Tests.
tests/test_mcp_server.pycovers JSON normalization and prompt helpers;tests/test_browser.pycovers provider routing, rate-limit detection, and browser helpers. Runpython3 -m pytest tests/ -q. Live browser UI flows still require manual verification against both providers.Browser lifecycle. First call launches Chromium and pays the startup cost. Subsequent calls reuse the same browser. If the user closes the browser window manually,
is_aliveflips false and the next call re-launches.Browser launches headed (
headless=False) because ChatGPT blocks headless automation, with--start-minimized, then immediately hides its exact macOS process. On macOS, normal Playwrightcontext.new_page()calls briefly unhide and foreground the Chrome window even when the process was already hidden;new_session()therefore creates tabs through Chromium'sTarget.createTargetprotocol withbackground: true. Do not replace that path withnew_page()for background service calls. Revealing the process also unminimizes its window for image rendering or manual provider login. If a provider login expires, the service reveals the browser for manual authentication and hides it again once the composer appears. Pass--headlessonly for explicit diagnostics; Cloudflare can serve a "Verify you are human" interstitial in that mode.Install location: never under
~/Desktop,~/Documents, or~/Downloads. macOS TCC blocks launchd background jobs from those folders — launchd can't chdir/open logs there, so the service dies at spawn withEX_CONFIG(78) and empty logs (Python never starts). Bit for real on 2026-07-07 after an OS update reset TCC grants; the repo moved from~/Desktopto~/Customization/gpt_tool_useas the fix.launchctl print gui/$UID/com.kchafloque.gpt-tools | grep 'last exit'is the tell.Transport modes.
mcp_server.pyaccepts--transport stdio(default, one server per MCP client session) or--transport http(long-lived server shared by Codex, Claude Code, and local pipeline clients). HTTP mode is the only way to run image gen concurrently across multiple sessions, because the persistent Chromium profile only allows one accessing process at a time. With stdio, two sessions = two server processes = profile lock conflict. With HTTP, one server process owns the profile; all sessions go through it. Defaults: host127.0.0.1, port8788, path/mcp(FastMCP'sstreamable_http_path). Seelaunchd.plist.templatefor auto-start.Settings via
mcp.settings. FastMCP host/port aren'trun()args; they're set onmcp.settingsbefore callingrun(transport="streamable-http").
Available Tools
4 toolsgpt_image_genA
Generate one or more images via ChatGPT image gen and save them to disk.
The prompt is sent directly to ChatGPT — phrase it as an image-generation request and let the prompt itself specify how many images you want.
For running multiple distinct prompts in parallel, use gpt_image_gen_batch instead — it fans out concurrently inside a single MCP call. Issuing two gpt_image_gen calls from one Claude message executes serially because the MCP harness serializes calls to the same server.
Args:
prompt: Full image-gen prompt sent directly to ChatGPT.
filename_prefix: Stem for saved files. Single image saves as <prefix>.<ext>; multiple images get numbered suffixes (<prefix>-1.<ext>, <prefix>-2.<ext>, ...). Defaults to a hash of the prompt.
save_dir: Where to save images. Defaults to <cwd>/generated/ (created if missing).
embed_images: When True, the saved images are returned in the tool response so Claude can analyze them. Set False during long iteration loops to keep context light — paths are still returned.
Returns a list of MCP content blocks: a text summary plus, if embed_images is True, the image blobs.
| Name | Required | Description | Default |
|---|---|---|---|
| prompt | Yes | ||
| filename_prefix | No | ||
| save_dir | No | ||
| embed_images | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses behavioral traits: serialization behavior, default save directory, naming conventions for single vs. multiple images, and the effect of embed_images on the response. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with separate paragraphs for the core function, usage notes, and parameter details. It is reasonably concise, though the details about naming and defaults could be slightly more streamlined.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero schema coverage, no output schema, and no annotations, the description covers the return format (list of MCP content blocks, text summary, optional images) and key defaults. It lacks explicit output schema, but the qualitative description suffices for the agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must add meaning for all parameters. It explains prompt, filename_prefix (default naming), save_dir (default location), and embed_images (response impact). This fully compensates for the lack of schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Generate one or more images via ChatGPT image gen and save them to disk.' It uses a specific verb and resource, and distinguishes from the sibling tool gpt_image_gen_batch which handles parallel distinct prompts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use this tool versus gpt_image_gen_batch (parallel runs), and notes that sequential calls via the MCP harness are serial. However, it does not explicitly contrast with the search siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gpt_image_gen_batchA
Run multiple image-gen prompts in parallel via ChatGPT image gen.
Each request opens its own ChatGPT tab and runs concurrently with the others. This is how you actually parallelize image gen — issuing multiple separate gpt_image_gen tool calls from a single Claude message gets serialized by the MCP harness, but a single gpt_image_gen_batch call fans out internally and bypasses that.
Each item in requests is a dict with keys:
prompt(required, str): the full image-gen promptfilename_prefix(optional, str): stem for saved files; falls back to a hash of the promptsave_dir(optional, str): override save location for this item; defaults to<cwd>/generated/
embed_images is batch-level — applies to all items. Set False during long iteration loops to keep Claude's context light.
All items run concurrently, capped at 3 ChatGPT tabs at a time server-wide; larger batches queue internally. If one fails, the others still complete; failed items show up in the response as [<prefix>] FAILED: <error>.
Account-level rate limits may still apply under sustained concurrency.
Returns a list of MCP content blocks: per-item text summaries plus, if embed_images is True, the image blobs in order.
| Name | Required | Description | Default |
|---|---|---|---|
| requests | Yes | ||
| embed_images | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses key behaviors: concurrent execution capped at 3 tabs, queueing for larger batches, error handling (one fails, others complete), rate limit caveat, and batch-level embed_images behavior. No annotations provided, but description fully compensates.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is informative without being overly verbose. Each sentence adds value, though slightly longer than necessary. Front-loaded with purpose and key usage note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and two parameters, the description covers all necessary context: parallel execution details, error behavior, return format (list of MCP content blocks with text and optionally images), and rate limits.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Adds rich meaning beyond schema: details each key in requests (prompt, filename_prefix, save_dir) and the batch-level embed_images flag. Schema coverage was 0%, so description carries full burden and executes well.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Run multiple image-gen prompts in parallel via ChatGPT image gen.' It distinguishes from sibling gpt_image_gen by explaining parallelization advantage over serialized calls.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use this tool over alternatives: 'This is how you actually parallelize image gen... issuing multiple separate gpt_image_gen tool calls... gets serialized... gpt_image_gen_batch fans out internally.' Also advises setting embed_images to false during long loops.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gpt_searchA
Search the web or research a topic using ChatGPT.
Provide either query or prompt_file. The prompt is sent directly to ChatGPT.
Args:
query: Full prompt to send to ChatGPT.
prompt_file: Path to a text file containing the prompt. Relative paths resolve from the MCP server process working directory.
output_file: Optional path where the cleaned markdown response should be saved. Parent directories are created if needed.
return_output: When True, return the full response to the MCP client. When False, return only a short saved-path summary. Defaults to True unless output_file is provided, in which case it defaults to False to keep client context light.
output_json: When True, try to parse/repair the response as JSON after ChatGPT returns. If output_file is provided, raw output is saved first and overwritten only when JSON post-processing succeeds. If post-processing fails, raw output is left in place.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | ||
| prompt_file | No | ||
| output_file | No | ||
| return_output | No | ||
| output_json | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavioral traits: it sends the prompt to ChatGPT, handles file output with directory creation, details the return_output default logic, and explains output_json post-processing including failure recovery. This is comprehensive and leaves no ambiguity.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with an Args section and clear parameter explanations. It is informative without being verbose, though some redundancy (e.g., repeating 'default') could be trimmed. Overall, it effectively communicates key details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (5 parameters, multiple behaviors) and the presence of an output schema (not shown but indicated), the description covers all necessary aspects: parameter usage, alternatives, defaults, and error handling. It is complete enough for an AI agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 0% description coverage, so the description carries full burden. It provides detailed semantics for all five parameters: query vs. prompt_file exclusivity, output_file with directory creation, return_output defaulting based on output_file, and output_json with fallback behavior. This significantly enhances schema understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Search the web or research a topic using ChatGPT.' It identifies the tool's core function and the two input options (query or prompt_file). However, it does not explicitly differentiate from sibling tools like gpt_image_gen or gpt_search_batch, though the purpose is distinct enough.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on parameter usage: 'Provide either `query` or `prompt_file`.' It also explains default behaviors for return_output and output_json. It lacks explicit when-to-use vs. alternatives, but the context from sibling names and the detailed parameter logic compensates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
gpt_search_batchA
Run multiple ChatGPT search/research prompts concurrently.
Each request opens its own ChatGPT tab and runs concurrently with the others. This is the text equivalent of gpt_image_gen_batch. The server runs at most 3 ChatGPT tabs at a time across all calls and sessions; larger batches queue internally.
Each item in requests is a dict with keys:
query(optional, str): the full promptprompt_file(optional, str): path to a text file containing the promptoutput_file(optional, str): path where the cleaned markdown response should be savedlabel(optional, str): heading used for this item in the combined response; defaults tooutput_file, thenprompt_file, thenrequest_<n>return_output(optional, bool): overrides the batch-levelreturn_outputfor this itemoutput_json(optional, bool): overrides the batch-leveloutput_jsonfor this item
Provide either query or prompt_file for each item. Relative file paths resolve from the MCP server process working directory.
return_output is batch-level unless overridden per item. When omitted, each item defaults to returning the full output only if it has no output_file.
output_json is batch-level unless overridden per item. When enabled, the response is parsed/repaired after ChatGPT returns. For file outputs, raw output is saved first and overwritten only when JSON post-processing succeeds.
Returns a markdown summary. If outputs are returned, they are grouped under per-request headings.
| Name | Required | Description | Default |
|---|---|---|---|
| requests | Yes | ||
| return_output | No | ||
| output_json | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It thoroughly discloses concurrency behavior, internal queuing, server limits, file path resolution, output handling, and JSON post-processing with potential overwriting, providing comprehensive behavioral transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the primary purpose and is dense with necessary information, but it is somewhat lengthy. Every sentence adds value, but slight trimming could improve conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (batch processing, multiple optional overrides, concurrency limits, file handling), the description covers all essential aspects. The output schema exists but the description still explains the return format (markdown summary with per-request headings), leaving no obvious gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 0% description coverage, but the description fully compensates by explaining each key in the requests array (query, prompt_file, output_file, label, return_output, output_json) with defaults and behavior, and also clarifies batch-level overrides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Run multiple ChatGPT search/research prompts concurrently,' specifying the verb, resource, and concurrency aspect, and distinguishes from siblings by mentioning gpt_image_gen_batch as the image equivalent and implying it's the batch version of gpt_search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use this tool (for concurrent batch requests) and notes the server limit of 3 tabs. It indirectly suggests using gpt_search for single queries by naming the sibling, but does not explicitly state when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
gpt_image_gen - First observed
gpt_image_gen_batch - First observed
gpt_search - First observed
gpt_search_batch
TDQS
Scored across 4 tools
The four tools are clearly separated into image generation (gpt_image_gen, gpt_image_gen_batch) and search (gpt_search, gpt_search_batch), with distinct purposes explained in detail. The batch variants explicitly state when to use them instead of the single variants, leaving no ambiguity.
All tool names follow a consistent pattern: the prefix 'gpt_' followed by a descriptive task ('image_gen' or 'search') and an optional '_batch' for concurrent execution. This makes naming predictable and intuitive.
With only 4 tools, the server is well-scoped for its two core functionalities (image generation and search), each offered in single and batch variants. The count is appropriate and avoids unnecessary complexity.
The tool surface covers the primary operations for image generation and search/research, including parallel execution via batch variants. There are no obvious missing tools for the server's stated purpose of interacting with ChatGPT for these tasks.
Maintenance
Related MCP Connectors
Let Claude and ChatGPT publish real websites — iterate in previews, keep the good one.
Web search, browser automation, scraping, crawling and CAPTCHA solving for AI agents.
Screenshot, PDF and HTML-to-image rendering API so Claude and Cursor can see any web page.
Screenshot, PDF and HTML-to-image rendering API so Claude and Cursor can see any web page.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to control a browser through Playwright automation tools, allowing them to perform web tasks like navigation, typing, clicking, and taking screenshots. Deployed on Cloudflare Workers and compatible with various AI platforms including Claude Desktop and VS Code.-
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to control a web browser via Playwright on Cloudflare Workers for automated tasks like navigation, clicking, typing, and taking screenshots. It integrates with platforms like Claude Desktop and GitHub Copilot to perform web automation through a standardized toolset.-
- AlicenseNot gradedqualityCmaintenanceEnables browser automation and web interaction control through Playwright, allowing Claude Code to navigate, click, fill forms, take screenshots, and manage sessions.155 npm8MIT
- AlicenseNot gradedqualityCmaintenanceEnables natural language browser automation through Claude, wrapping Playwright to execute commands like navigation, clicking, form filling, and screenshots.5 npm30MIT