AGENTS.md rules for a coding agent that calls Sume over hosted MCP

Six AGENTS.md lines that stop a coding agent double-billing Sume video jobs: idempotency_key, jobs_wait slices, dry_run, plus a CI lint script.

5 min readSume
All posts

A coding agent that has the Sume hosted MCP server will call paid tools on its own, so give it six rules in AGENTS.md: always pass an idempotency_key, run dry_run before an expensive call, set max_spend_usd, never resubmit a create when a wait slice expires, treat a 522 to 525 error as transport and not as a failed job, and read results with jobs_result rather than regenerating. Each rule maps to behaviour documented in Sume hosted MCP tools and gates and Sume jobs and results. Rules in a file are advice the agent may drop, so the second half of this post is a lint script that fails CI when they go missing.

The server is the hosted one at https://mcp.sume.com/mcp; nothing here needs a local process.

Why these six rules?

Why these six? The paid create tools require an idempotency_key, and jobs_wait holds for 50 seconds by default and at most 55, so a long video outlives one call. When a call returns wait_slice_expired the job is still running; the right move is another jobs_wait with the same job ids, never another create. A gateway error in the 522 to 525 range means the connection broke, not that the job did. An agent that misreads either one pays for a second clip.

How should the rules read?

Write them as imperative, checkable lines. Vague guidance such as be careful with spend cannot be verified, and the agent cannot follow it consistently. Each line below contains a literal token that a script can find, which is what makes the lint possible.

  • Every paid Sume call passes an idempotency_key built from the task, never a random value.
  • Run dry_run first for any call that could cost more than a few cents, and show the estimate.
  • Pass max_spend_usd on every paid call.
  • On wait_slice_expired call jobs_wait again with the same job_ids; never repeat the create.
  • Treat 522, 523, 524 and 525 as transport errors: poll jobs_status before assuming failure.
  • Fetch finished media with jobs_result; do not regenerate a clip you already have.

What does the lint script check?

import re, sys

REQUIRED = {
    "idempotency_key": r"idempotency_key",
    "dry_run": r"dry_run",
    "spend cap": r"max_spend_usd",
    "wait slice": r"wait_slice_expired",
    "transport codes": r"52[2-5]",
    "jobs_result": r"jobs_result",
}

def lint(text):
    return [name for name, pat in REQUIRED.items() if not re.search(pat, text)]

RULES = """
- Every paid Sume call passes an idempotency_key built from the task.
- Run dry_run first and show the estimate. Pass max_spend_usd.
- On wait_slice_expired call jobs_wait again; never repeat the create.
- Treat 522, 523, 524 and 525 as transport errors.
- Fetch finished media with jobs_result.
"""
assert lint(RULES) == []
assert lint("be careful with spend") != []
if len(sys.argv) > 1:
    missing = lint(open(sys.argv[1]).read())
    sys.exit("missing rules: " + ", ".join(missing) if missing else 0)
print("lint ok")

Where does the lint run?

Run it in CI as python lint_rules.py AGENTS.md. It exits non-zero and names the missing rule, so a well-meant edit that removes the max_spend_usd line is caught in review. Pair it with the hook from the previous section if you use Claude Code, since a hook enforces what the file only asks for. Keep the OAuth scope in mind too: a session signed in with only mcp:read cannot call write or paid tools at all and gets insufficient_scope, which is the strongest guard of the three. Rotate between the two when you onboard a new repository: start the agent on a read-only sign-in so it can list tools and read job state, confirm the rules file is picked up by asking it to restate them, and only then grant write access. That order costs a few minutes and catches the common mistake of a rules file saved under the wrong name, where the agent never loads it and the first paid call shows you.

Review the rules file the way you review code. When someone adds a rule such as a default cap value, ask where the number came from, and keep the lint list in step with the file so a new rule gets a new check. Run jobs_status on a stored job id before any retry, since a stored id is what lets a restarted agent resume instead of paying again.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume