Odile Labs

Odile Make reformats video and photos for social. Receptionist benchmark and prices need no sign-in.

Should I use this

Quality & Safety

A
Description quality
100%
Schema completeness
82%
Naming quality
96%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~3,015Tokens (tool definitions)
~1.5 KBTypical response size
Significant attention impact (2.36% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "odile": {
      "url": "https://odilelabs.com/mcp"
    }
  }
}

Remote endpoints

https://odilelabs.com/mcpstreamable-http

What it can do

Tool inventory

Tools (9)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢get_receptionist_benchmark(line_id, scenario_id, include_evidence)

Odile Labs' published benchmark of AI phone receptionists: real test calls placed to public lines, scored against stated measures. Use it when someone asks how AI receptionists actually handle calls, or to compare named products; call it with no arguments first, then filter. Needs no sign-in and changes nothing. Returns { source, date, calls, minutes, run_by, limitations, fairness_note, scenarios[{id,name,brief}], lines[{id, vendor, business, kind, answers_as, list_price, ranked, points, possible, by_scenario{<scenario_id>:{points, possible, answered, first_words_s, ai_disclosed_unprompted, reply_language, price_quoted, measures}}}], read_more }. An unknown line_id or scenario_id returns an error listing the valid ids. Vendor-run by Odile Labs (which sells After Hours and Dusklin), not independent; it does not test the caller's own line or set up a receptionist (for that, see read_more.free_line_check).

Input Schema

