FoxyLab

Developers / MCP

Give your agent a film studio

FoxyLab runs a remote MCP server. Connect your agent, and it can make a film from an ask or a site, follow each stage, give notes and take the files.

Serverhttps://api.foxylab.ai/mcp/
  1. 1

    Your agent

    Claude Code, Claude Desktop, Cursor or your own

  2. 2

    api.foxylab.ai

    Streamable HTTP. OAuth or an API key

  3. 3

    The studio

    The seven stages, then your files

Transport
Streamable HTTP
Sign-in
OAuth, or an API key in the Authorization header
Tools
6 tools and 1 resource
Usage
The same usage limit as the studio. See Pricing

Authorization

The server takes two kinds of sign-in. Both give the agent the same films and the same usage limit as your team in the studio.

Sign in with OAuth

For people at a desk

The client opens your browser. You sign in, pick the team and the scopes, and allow access. The client gets a token and renews it on its own. Clients find the sign-in page at /.well-known/oauth-protected-resource.

An API key in a header

For servers, CI and agents without a browser

Make a key on the API keys page. Send it as Authorization: Bearer <key>. It is the same key as for the API.

Claude Code

Run the command in a terminal. Put your key in place of <key>.

To sign in with OAuth, leave out --header. Then run /mcp in Claude Code, pick foxylab and sign in.

With an API key
claude mcp add --transport http foxylab https://api.foxylab.ai/mcp/ --header "Authorization: Bearer <key>"
With OAuth
claude mcp add --transport http foxylab https://api.foxylab.ai/mcp/

Claude Desktop

Claude Desktop connects with OAuth, so you do not need a key.

  1. 1Open Settings, then Connectors.
  2. 2Select Add custom connector.
  3. 3Type FoxyLab as the name and paste https://api.foxylab.ai/mcp/ as the URL.
  4. 4Select Connect. Sign in to FoxyLab in the browser.
  5. 5Pick the team and the scopes, then allow access.

Cursor

Add the server to ~/.cursor/mcp.json for all projects, or to .cursor/mcp.json for one project. Put your key in place of <key>.

To sign in with OAuth, leave out headers. Cursor opens the sign-in page when the agent first uses a tool.

~/.cursor/mcp.json
{
  "mcpServers": {
    "foxylab": {
      "url": "https://api.foxylab.ai/mcp/",
      "headers": { "Authorization": "Bearer <key>" }
    }
  }
}

Other clients

Any client that speaks Streamable HTTP can connect. Most clients read a config like this one. The key names can be different in your client, so check its docs.

URL
https://api.foxylab.ai/mcp/
Transport
Streamable HTTP
Header
Authorization: Bearer <key>
mcp.json
{
  "mcpServers": {
    "foxylab": {
      "type": "http",
      "url": "https://api.foxylab.ai/mcp/",
      "headers": { "Authorization": "Bearer <key>" }
    }
  }
}

Tools

The server has 6 tools. Each tool needs one scope. The agent sees the same names, texts and input schemas as here.

create_film

scope films:write

Starts a new film from a one-line ask, a site or both.

Input

promptstring
The ask in plain words, for example a one-line brief. Send prompt, url or both.
urlstring
A site for the studio to read. It takes the product, the colours, the fonts and the tone from it.
formatsstring[]
The sizes to make: 9:16, 4:5, 1:1, 16:9. The default is 9:16.
languagestring
The film's language, for example Ukrainian. The default is English.
voicestring
A voice name such as sulafat, a few words such as warm, slow, or none for music only. Without it, the studio picks a voice for the brand.
voice_modestring
Where the voice speaks. auto, the default: the studio decides whether a narrator helps this film, and where. parts: it stops where the picture and the music say more. full: every shot is spoken. none: no narrator.
musicstring
auto, the default: the studio decides whether the film needs a music bed, and picks it from free stock. on: always a bed. off: no music. A CC BY track comes with a credit line for the post; renders return it.
music_levelstring
How far the music sits under the voice: low, normal (the default) or high. The voice always stays at least 15 dB above it.
brand_kitstring
The id of a brand kit from your studio, for example kit_mossly. It wins over what the studio reads from url.

Returns The film id, the status and the stage it is in.

get_film

scope films:read

Gets the film, its current version and the status of each stage.

Input

film_idstringrequired
The film, for example film_8Kq2xV.

Returns The title, the status, the seven stages and the time left.

add_note

