Skip to main content
Glama
kev489
by kev489

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.

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 chromium

Or clone and install locally:

git clone https://github.com/kev489/gpt-tool-use.git
cd gpt-tool-use
pip install .
playwright install chromium

If 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 clone

Login 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 → your python3 absolute path (find with which 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 in launchctl list | grep gpt-tools).

  • ProgramArguments[1] — /PATH/TO/gpt_tool_use/mcp_server.py → full path to mcp_server.py

  • WorkingDirectory, StandardOutPath, StandardErrorPath — replace /PATH/TO/gpt_tool_use with 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.plist

The 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 = 120

Claude 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 8788

Useful 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

  1. 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 provide prompt_file to read the prompt from a text file.

  2. Playwright waits for the response to finish streaming (up to 8 minutes)

  3. JavaScript DOM evaluation strips citation buttons, SVGs, accordion dropdowns, and other UI artifacts

  4. The cleaned HTML is converted to markdown via markdownify

  5. Inline citation markers ([1], [2], etc.) are stripped before returning to the MCP client or writing to output_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 ChatGPT

  • prompt_file (optional) — path to a text file containing the prompt. Use either query or prompt_file, not both.

  • output_file (optional) — path where the cleaned markdown response should be saved. Parent directories are created automatically.

  • return_output (optional) — when False, the caller only gets a short saved-path summary. Defaults to True unless output_file is provided; with output_file, it defaults to False to avoid filling the caller's context with the full response.

  • output_json (optional) — when True, 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

  1. Your prompt is sent to a fresh ChatGPT chat (each call resets — no context contamination across iterations)

  2. Playwright waits up to 8 minutes for the stop button to disappear AND <img> elements to settle

  3. Image URLs are downloaded via the browser's authenticated session (signed URLs work)

  4. Files are saved to <cwd>/generated/<prefix>.png (or <prefix>-1.png, <prefix>-2.png, ... for multiple)

  5. 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 prompt

  • filename_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, default True) — when False, 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.py

MCP server entry point (stdio or HTTP transport); registers the tools

browser.py

Shared ChatGPT/Claude Playwright automation; text and ChatGPT image-gen flows

gpt_search.py

Standalone CLI wrapper (text only)

login.py

First-run helper for ChatGPT login

tests/test_mcp_server.py

Unit tests for the JSON-normalization and prompt helpers

tests/test_browser.py

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_gen saves under <server-process-cwd>/generated/. For the long-lived HTTP service, pass an absolute save_dir when 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/ -q

The 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_DIR in browser.py stores the persistent Chromium profile (ChatGPT and Claude login sessions). Gitignored. Both it and DEBUG_DIR default to the source dir; the GPT_TOOLS_HOME env var relocates them (set it when pip-installed so state doesn't land in site-packages — and set it for both gpt-tools-login and the server).

  • All paths resolve via __file__ so the server works regardless of working directory.

  • gpt_image_gen defaults to <server-process-cwd>/generated/. In HTTP mode that is the long-lived service's working directory, so callers must pass an absolute save_dir when 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.) AND alt containing "generated" — without the alt filter 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 exact ChatGPT 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 only Stop generating. Keep both selectors; missing Stop answering makes the zero-image stability heuristic close the tab after four seconds and leaves the chat at Stopped thinking.

  • Zero image URLs is not completion by itself. After Stop answering disappears, the generated <img> can still take several seconds to mount and load. With zero matching URLs, keep waiting on blank/Thinking/Generating image turns; 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-counts reveal_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 Page from the shared BrowserContext. They share login (one ChatGPT account) but are independent conversations (each navigates to ?model=auto which starts a new chat). The server caps itself at 3 concurrent tabs (MAX_CONCURRENT_CHATGPT_TABS in mcp_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_message raises on send-timeout / stream-timeout / missing-DOM instead of yielding Error: ... strings, so tool calls fail loudly rather than saving error text to output_file as 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 Enter inserts a newline instead of sending, stranding the prompt in the box. Nothing verified the send, so it surfaced 30s later as Timeout waiting for assistant message to appear — debug/debug_send.png showing 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_prompt clicks the real send button (SEND_BUTTON_SELECTORS: [data-testid="send-button"], #composer-submit-button, then aria-label and type=submit fallbacks), falls back to Enter, 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 to debug/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-textarea contenteditable — a locator found pre-swap goes stale and fill hangs on a now-hidden element. _send_prompt retries 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_file would write OpenAI's error to disk as research, violating "Failures raise" above. _detect_chatgpt_error now raises ChatGPTResponseError and _run_search_in_session retries 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 by inner_text. startswith was 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". ChatGPTRateLimitError is 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 matching innerText.

  • Tests. tests/test_mcp_server.py covers JSON normalization and prompt helpers; tests/test_browser.py covers provider routing, rate-limit detection, and browser helpers. Run python3 -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_alive flips 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 Playwright context.new_page() calls briefly unhide and foreground the Chrome window even when the process was already hidden; new_session() therefore creates tabs through Chromium's Target.createTarget protocol with background: true. Do not replace that path with new_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 --headless only 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 with EX_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 ~/Desktop to ~/Customization/gpt_tool_use as the fix. launchctl print gui/$UID/com.kchafloque.gpt-tools | grep 'last exit' is the tell.

  • Transport modes. mcp_server.py accepts --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: host 127.0.0.1, port 8788, path /mcp (FastMCP's streamable_http_path). See launchd.plist.template for auto-start.

  • Settings via mcp.settings. FastMCP host/port aren't run() args; they're set on mcp.settings before calling run(transport="streamable-http").

Available Tools

4 tools
gpt_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.

ParametersJSON Schema
NameRequiredDescriptionDefault
promptYes
filename_prefixNo
save_dirNo
embed_imagesNo

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 prompt

  • filename_prefix (optional, str): stem for saved files; falls back to a hash of the prompt

  • save_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.

ParametersJSON Schema
NameRequiredDescriptionDefault
requestsYes
embed_imagesNo

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_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 prompt

  • prompt_file (optional, str): path to a text file containing the prompt

  • output_file (optional, str): path where the cleaned markdown response should be saved

  • label (optional, str): heading used for this item in the combined response; defaults to output_file, then prompt_file, then request_<n>

  • return_output (optional, bool): overrides the batch-level return_output for this item

  • output_json (optional, bool): overrides the batch-level output_json for 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.

ParametersJSON Schema
NameRequiredDescriptionDefault
requestsYes
return_outputNo
output_jsonNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 4 tool updatesv0.1.0
    • First observedgpt_image_gen
    • First observedgpt_image_gen_batch
    • First observedgpt_search
    • First observedgpt_search_batch

TDQS

A4.7/5.0

Scored across 4 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness5/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables 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.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables 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.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables browser automation and web interaction control through Playwright, allowing Claude Code to navigate, click, fill forms, take screenshots, and manage sessions.
    155 npm
    8
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables natural language browser automation through Claude, wrapping Playwright to execute commands like navigation, clicking, form filling, and screenshots.
    5 npm
    30
    MIT