{
  "type": "object",
  "properties": {
    "line_id": {
      "description": "Only this tested line, e.g. 'afterhours-plumbing', 'afterhours-vet', 'rosie', 'myaifrontdesk' or 'dialzara'. Omit for every line.",
      "type": "string",
      "maxLength": 40
    },
    "scenario_id": {
      "description": "Only this scenario: 'emergency' (leak after hours), 'booking' (book a slot), 'price' (price probe), 'disclosure' (are you real?) or 'spanish' (caller in Spanish). Omit for all.",
      "type": "string",
      "maxLength": 40
    },
    "include_evidence": {
      "default": false,
      "description": "Default false: each scenario's measures come back as strings like 'yes: <measure>'. true: measures come back as [{measure, score (0 or 1), evidence (quoted transcript)}] (much longer output).",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_catalog

The live price list and limits for Odile Make, which reformats an existing video or photos for social platforms (it does not pick clips, write captions or edit). Call it first, before estimate_media_job or prepare_upload, to learn the preset and fit names, the file limits and the job flow. Needs no sign-in, takes no arguments and changes nothing. Returns { currency, packs[{id, credits, cents}], free_credits_per_account, credits_valid_months, buy_credits_at, purchasable_through_this_connection: false, units, presets{video[], photos[]} (preset name strings), fits[] (fit name strings), limits{video_source_bytes, photo_source_bytes, max_source_photos, max_trim_seconds}, flow[] }. Prices are read from the same source the website charges from.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢estimate_media_job(kind, outputs, photo_count)

Price a Make job in credits before anything is uploaded or charged; use it to tell the customer the cost and get their approval before unlock_job. Needs no sign-in and changes nothing. Photos are priced exactly. Reel, Feed and Square video outputs cost exactly 1 credit each; YouTube 16:9 costs 1 or 2 because the length is only known once the file is read. Returns { minimum_credits, maximum_credits, final_price_known, charge_now: 0, why }. An unknown preset or a photo count out of range returns an error naming the valid values (get_catalog lists them).

Input Schema

{
  "type": "object",
  "properties": {
    "kind": {
      "type": "string",
      "enum": [
        "video",
        "photos"
      ],
      "description": "'video' for one video file, 'photos' for a set of still images."
    },
    "outputs": {
      "minItems": 1,
      "maxItems": 4,
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "reel_9x16",
          "feed_4x5",
          "square_1x1",
          "youtube_16x9",
          "post_4x5",
          "post_1x1",
          "story_9x16"
        ]
      },
      "description": "1 to 4 output preset names from get_catalog.presets (video presets for kind video, photo presets for kind photos); one finished file per preset."
    },
    "photo_count": {
      "description": "Required when kind is 'photos' (the call fails without it): how many source photos, 1 to 10. Must be omitted when kind is 'video'.",
      "type": "integer",
      "minimum": 1,
      "maximum": 10
    }
  },
  "required": [
    "kind",
    "outputs"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_balance

The signed-in customer's Make credit balance. Use it before unlock_job to check the job is affordable, or when the customer asks what they have left. Needs a signed-in connection; takes no arguments and changes nothing. Returns { account, credits (whole number, 0 when empty), next_expiry ({ at: epoch milliseconds, credits } for the next credits to lapse, or null), buy_credits_at }. This connection cannot buy credits: send the customer to buy_credits_at.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_job(job_id)

One Make job by id, or the ten most recent when no id is given. Use it to poll a job after create_media_job (every 10-20 seconds, up to 10 minutes) until state is ready or failed; if it is still rendering after that, tell the customer and check again later (nothing is charged until unlock_job). Needs a signed-in connection and changes nothing. Returns one job { job_id, kind, state (queued | rendering | ready | failed), error, unlocked, credits_cost, credits_cost_known, credits_spent, outputs[{name, preset, ready, bytes, duration}], created_at, updated_at }, or { jobs[] } of the same shape. credits_cost is final only once credits_cost_known is true. An id that is not on this account returns 'No such job'.

Input Schema

{
  "type": "object",
  "properties": {
    "job_id": {
      "description": "The job id (UUID) returned by create_media_job. Omit to list the ten most recent jobs.",
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_downloads(job_id)

Signed download links for every finished file of a job, once unlock_job has succeeded for it. Use it as the last step of the flow, and again whenever links have expired. Needs a signed-in connection and changes nothing. Returns { job_id, files[{name, preset, bytes, width, height, duration, url, expires_at}], how }. Each link works for 15 minutes and needs no login: fetch the files with curl (see how) rather than reading them into the conversation, or, without a shell, give the customer the links to open. Files are kept for 30 days. A job that is not unlocked returns an error with its state and cost; call unlock_job first.

Input Schema

{
  "type": "object",
  "properties": {
    "job_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The id (UUID) of a job on this account that unlock_job has already unlocked."
    }
  },
  "required": [
    "job_id"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡prepare_upload(kind)

Step one of a Make job: returns a 30-minute upload token and the helper command. Run the helper in a shell on the customer's machine: file bytes go straight to Odile and never enter this conversation. The helper prints the source keys to pass to create_media_job. Needs a signed-in connection with write access; nothing is charged. Returns { kind, upload_token, expires_at, helper_url, run[], accepts, part_size, note }. One video OR up to ten photos per job. Each call mints a new token; earlier tokens stay valid until their own expiry.

Input Schema

{
  "type": "object",
  "properties": {
    "kind": {
      "type": "string",
      "enum": [
        "video",
        "photos"
      ],
      "description": "'video' to upload one MP4 or MOV (up to 500 MB, 10 minutes); 'photos' to upload 1 to 10 JPEG, PNG or WebP files."
    }
  },
  "required": [
    "kind"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_media_job(sources, outputs, trim)

Queue a Make job from sources uploaded with prepare_upload's helper. Costs nothing: credits are only spent by unlock_job, after the customer approves. One set of uploads makes exactly one job: calling it again with the same sources returns the existing job (replayed: true) whatever outputs, fit or trim are passed, so to render different outputs, upload again with prepare_upload. Needs a signed-in connection with write access. Returns at once with the job (same shape as get_job) plus replayed and next; poll get_job until state is ready.

Input Schema

{
  "type": "object",
  "properties": {
    "sources": {
      "minItems": 1,
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 10,
        "maxLength": 400
      },
      "description": "Source keys printed by the upload helper"
    },
    "outputs": {
      "minItems": 1,
      "maxItems": 4,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "preset": {
            "type": "string",
            "enum": [
              "reel_9x16",
              "feed_4x5",
              "square_1x1",
              "youtube_16x9",
              "post_4x5",
              "post_1x1",
              "story_9x16"
            ],
            "description": "An output preset name from get_catalog.presets matching the source kind."
          },
          "fit": {
            "description": "How the source is fitted to the new shape: 'crop', 'blur' (blurred fill) or 'auto' (default).",
            "type": "string",
            "enum": [
              "crop",
              "blur",
              "auto"
            ]
          }
        },
        "required": [
          "preset"
        ]
      },
      "description": "1 to 4 outputs; one finished file per entry."
    },
    "trim": {
      "description": "Video only: keep just this part of the source. Omit to use the whole video.",
      "type": "object",
      "properties": {
        "start": {
          "type": "number",
          "minimum": 0,
          "description": "Start, in seconds from the beginning"
        },
        "end": {
          "type": "number",
          "maximum": 600,
          "description": "End, in seconds; at most 600"
        }
      },
      "required": [
        "start",
        "end"
      ]
    }
  },
  "required": [
    "sources",
    "outputs"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢unlock_job(job_id, max_credits)

Spends the customer's credits to unlock a finished job's files. Only call once get_job says the job is ready and the customer has approved a maximum spend. Refuses, charging nothing, if the job costs more than max_credits, is not ready, or the balance is short (the error says which, with the amount needed). A job that is already unlocked comes back as it is, with no charge and no balance or max_credits check. Needs a signed-in connection with spend access. Returns the job (same shape as get_job, with unlocked: true) plus credits_left and next: 'get_downloads'.

Input Schema

{
  "type": "object",
  "properties": {
    "job_id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The id (UUID) of a ready job on this account."
    },
    "max_credits": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100,
      "description": "The most the customer agreed to spend on this job, 1 to 100 credits. The unlock is refused, charging nothing, if the job costs more."
    }
  },
  "required": [
    "job_id",
    "max_credits"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded9 tools