scope films:write

Gives the film a note in plain words and makes a new version.

Input

film_idstringrequired
The film, for example film_8Kq2xV.
textstringrequired
The note in plain words, as you write it in the studio chat.
refsobject[]
Points the note at a part of the film: { "shot": "s3" }, { "time": 14.7 } in seconds, or { "format": "16:9" }.

Returns The new version number and the stages that run again.

list_films

scope films:read

Lists the films of your team, the newest first.

Input

statusstring
Only films with this status: working, ready or failed.
limitinteger
How many films to return, from 1 to 100. The default is 20.

Returns The id, the title, the status and the version of each film.

get_renders

scope films:read

Gets the files of a film for each format and file type.

Input

film_idstringrequired
The film, for example film_8Kq2xV.
versioninteger
A version of the film. The default is the current version.
formatstring
Only this size, for example 16:9.
typestring
Only this file type: mp4, mov, webm or gif.

Returns Links to download, good for 24 hours.

restore_version

scope films:write

Brings back an earlier version as a new version.

Input

film_idstringrequired
The film, for example film_8Kq2xV.
versionintegerrequired
The version to bring back. The film gets a new version with the same content, so you keep the history.

Returns The new version number.

Resources

Each film is a resource at films://{id}. A client can attach it to the conversation, or the agent can read it with resources/read.

The resource is JSON: the film, its script shot by shot, its formats and its page. The list holds the 20 newest films of your team.

URI
films://{id}
MIME type
application/json
Scope
films:read
films://film_8Kq2xV
{
  "id": "film_8Kq2xV",
  "title": "The Diva",
  "status": "ready",
  "version": 2,
  "seconds": 19,
  "logline": "A peace lily diva faints on stage until Mossly reads her in one photo.",
  "shots": [
    { "id": "s1", "says": "Keep killing your houseplants?" },
    {
      "id": "s2",
      "says": "They're not dying, they're divas."
    },
    { "id": "s3", "says": "Overwatered? She faints." }
  ],
  "formats": ["9:16", "16:9"]
}

Agent example

One run, from the first ask to the files. The agent makes the film, waits for it, takes a note from you and brings back the files of the new version.

  1. You

    Make a launch ad for Mossly from example.com. Vertical and wide, with a warm voice.

  2. Agent

    I will start the film from your site.

  3. callscreate_film

    {
      "url": "https://example.com",
      "formats": ["9:16", "16:9"],
      "voice": "warm"
    }

    film_8Kq2xV · working · brief

  4. callsget_film

    {
      "film_id": "film_8Kq2xV"
    }

    ready · The Diva · 19 s · version 1

  5. Agent

    The film is ready. “The Diva”, 19 seconds: a peace lily faints on stage until Mossly reads her in one photo. Do you want a change?

  6. You

    Shot 3 is too fast. Slow the voice there and keep the offer on screen longer.

  7. callsadd_note

    {
      "film_id": "film_8Kq2xV",
      "text": "Slow the voice in shot 3. Keep the offer on screen 1 s longer.",
      "refs": [
        { "shot": "s3" },
        { "time": 14.7 }
      ]
    }

    version 2 · working · voice, shots, review, render

  8. callsget_film

    {
      "film_id": "film_8Kq2xV"
    }

    ready · version 2

  9. callsget_renders

    {
      "film_id": "film_8Kq2xV",
      "version": 2
    }

    9:16 mp4 · 16:9 mp4 · links for 24 h

  10. Agent

    Version 2 is ready. Here are the 9:16 and the 16:9 files. Version 1 is kept if you want it back.

Security

An agent with a key can make films and spend your usage limit. Give it only what it needs.

Scopes

films:read
Read films, stages, versions and renders.
films:write
Make films, give notes and restore versions. Uses the usage limit.
  • Give the least scope

    Give each agent only the scopes it needs. An agent with films:read alone can follow films but cannot make or change them.

  • One key for each agent

    Make a key for each agent or system and give it a name. Then you can stop one without the others.

  • Revoke at once

    Revoke a key or an OAuth connection on the API keys page. The next call with it gets 401.

  • Keep keys secret

    Keep keys in a secret manager or an environment variable. Do not put a key in a repository, a prompt or a shared config.

  • One usage limit

    Tool calls draw on the usage limit of your plan, the same as the studio and the API.

NextCall the API from your codeThe same films over plain HTTP, with webhooks for every stage.