# Fotor MCP Integration ## Connection This **production release channel** package connects to the **production service** at `https://mcp.fotor.com/mcp` using Streamable HTTP. Both release channels use the production account, website, and credits. Preserve this service throughout a task and its assets. | Environment | MCP endpoint | Website target | Login handoff endpoint | | --- | --- | --- | --- | | production | `https://mcp.fotor.com/mcp` | `https://www.fotor.com/` | `https://api.fotor.com/api/user/mcp/browser-handoff` | Package checks cover files, references, and configuration. Verify installation, MCP authorization and calls, website login, credit links, uploads, and media execution separately in the selected host and environment. A release or model query does not establish successful website login or completed media results. Use the runtime routing, authentication, and website flow below. Keep credentials in the client's supported store and report actual outcomes for the requested operation. ## Runtime workflow ### Route the request | Intent | Action | | --- | --- | | Connect to Fotor, connect to the Fotor website, or connect and open Fotor | Authenticate MCP, then follow the website flow below | | Connect to Fotor MCP or check MCP connectivity without a website request; explicitly keep the website closed | Perform the requested MCP check; omit the website handoff | | Introduce features or query models | Answer from current tool descriptions or model queries; omit website navigation unless also requested | | The user asks for their own Fotor credit balance | Follow the [credits workflow](credits.md); ordinary connection does not query balance | Equivalent wording in other languages follows the same routing. Uploads, image processing, and media generation alone do not request website access. Ordinary website connection requests authorize the final visible navigation; they do not authorize media submissions. ### Authenticate MCP Authentication belongs to the native host client except in DeepSeek Harness, where the separately installed bridge owns OAuth and credential storage. Follow the packaged [authentication guide](authentication.md) for that owner and its status, authorization and recovery entrypoints. The shared gates below still apply; DeepSeek Harness's standalone authorization client must finish before its stdio proxy starts. 1. Confirm the installed endpoint and enabled state. Both release channels require the production MCP endpoint in the Connection section. If the package or a host override selects another service, stop and explain that the installation/configuration needs updating through the host's controls; do not contact that service, silently change endpoints, or migrate its credentials. If Fotor tools are absent or a call fails authentication, diagnose native authorization before choosing a reload/new-chat fallback. Follow the packaged [authentication guidance](authentication.md) for native status, permission recovery, and login routes, including when Fotor remote tools are unavailable. Reuse usable production credentials through the host's supported MCP client. A confirmed missing/invalid authorization enters OAuth; unknown status remains inconclusive and uses the explicit choice in that workflow after bounded diagnosis. If the user forbids all browser use and authentication is needed, explain that requirement and stop. Otherwise, start OAuth only for missing/invalid credentials or explicit reauthorization, preserving existing credentials on network errors. 2. When OAuth is needed, start the documented authentication owner's supported login flow for the selected server and open its authorization URL in an external browser. Let the user complete login and consent. If external-browser automation is unavailable, explain that limitation and give the user the authorization link to open externally; keep the callback flow active. Do not silently use the in-app browser for OAuth. 3. After opening the external authorization page or supplying the manual external link, collect the [OAuth completion choice](#oauth-completion-choice). Keep the callback flow active while awaiting the answer. 4. When this request started OAuth, proceed only after an explicit continue choice and client-confirmed authorization success. If the callback is pending, explain the delay and wait within the client's login timeout. OAuth cancellation, login expiry, or denied authorization stops the flow before website handoff. A user reporting completion or a login page loading is not proof that credentials were obtained. 5. After credential reuse or successful OAuth, establish a usable connection in the client serving this request and discover the authenticated tools. Apply [bounded connection recovery](#bounded-connection-recovery) to eligible transient failures; a successful OAuth result alone does not establish tool availability. Keep credential values in the client's store, outside conversation output, files, and logs. For an MCP-only health check, call `list_models` when discovered and report its actual outcome. If a successful discovery omits it, report the unavailable probe without assuming authentication failed; uploads and the new website-login tool can remain available while generation and credits tools are disabled. A failed or incomplete discovery is a connection problem, not proof that a tool is absent. Installation and discovery alone do not establish a successful call. Do not request upload addresses, transfer files, submit media, query arbitrary tasks, or call `get_credits` or `get_website_url` for a read-only health check. ### OAuth completion choice Use the host's structured question/choice UI when available to ask whether the user has completed external login and authorization; otherwise offer the same choices conversationally. Localize the question and labels to the conversation language. For a website connection, use the Continue label and browser route from the packaged [authentication guidance](authentication.md); the shared actions below remain the same. | Choice | Next action | | --- | --- | | Signed in and authorized; continue to Fotor in the selected browser | Verify client-confirmed OAuth success, then continue the website flow. | | Not finished; keep waiting | Keep the current callback active within its timeout and wait for the user to explicitly choose to continue. | | Cancel connection | Stop this connection attempt and cancel the pending login through the client when supported. Preserve credentials already stored; cancellation does not request logout or revocation. | A preselected option, no answer, elapsed time, or a successful callback alone does not select Continue. Request `get_website_url` only after both user continuation and client success, so its short-lived ticket is not created while waiting for a choice. If structured input is unavailable, present the same choices in text and wait for an explicit reply. If the user reports an error, report the failed authorization and stop rather than treating the answer as completion. Skip this prompt when the request reuses valid credentials without starting OAuth. For an MCP-only check or another task requiring authentication, replace the first label with "Signed in and authorized; continue the requested task" and preserve the original scope; the choice does not add website navigation. ### Bounded connection recovery Apply this policy only to read-only OAuth metadata retrieval, MCP connection/tool discovery, and the `list_models` connection probe. Eligible failures are connection interruptions, request timeouts, temporary HTTP 5xx responses, and errors such as "failed to resolve OAuth metadata before using stored credentials" caused by an HTTP request failure. An OAuth-related network error does not establish invalid credentials. Read-only native authorization diagnosis shares the same retry counter and time budget. First resolve known execution restrictions through host permissions or its connection UI: follow the packaged [authentication and permission guidance](authentication.md); unchanged access restrictions are not transient retries. Other inconclusive results use the remaining limits, then the explicit unknown-state choice rather than silently entering OAuth. 1. Use one retry counter and one **90-second automatic-work budget** for the whole connection/discovery/probe sequence, starting with its first automatic request. After the initial attempt, allow at most **two retries**, waiting **2 seconds** before retry 1 and **5 seconds** before retry 2. Count automatic requests, reconnect/refresh work, and backoff waits. Pause accounting while the user completes external login, answers a connection choice, or decides a host permission request; the client's own OAuth timeout still applies. Preserve spent time and retries across stages, successful intermediate requests, OAuth completion, and refreshes. 2. Before another wait or request, check the remaining budget and cancellation state. If the remaining time cannot cover the next backoff, stop rather than shortening the delay. Cap request timeouts to the remaining budget where the host supports it. Stop at the first exhausted limit. If the host cannot interrupt an in-flight request, report any overrun and start no further work after it returns; these skill instructions cannot enforce the host's transport deadline. 3. Retain the selected environment, stored credentials, and the user's Continue / Wait / Cancel decision. Briefly report the retry number in the conversation language. Continue does not need another confirmation; Wait keeps continuation pending and Cancel ends it. This loop never restarts OAuth, repeats token exchange, logs out, or clears credentials. 4. Retry the failed read-only operation. When initialization or tool availability requires recovery, use an available host-supported refresh/reconnect in the client serving the current request, then rediscover its tools. A separate diagnostic client does not refresh the original chat. Before declaring the host unable to recover, classify native authorization using the [authentication workflow](#authenticate-mcp). Missing remote tools do not rule out a native login command or connection UI. After authorization is classified or completed, if the current host still offers no usable recovery path, report that specific limitation and the reload/new-session next step; do not invent commands, extract tokens, or create an ad hoc credential client. 5. Require successful discovery and, when `list_models` is available, a successful call before resuming the requested workflow. A catalog or saved OAuth status alone is insufficient; an empty filtered model result is a valid response. If successful discovery genuinely omits the probe, report that capability gap and retain the existing workflow for available tools. After exhaustion, report the failed stage and retries used without claiming a website connection or assuming the user must log in again. Confirmed invalid credentials, denied permissions, invalid parameters, environment mismatches, certificate-validation errors, and genuinely absent tools are not transient retries. Stop this recovery loop and explain the specific condition; use the supported authorization flow only when missing/invalid credentials or an explicit reauthorization request warrant it. User cancellation stops recovery immediately. This budget covers automatic MCP connection recovery, not website navigation, credit queries, or media execution. Keep website ticket creation and consumption, upload requests/transfers, media submissions, and task queries outside this retry loop. Their existing workflows retain their own stopping conditions; in particular, preserve uncertain submissions and the website-link replacement limit. Credit responses follow the packaged [credits workflow](credits.md). ### Connect to the website 1. Complete MCP authentication and authenticated tool discovery, using [bounded connection recovery](#bounded-connection-recovery) for eligible failures. When available, require a successful `list_models` read-only check without dumping its catalog before requesting a website link. Determine browser availability before creating the short-lived link, following the browser route in the packaged [authentication guidance](authentication.md). Otherwise prepare the manual fallback. Only a successful discovery that omits `get_website_url` establishes a missing website capability; an unavailable chat tool surface or failed discovery does not establish the service version. Report MCP and website outcomes separately, without claiming an ordinary page visit established automatic login. 2. Call `get_website_url` without arguments. Its public response contains `handoff_url` and integer `expires_in` from 0 to 600; it does not expose `target_url`. Require a usable link and remaining lifetime greater than zero. A zero lifetime is already expired: use the bounded replacement rule below. Missing, malformed, or out-of-range fields are a handoff failure. The server configures and validates the destination; before navigation, the plugin can check only the handoff endpoint against the [connection table](#connection), not the hidden target. Never decode the ticket, rewrite its URL, or change environments to recover a mismatch. 3. Follow [one-time browser links](#one-time-browser-links) for the returned `handoff_url`, using the actual remaining lifetime. This final visible navigation is the requested website visit and consumes the ticket. 4. Inspect the resulting page in that same browser session. Compare its HTTPS origin with the selected website in the connection table and verify authenticated state before reporting the website connected. A valid handoff endpoint alone does not prove the hidden redirect target is correct. On a different environment or unexpected origin, stop further interaction and report the mismatch; do not follow it as a fallback. A link, a generic page, or a login/error screen is insufficient. If state is unclear, ask the user to confirm it. Website failure does not justify resetting working MCP credentials. 5. Introduce the available main features after the connection attempt and report partial outcomes accurately. Do not automatically list models or query credits; website login works independently of balance and billing-account registration. ### One-time browser links Apply this section only to `get_website_url.handoff_url`. This plugin's selected website connection flow uses one final visible navigation in the browser specified by the packaged [authentication guidance](authentication.md). The service description instead prescribes a user-clicked link to prevent early consumption; the plugin's selected browser action is the intended final visit, never a pre-opening check. Honor an explicit user preference for manual delivery and any host restriction; use the manual fallback when direct navigation is unavailable. - Parse the returned URL before use. It must have the exact HTTPS origin and path of the selected environment's [login handoff endpoint](#connection), no username/password or fragment, and one nonempty `code` query parameter only. Check URL components rather than hostname substrings. Reject an unknown environment or mismatch without fetching the address, rewriting the host, or switching services. - Immediately navigate once in the selected visible host browser. Do not first fetch, preview, probe, or open the ticket in a hidden tab. After navigation, treat it as consumed and never offer it as a reusable login link. - When the required browser is unavailable, explain the limitation and present the complete unused link with its returned lifetime for immediate manual opening. Manual completion stays pending until confirmed. Honor explicit user restrictions on browsing or link disclosure; do not silently switch browsers. - If a link expired or a failed navigation may have consumed it, resolve the cause or establish a manual route before requesting one replacement for the still-requested action. Stop after a repeated failure. Record outcomes without credentials, authorization codes, or one-time URLs in repository files or diagnostic logs. ### Discover capabilities and choose a model Inspect the connected service's actual tool descriptions and input schemas. The table below describes the current contract, not a fixed tool-count requirement. If a required operation is absent, explain the missing capability and provide only a clearly labeled preparation brief when useful. | Tool | Purpose and required decision | | --- | --- | | `list_models` | Discover model IDs and modes; query a selected ID for its supported parameters and defaults | | `get_upload_url` | Obtain a signed PUT address; follow the [upload workflow](media-upload.md) to actually transfer local media | | `submit_image_task` | Generate without reference images; edit/reference with `image_urls`; a successful call may consume Fotor credits | | `submit_image_upscale_task` | Upscale `image_url` with an optional positive ratio; no model ID or prompt; a successful call may consume Fotor credits | | `submit_background_removal_task` | Remove the background from `image_url`; no model ID or prompt; a successful call may consume Fotor credits | | `submit_text_to_video_task` | Generate video from a text prompt; a successful call may consume Fotor credits | | `submit_first_frame_video_task` | Animate `image_url` as the first frame; a successful call may consume Fotor credits | | `submit_first_last_frame_video_task` | Use ordered `start_image_url` and `end_image_url`; a successful call may consume Fotor credits | | `submit_multimodal_video_task` | Use supported image, video, and/or audio references; a successful call may consume Fotor credits | | `submit_soundtrack_task` | Compose a separate MP3 from exactly one source image or video | | `submit_audio_track_task` | Generate a new track from reference audio | | `submit_song_edit_task` | Extend, remix or edit a section of a song | | `submit_speech_task` | Generate speech or a scripted podcast with built-in voices | | `submit_audio_separation_task` | Separate existing vocals and accompaniment into a ZIP | | `get_task` | Look up one known image, video or audio task using existing credentials | | `get_website_url` | Obtain an environment-bound, one-time website login link for the verified MCP user | | `get_credits` | Query only the authenticated user's own balance; follow the [balance lookup](credits.md#query-the-selected-account) | For model-based generation/editing, start with `list_models`, optionally filtering by `media_type` and `mode`. Uploads and fixed image-processing operations use their own tool contracts without model selection. Filters combine with AND; an empty filtered result is not evidence of a failed connection. Then query `list_models` with the chosen `model_id` before submitting. Model IDs, available modes, and catalog sizes can change; an unknown or retired ID requires a new selection, not an invented replacement. For standalone audio, read the selected model’s `operations[]`. Use its tool, selector, required parameters, result format and synchronous behavior. Only soundtrack creation accepts a model ID. For images and videos, use the returned resolutions, aspect ratios, qualities, duration values/ranges, reference types, and defaults. Honor an explicit model or output preference; explain an unsupported constraint before changing it. When no preference is given, choose a suitable supported model and use its reported defaults. `duration=0` selects `default_duration`; duration ranges are inclusive integer seconds, while a list permits only its listed values. `explicit_aspect_ratio_modes` requires a concrete supported ratio instead of `auto`; for multimodal references this condition applies when images are supplied without videos. ### Inputs and native capabilities Generation references and image-processing inputs must be accessible HTTPS URLs. For local files and client-accessible attachments, follow the shared [media upload workflow](media-upload.md). Use the successful upload's `file_url`, never its signed `upload_url` or a filesystem path, as a task input. Preserve the selected environment and ordered references, including first/last frames. Storage acceptance does not establish the model's input compatibility. Use native model resolutions and supported output options for generation. Explicit image upscaling uses `submit_image_upscale_task`; its current positive, finite ratio defaults to 2 and its output width and height are capped at 2048 pixels. Background removal uses `submit_background_removal_task` for a transparent image. Neither fixed operation requires a model ID or prompt. These tools do not establish masks, video upscaling, timeline/range editing, or dubbing. Run a sequence of operations only when requested, waiting for each required result before the next submission. ### Credit consumption before submission Every discovered tool whose name matches `submit_*_task` may consume Fotor credits when its call succeeds. This applies to all image, video and audio submissions, including future tools matching that name pattern; discovery and the actual schema still determine whether a tool can be called. Before submitting, briefly tell the user in their conversation language that the successful call may consume Fotor credits. Continue under an already explicit task request without adding a blanket confirmation step. Preserve the user's budget, requested scope, and host approval requirements. For an explicitly requested sequence, one notice before the first submission may cover every named step; disclose newly added steps or scope changes before submitting them. Do not apply this notice to model discovery, balance queries, uploads or task polling, and do not add a preliminary balance query to a media request. Do not invent a price, guarantee a charge, or equate accepted submission with completed media. Preserve zero and unknown `credits_increment` values and never add repeated observations as separate charges. Uncertain submissions still follow the no-automatic-resubmission rule below. ### Submission, recovery, and results For an explicit `insufficient_credits` submission error, follow [insufficient credits during media submission](credits.md#insufficient-credits-during-media-submission). This applies to image generation, fixed image processing, and every video and audio submission mode; it does not make balance queries a prerequisite. 1. Submit once. Retain the returned task ID, environment, selected operation and expected output format. Image and video calls normally return an accepted task. Audio may already have completed. Inspect both the MCP error flag and the structured content, including on `isError=true`. Retain any known task ID, safe `failure_reason` and reported credit value. 2. On completion, deliver the actual `result_url` immediately without polling. Prefer a host-supported preview for playable media. Offer an audio separation ZIP as a download. If the URL is absent, report completion without an available link. Describe quality only after inspecting the artifact. 3. For an accepted or processing task, query the same ID with `get_task`. Each call performs one lookup. Within the task budget, wait between checks. The query can omit the model and result format, so retain the originating operation. Stop on completion, `failed`, `timed_out` or `cancelled`. Report unknown or conflicting state as uncertain. A safe failure summary may be generic. 4. A transport timeout, lost response or `submission_uncertain` may follow an accepted, chargeable submission. Recover only by looking up a known ID. Without an ID, report the uncertain outcome and stop. Never automatically resubmit. On a lookup error or polling limit, preserve the ID and last observed state. `credits_increment` reports the increment returned by that particular submission or query, not a balance or a price quote. Preserve `0` as zero and `null` as unknown. Do not add submission and polling values together as if each observation were a new charge. Report missing or inconsistent values without estimating usage. Task lookup is scoped to the selected API key's Business. Another Business cannot retrieve its results, and a task ID must not be moved between environments to recover a failure. Task lookup uses existing credentials. If none are usable, report `credentials_unavailable`. It creates no developer, key or task and consumes no credits. Use `list_models` for connection checks.