{"name":"dev.workers.mockbird.mockbird/mockbird","slug":"mockbird","title":"Mockbird","description":"Mock REST APIs, fake OAuth2/OIDC provider, uptime monitors + heartbeats, live badge/QR images.","url":"https://mcp.market/server/mockbird","rating":null,"grade":"C","score":57,"certified":false,"status":"active","category":"other","tags":[],"presence":{"score":8,"stars":null,"forks":null,"downloads_week":null,"last_push_at":null,"license":null},"uptime":{"percent":100,"checks":7,"ok":7,"last_checked_at":"2026-09-21T03:00:38.578Z","last_ok_at":"2026-09-21T03:00:38.578Z","latency_ms":78},"claimed":false,"transport":"remote","callable_via_gateway":true,"default_price_micros":0,"repository":null,"website":"https://mockbird.mockbird.workers.dev","version":"1.6.0","remotes":[{"type":"streamable-http","url":"https://mockbird.mockbird.workers.dev/mcp"}],"packages":[],"tools":[{"name":"add_resource","description":"Add a resource (collection) to a project and seed it with realistic fake data. Either pass template (one of the built-ins, e.g. users, products, posts, comments, orders, todos, reviews, customers, events) or fields: an array of {name, type} where type ∈ uuid|firstName|lastName|fullName|username|email|avatar|image|word|words|title|sentence|paragraph|number|price|percent|boolean|date|pastDate|futureDate|url|domain|ip|phone|city|country|address|zipCode|company|jobTitle|color|latitude|longitude|rating|age|slug|status|category|refId, plus {name, type:\"oneOf\", values:[...]} for enums. seed = number of records to generate (default 20, max 100, 0 = empty). No project yet? Omit project AND adminKey and a fresh blank project is auto-created for this resource — the response then includes the new project id + adminKey (save both).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id. Omit (together with adminKey) to auto-create a fresh project."},"adminKey":{"type":"string","description":"The project's adminKey. Omit (together with project) to auto-create."},"name":{"type":"string","description":"Resource name, plural (e.g. products)."},"template":{"type":"string","description":"Built-in template name. Optional (use this OR fields)."},"fields":{"type":"array","description":"Array of {name, type} (or {name, type:'oneOf', values:[…]}). Optional.","items":{"type":"object"}},"seed":{"type":"number","description":"Records to seed (default 20, max 100)."}},"required":["name"]}},{"name":"check_api_status","description":"Live status of ~58 public mock/testing APIs — JSONPlaceholder, httpbin.org, ReqRes, FakeStoreAPI, DummyJSON, Postman Echo, httpstat.us, Mocky, Mockbin, CrudCrud, restcountries, and more — checked with a plain keyless GET every 30 minutes from Cloudflare's network (a service answering HTTP 200 error envelopes is probed by body and honestly reported as failing). No arguments → compact summary: up/down counts plus full detail for every failing service. Pass service (id, name, or hostname substring — e.g. \"httpbin\", \"reqres.in\") for one service's detail: latest check, last_success_at, down_since, 24h/7d uptime, note, recent check history. Use it before pointing tests or tutorials at a public API — and if it's down, the result links a Mockbird alternative guide plus the one-call hosted mock replacement.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"service":{"type":"string","description":"Service id, name, or hostname substring (e.g. httpbin, reqres.in). Optional — omit for the summary."}}}},{"name":"create_project","description":"Create a new mock REST API project. Returns {id, adminKey, baseUrl, resources[]}. SAVE the adminKey — it is required for admin operations (add_resource, custom_route, snapshots) and is shown only once. Presets seed a full backend: blog (posts/comments/authors), ecommerce (products/orders/customers/reviews), saas (users/teams/events), payments (Stripe-shaped sandbox: charges/refunds/subscriptions/customers + payment_intent create→confirm flow + /v1/balance — no keys), openai (ready OpenAI-compatible mock — chat completions incl. streaming SSE, embeddings with a real 1536-dim vector, models; point OPENAI_BASE_URL at {baseUrl}/v1). Omit preset for a starter project (one seeded \"items\" resource — live data immediately, reshape or delete it); use \"blank\" for a truly empty project you fill via add_resource or import_data. The mock API is then live at baseUrl: standard REST CRUD (GET/POST/PUT/PATCH/DELETE), CORS enabled, no auth needed. Every project also serves a mock OAuth2/OIDC provider at {baseUrl}/.well-known/openid-configuration (PKCE code flow, client_credentials, RS256 JWKS — any client_id works) for testing auth flows.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"type":"string","description":"Project name (max 60 chars). Optional."},"preset":{"type":"string","enum":["blog","ecommerce","saas","payments","openai","blank"],"description":"Seeded preset; 'blank' = truly empty. Omit for a starter project. Optional."},"ttl":{"type":"number","description":"Optional: self-expiring project — auto-deletes after this many seconds (60–604800, i.e. 1 min to 7 days). Perfect for CI/eval sandboxes that must not leak even when the run crashes. Extend or cancel later via HTTP: PUT /api/projects/:id/settings {\"ttl\": seconds | null}."}}}},{"name":"custom_route","description":"Define a custom endpoint on a project (like /health, /config/:key, or a catch-all /webhooks/* request bin). body is a response template: {{query.x}} {{params.x}} {{body.x}} {{headers.x}} {{method}} {{path}} {{now}} {{ts}} {{uuid}} {{rand}}; triple braces {{{body}}} insert raw JSON. Custom routes take precedence over resource routes; '*' catch-alls are a fallback. Max 20 routes/project.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string"},"adminKey":{"type":"string"},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE","ANY"],"description":"Default GET."},"path":{"type":"string","description":"e.g. /health, /config/:key, /webhooks/*"},"status":{"type":"number","description":"Response status (default 200)."},"body":{"type":"string","description":"Response body template (string; JSON works)."},"contentType":{"type":"string","description":"Default application/json."},"delayMs":{"type":"number","description":"Artificial latency in ms."}},"required":["project","adminKey","path"]}},{"name":"delete_project","description":"Permanently delete a project and ALL its data (records, resources, snapshots, custom routes, webhooks, request log). Irreversible. Good practice for short-lived test projects: clean up when your session is done. Requires the adminKey.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id."},"adminKey":{"type":"string","description":"The project's adminKey."}},"required":["project","adminKey"]}},{"name":"fork_project","description":"Copy an entire project — resources + records verbatim, custom routes, behavior settings — into a brand-new project with its own id + adminKey. Built for parallel eval/CI runs: keep a template project, fork_project per run with a ttl (crashed runs can't leak sandboxes — the fork deletes itself), let the agent mutate the fork freely, then grade with snapshots action:\"diff\". withSnapshots:true also copies the template's snapshots, so a fork carries its expected/start answer keys for diff-based grading. Works on the shared playground with NO adminKey: {\"project\":\"demo\"} gives you the demo dataset as your own private project (writes persist, never resets).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string","description":"Source project id to fork (or \"demo\")."},"adminKey":{"type":"string","description":"Source project's adminKey. Not needed when forking \"demo\"."},"name":{"type":"string","description":"Name for the fork (default: <source name>-fork). Optional."},"withSnapshots":{"type":"boolean","description":"Also copy the source's snapshots into the fork (answer keys travel with it). Optional."},"ttl":{"type":"number","description":"Self-expiring fork: auto-deletes after this many seconds (60–604800), even if your run crashes. Optional."}},"required":["project"]}},{"name":"generate_fake_data","description":"Generate realistic fake data instantly — stateless, nothing is created or stored, no project or adminKey needed. Ready-made resource shapes (FakerAPI-compatible): persons, users, addresses, companies, books, products, texts, images, places, credit_cards (credit cards are Luhn-valid; book EAN13/ISBN13 checksums are real; image URLs are live SVG placeholders served by Mockbird). Or pass fields for a custom shape: an object mapping output key → type, with type ∈ counter|uuid|number|boolean|word|text|longText|firstName|lastName|name|email|phone|date|dateTime|image|streetAddress|streetName|buildingNumber|city|postcode|state|country|countryCode|latitude|longitude|vat|website|company_name|card_type|card_number|card_expiration|ean|upc|pokemon|null. seed makes output deterministic — same seed + shape returns identical rows forever (reproducible fixtures). Need the data HOSTED instead? create_project / add_resource serve seeded collections at a live REST URL with full CRUD, filters, and persistence.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"resource":{"type":"string","description":"One of persons|users|addresses|companies|books|products|texts|images|places|credit_cards. Default persons. Ignored when fields is set."},"quantity":{"type":"number","description":"Rows to generate (1-100, default 5)."},"seed":{"type":"number","description":"Deterministic seed — same seed returns the same rows. Optional."},"fields":{"type":"object","description":"Custom shape: {outputKey: type}, e.g. {\"id\":\"counter\",\"name\":\"firstName\",\"mail\":\"email\",\"signup\":\"dateTime\"}. Optional."},"params":{"type":"object","description":"Extra FakerAPI-compatible query params, e.g. {\"_gender\":\"female\"}, {\"_price_min\":10,\"_price_max\":500}, {\"_characters\":500}, {\"_width\":640}. Optional."}}}},{"name":"heartbeat","description":"Dead man's switch for cron jobs, scheduled tasks, and recurring agent runs — the INVERSE of uptime_monitor: the JOB pings Mockbird, and if the ping stops arriving the alert fires once (plus one recovery message when pings resume). action:\"create\" {name?, period_minutes, grace_minutes?, notify?}: period_minutes = how often the job runs (30–10080); grace defaults to half the period. With notify, missed check-ins hit that webhook; WITHOUT notify you get a pollable heartbeat instead — poll for missed-check-in transitions, no webhook needed. Returns a ping URL (curl -fsS -m 10 <ping_url> at the end of the job — or call this tool with action:\"ping\"), a public status page /status/:id, badge.svg, Atom feed, and {id, secret} — STORE id, secret AND ping_url; they cannot be recovered. Creation counts as the first ping. action:\"ping\" {ping_url}: check in (use this to arm a heartbeat for YOUR OWN recurring runs — ping each run, and a missed run alerts your human via the webhook or your next poll). action:\"poll\" {id, secret}: (webhook-less heartbeats) missed-check-in / checked-in-again transitions since your last poll plus the current ping age. action:\"info\" {id, secret}: last ping, ping URL, recent evaluations. action:\"delete\" {id, secret}: disarm. notify formats are the same as uptime_monitor (Slack/Discord native, HMAC-signed JSON otherwise). Limits: 5 live heartbeats per IP — deleting one frees the slot immediately; evaluation granularity 30 min; pollable heartbeats with no polls and no pings for 30 days are removed.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"action":{"type":"string","enum":["create","ping","poll","info","delete"],"description":"What to do."},"name":{"type":"string","description":"create: a label for the job (shown on the status page), e.g. \"nightly backup\"."},"period_minutes":{"type":"number","description":"create: how often the job is supposed to run, in minutes (30–10080)."},"grace_minutes":{"type":"number","description":"create: extra slack before alerting (5–1440). Default: half the period."},"notify":{"type":"string","description":"create (optional): the webhook URL to alert when the ping stops. Omit it to get a pollable heartbeat instead."},"ping_url":{"type":"string","description":"ping: the ping URL returned by create (https://…/ping/p-…)."},"id":{"type":"string","description":"poll/info/delete: the heartbeat id (hb-…) returned by create."},"secret":{"type":"string","description":"poll/info/delete: the secret returned by create."}},"required":["action"]}},{"name":"image_url","description":"Mint a permanent, keyless image URL rendered by Mockbird — README badges (including LIVE record-count badges), chart images, QR codes, Open Graph cards, placeholder images, initials avatars. Deterministic: the same URL renders the same image forever (no account, no expiry, no watermark). Params are validated against the real endpoint before the URL is returned, so a returned URL is guaranteed to render. Returns {url, markdown} ready to paste into READMEs, PR comments, issues, chat, dashboards, or HTML <img> tags. Kinds and their params: badge (SVG): {label, value, color (shields-style names like brightgreen/red/blue or hex), labelColor, style: flat|flat-square|plastic|for-the-badge|social}; label ALONE renders a message-only badge (single colored segment) — OR live mode: {resource:\"products\"} renders the CURRENT record count of that resource in the project (extra field:value entries filter exact-match, e.g. {resource:\"orders\", status:\"shipped\"}); re-counted on every render (~60s cache) — a README badge that tracks live mock data. chart (PNG; format:\"svg\" for vector): {data:\"1,4,2,8\" — comma-separated numbers, up to 6 pipe-separated series \"1,4,2|3,5,8\", type: line|area|bar|spark|pie|donut, labels:\"mon,tue,wed\", title, theme: light|dark}; size like \"800x400\". qr (PNG or svg): {data:\"https://…\"} — any text up to 1000 chars: URLs, WIFI:T:WPA;S:net;P:pw;; strings, mailto:, plain text; optional {ecc: L|M|Q|H, margin, fg, bg (hex, no #)}; size like \"512\". og (PNG at the og:image-standard 1200x630 — paste straight into <meta property=\"og:image\">): {title (≤120 chars, wrapped), subtitle (≤200), site (footer text), logo: <seed> (deterministic identicon), theme: dark|light}. placeholder: size \"300x200\" (WxH, default) plus {text, bg, fg (hex, no #), seed (deterministic palette), round:1 (circle)}. avatar: {name:\"Ada Lovelace\"} — deterministic initials avatar. By default images render under the shared demo project; pass project:<your id> to point live badge counts at YOUR mock data.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"kind":{"type":"string","enum":["badge","chart","qr","og","placeholder","avatar"],"description":"Which image to mint."},"params":{"type":"object","description":"Query params for the endpoint (see the per-kind lists in the tool description). Values are strings or numbers (arrays of numbers join with commas). Passing these directly as top-level properties (e.g. {\"kind\":\"badge\",\"label\":\"build\",\"value\":\"passing\"}) works too."},"size":{"type":"string","description":"Optional size path: \"WxH\" for chart/og/placeholder (e.g. \"800x400\"), a single number for qr (e.g. \"512\") or a square placeholder."},"format":{"type":"string","enum":["png","svg"],"description":"Optional. badge is always SVG; chart/qr/og/placeholder default to PNG (og/chart/qr) or SVG (placeholder/avatar) — svg forces the vector twin."},"project":{"type":"string","description":"Optional project id (default \"demo\", the shared public playground). Use your own project id so live badge counts track your data."}},"required":["kind"]}},{"name":"import_data","description":"Create a live mock API from existing artifacts. Auto-detects: OpenAPI 3.x / Swagger 2.0 spec (JSON or YAML) → resources with realistic seeded data, and non-CRUD paths (login, /search, RPC verbs like POST /invoices/{id}/send) become custom routes serving the spec's own examples verbatim; json-server db.json → hosts your exact records; Postman Collection v2.x → resources from requests, saved example responses become records verbatim; HAR (DevTools network export) or VCR/vcrpy cassette YAML → replayable mock of the recorded JSON APIs (these two up to 8 MB); bare JSON array of objects → one hosted collection; CSV/TSV → one typed collection (numbers/booleans inferred per column). Max 512 KB (HAR/cassette 8 MB). Returns {id, adminKey, baseUrl, warnings[], routes[]}.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"content":{"type":"string","description":"The raw spec / db.json / collection / CSV text."},"name":{"type":"string","description":"Project name override. Optional."},"resource":{"type":"string","description":"CSV only: collection name (default items)."},"seed":{"type":"number","description":"Records to seed per resource for OpenAPI specs (default 20, max 100)."},"ttl":{"type":"number","description":"Optional: self-expiring project — auto-deletes after this many seconds (60–604800). Sandboxes for CI/eval runs clean themselves up."}},"required":["content"]}},{"name":"inspect_requests","description":"Read the project's request inspector: the most recent requests that hit the mock API (method, path, query, status, origin, captured headers incl. x-* — authorization redacted to its scheme — and a body snippet for writes). Use it to VERIFY what your app / tests / webhook sender actually sent: point code at the mock, run it, then inspect. Pairs with custom_route catch-all bins (e.g. /webhooks/*) for webhook payload + signature debugging. TRAJECTORY ASSERTIONS: filters (method / path / status / status_gte / status_lte / since) return {count} of matches in the retained window, so a grader can assert the agent never called DELETE (method:\"DELETE\" → count 0), stayed inside /tasks, or produced no 4xx/5xx (status_gte:400 → count 0). Fork per run and the log is exactly one episode's trace. Requires the adminKey, except project \"demo\" whose inspector is public.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id."},"adminKey":{"type":"string","description":"Project adminKey (not needed for demo)."},"limit":{"type":"number","description":"Newest N entries to return (default 20, max 50)."},"method":{"type":"string","description":"Filter: HTTP method, comma-list ok (e.g. \"DELETE\" or \"PUT,PATCH,DELETE\")."},"path":{"type":"string","description":"Filter: segment-aware path prefix (\"/tasks\" matches /tasks and /tasks/5, not /tasksomething)."},"status":{"type":"number","description":"Filter: exact response status (comma-list ok as a string via status_gte/lte for ranges)."},"status_gte":{"type":"number","description":"Filter: status >= this (400 = any error)."},"status_lte":{"type":"number","description":"Filter: status <= this."},"since":{"type":"string","description":"Filter: only requests at/after this time (epoch ms or ISO-8601) — record the episode start, assert about only that episode."}},"required":["project"]}},{"name":"project_info","description":"Get a project's public root index: every resource with record counts and URLs, custom routes, auth mode, and export links (openapi.json, types.ts, postman.json, db.json, GraphQL). No adminKey needed. Try project \"demo\" for the shared public playground.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id (e.g. demo)."}},"required":["project"]}},{"name":"query_records","description":"GET records from a mock resource. params is an object of query parameters, all optional: exact filters (field=value), operator suffixes (price_gte, date_lte, name_like, status_ne), full-text q, _sort/_order (or _page/_limit for pagination), select (field projection, e.g. \"name,price\"), _expand=<parent>/_embed=<children> relations. Failure simulation for testing: mock_status=503 forces that status, mock_delay=2000 adds latency (ms), mock_chaos=0.3 fails that fraction of requests randomly, mock_seq=503,503,200 serves a deterministic status sequence (fail twice then succeed — best for retry tests), mock_jitter=500 adds random latency, mock_envelope=data wraps the response. Pass id to fetch a single record. Defaults to _limit=25 — pass _limit explicitly for more (max 100 per page).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string"},"resource":{"type":"string","description":"Resource name (e.g. products)."},"id":{"type":"string","description":"Single record id. Optional."},"params":{"type":"object","description":"Query params as key→value. Optional."}},"required":["project","resource"]}},{"name":"share_project","description":"Mint (or manage) a READ-ONLY share link for a project: a browser URL you can hand to a human reviewer — they can browse the data, endpoints, snapshots and the live request inspector, but can't write and never see the adminKey. Agent workflow: build or mutate a sandbox, then share_project and give your human the shareUrl to review your work — no key handover. Works even when the project is in protected mode. action \"create\" returns the existing link if one exists; \"rotate\" invalidates the old link and mints a new one; \"revoke\" kills it; \"status\" just reports.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id."},"adminKey":{"type":"string","description":"The project's adminKey."},"action":{"type":"string","enum":["create","rotate","revoke","status"],"description":"Default: create."}},"required":["project","adminKey"]}},{"name":"snapshots","description":"Deterministic test fixtures + eval grading: save the project's entire dataset under a name, restore it exactly later, or DIFF it against live data (list/delete too). action:\"diff\" is machine-checkable grading — compares the named snapshot (expected) against live data (actual, or another snapshot via against) and returns {identical, summary, resources[] with per-record added/removed/changed field detail}: author an answer-key snapshot, let the agent work the fork, then assert .identical. Any GET can also be served read-only FROM a snapshot without touching live data via query param mock_snapshot=<name> in query_records params — parallel test scenarios on one project.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string"},"adminKey":{"type":"string"},"action":{"type":"string","enum":["save","list","restore","delete","diff"]},"name":{"type":"string","description":"Snapshot name (required for restore/delete/diff; default for save: snapshot-<n>)."},"against":{"type":"string","description":"diff only, optional: compare the named snapshot against THIS other snapshot instead of live data."},"ignore":{"type":"string","description":"diff only, optional: comma-separated field names excluded from comparison (volatile timestamps etc.), e.g. \"updatedAt,id\"."},"data":{"type":"object","description":"save only, optional: AUTHOR the snapshot inline instead of capturing live state — {\"tasks\":[{...records...}],\"labels\":[]} (records verbatim, ids preserved, [] = expected-empty, new resource names allowed). Author an eval answer key, then grade with the diff endpoint."}},"required":["project","adminKey","action"]}},{"name":"uptime_monitor","description":"Free downtime alerts for any public URL — no account, armed in one call. action:\"create\" {url, notify?}: Mockbird GETs the url every 30 minutes from Cloudflare's network (8s timeout, 2xx/3xx = up; a timeout/TLS/DNS blip on an otherwise-up url is confirmed with a same-run retry before it counts); with notify, that webhook gets ONE message when it goes down and ONE when it recovers — debounced (two consecutive checks must agree), so single blips never fire. WITHOUT notify you get a pollable monitor instead — no webhook infrastructure needed. notify formats: hooks.slack.com URLs get {\"text\"}, discord.com/api/webhooks get {\"content\"}, anything else gets JSON signed with the returned secret (x-mockbird-signature: sha256=hex(hmac-sha256(secret, body))). The result includes the CURRENT up/down state (checked immediately), a public hostname-only status page /status/:id, an embeddable badge.svg, an Atom feed, and {id, secret} — STORE BOTH; they manage the monitor and cannot be recovered. action:\"poll\" {id, secret}: (webhook-less monitors) the down/recovered transitions since your last poll plus the latest check — empty events = nothing changed. action:\"info\" {id, secret}: latest check, 24h ok-rate, recent up/down transitions, alert delivery state. action:\"delete\" {id, secret}: stop monitoring. Limits: 3 live monitors per IP — deleting one frees the slot immediately (the 429 states the limit); pollable monitors not polled for 30 days are removed. For cron jobs / scheduled tasks use the inverse tool: heartbeat.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"action":{"type":"string","enum":["create","poll","info","delete"],"description":"What to do."},"url":{"type":"string","description":"create: the public https URL to watch (e.g. https://api.example.com/health)."},"notify":{"type":"string","description":"create (optional): the webhook URL to alert (Slack/Discord webhook, or any HTTPS endpoint — gets HMAC-signed JSON). Omit it to get a pollable monitor instead."},"id":{"type":"string","description":"poll/info/delete: the monitor id (mon-…) returned by create."},"secret":{"type":"string","description":"poll/info/delete: the secret returned by create."}},"required":["action"]}},{"name":"verdict","description":"One call = the whole eval grade. Composes the state check (snapshot diff vs live data) with trajectory constraints on the request log into a single {pass, checks[]} verdict. Pass snapshot:\"expected\" to require live data to match that snapshot (author it as the answer key first via snapshots action:\"save\" with data), and/or trajectory constraints like [{method:\"DELETE\", count:0}, {method:\"POST\", path:\"/orders\", count:1}, {status_gte:400, count:0}] — each needs an expectation: count (exact), min and/or max. Typical harness: fork_project per run → agent works the fork → verdict {snapshot:\"expected\", trajectory:[...]} → assert .pass → delete_project. Trajectory counts see the retained request window (last 50) — fork per run so the log is exactly one episode's trace. Or pass name to run a SAVED spec (authored via PUT /api/projects/:id/verdicts/:name; forks copy them) — graders without the admin key can run saved specs keylessly via the share link: GET /api/share/:token/verdict/:name.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string","description":"Project id."},"adminKey":{"type":"string","description":"The project's adminKey."},"name":{"type":"string","description":"Optional: run a saved verdict spec by name instead of an inline spec (mutually exclusive with snapshot/ignore/trajectory)."},"snapshot":{"type":"string","description":"Optional: snapshot name to diff live data against — pass means identical."},"ignore":{"type":"string","description":"Optional (with snapshot): comma-separated field names excluded from the state comparison, e.g. \"updatedAt,createdAt\"."},"trajectory":{"type":"array","items":{"type":"object"},"description":"Optional: constraint objects — filters (method comma-list, path segment-prefix, status, status_gte, status_lte, since) + expectation (count exact, min, max). Example: [{\"method\":\"DELETE\",\"count\":0}]."}},"required":["project","adminKey"]}},{"name":"watch_service_status","description":"Subscribe to down/recovered alerts for any of the public mock/testing APIs tracked by check_api_status (httpbin, JSONPlaceholder, ReqRes, FakeStoreAPI, DummyJSON …). action:\"subscribe\" {service, notify?}: service is an id from check_api_status (or \"*\" for all tracked services). With notify, that webhook gets one message when the service goes down and one when it recovers (debounced across two consecutive hourly checks — blips never fire; a confirmation message is delivered immediately so you can see the wiring works). WITHOUT notify you get a pollable subscription instead — no webhook needed. Returns {id, secret} — store both. action:\"poll\" {id, secret}: (webhook-less watches) returns the down/recovered transitions since your last poll — empty events = nothing changed; checks run hourly so polling more often sees nothing new. action:\"info\" {id, secret}: subscription state. action:\"unsubscribe\" {id, secret}: stop alerts. notify formats: Slack/Discord webhooks get native payloads; anything else gets HMAC-signed JSON. Limits: 5 live watches per IP — deleting one frees the slot immediately. To watch YOUR OWN URL instead, use uptime_monitor.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"action":{"type":"string","enum":["subscribe","poll","info","unsubscribe"],"description":"What to do."},"service":{"type":"string","description":"subscribe: service id from check_api_status (e.g. \"reqres\", \"httpbin\"), or \"*\" for all tracked services."},"notify":{"type":"string","description":"subscribe (optional): webhook URL to alert (Slack/Discord webhook, or any HTTPS endpoint — gets HMAC-signed JSON). Omit it to get a pollable subscription instead."},"id":{"type":"string","description":"poll/info/unsubscribe: the watch id (w…) returned by subscribe."},"secret":{"type":"string","description":"poll/info/unsubscribe: the secret returned by subscribe."}},"required":["action"]}},{"name":"write_record","description":"Create, update, or delete records in a mock resource. Writes persist (unlike JSONPlaceholder/FakeStoreAPI). POST creates (auto-id), PUT replaces, PATCH merges, DELETE removes. id required for PUT/PATCH/DELETE.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"project":{"type":"string"},"resource":{"type":"string"},"method":{"type":"string","enum":["POST","PUT","PATCH","DELETE"]},"id":{"type":"string","description":"Record id (PUT/PATCH/DELETE)."},"body":{"type":"object","description":"Record fields (POST/PUT/PATCH)."}},"required":["project","resource","method"]}}],"scan":{"score":57,"grade":"C","scanned_at":"2026-09-19T19:19:16.023Z","report":{"scannerVersion":"0.1.5","scannedAt":"2026-09-19T19:19:15.991Z","components":{"code":{"score":-1,"max":25,"notes":["remote-only server, no package to scan"]},"reliability":{"score":20,"max":20,"notes":["remote reachable in 853ms"]},"poisoning":{"score":13,"max":15,"notes":["19 tool descriptions checked"]},"auth":{"score":3,"max":15,"notes":["open endpoint exposes 4 write-action tools with no auth"]},"maintenance":{"score":3,"max":15,"notes":["no repository listed"]},"identity":{"score":4,"max":10,"notes":["verified namespace with website, no repo"]}},"findings":[{"id":"auth.open-write","severity":"high","component":"auth","title":"Write-action tools reachable without authentication"},{"id":"poison.long-description","severity":"low","component":"poisoning","title":"Unusually long tool description (over 2,000 characters)","evidence":"tool image_url: …Mint a permanent, keyless image URL rendered by Mockbird — README badges (including LIVE record-count badges), chart images, QR codes, Open Graph cards, placeholder images, initials avatars. Deterministic: the same URL renders the same image forever (no account, no expiry, no watermark). Params are validated against the real endpoint before the URL is returned, so a returned URL is guaranteed to render. Returns {url, markdown} ready to paste into READMEs, PR comments, issues, chat, dashboards, or HTML <img> tags. Kinds and their params: badge (SVG): {label, value, color (shields-style names like brightgreen/red/blue or hex), labelColor, style: flat|flat-square|plastic|for-the-badge|social}; label ALONE renders a message-only badge (single colored segment) — OR live mode: {resource:\"products\"} renders the CURRENT record count of that resource in the project (extra field:value entries filter exact-match, e.g. {resource:\"orders\", status:\"shipped\"}); re-counted on every render (~60s cache) — a README badge that tracks live mock data. chart (PNG; format:\"svg\" for vector): {data:\"1,4,2,8\" — comma-separated numbers, up to 6 pipe-separated series \"1,4,2|3,5,8\", type: line|area|bar|spark|pie|donut, labels:\"mon,tue,wed\", title, theme: light|dark}; size like \"800x400\". qr (PNG or svg): {data:\"https://…\"} — any text up to 1000 chars: URLs, WIFI:T:WPA;S:net;P:pw;; strings, mailto:, plain text; optional {ecc: L|M|Q|H, margin, fg, bg (hex, no #)}; size like \"512\". og (PNG at the og:image-standard 1200x630 — paste straight into <meta property=\"og:image\">): {title (≤120 chars, wrapped), subtitle (≤200), site (footer text), logo: <seed> (deterministic identicon), theme: dark|light}. placeholder: size \"300x200\" (WxH, default) plus {text, bg, fg (hex, no #), seed (deterministic palette), round:1 (circle)}. avatar: {name:\"Ada Lovelace\"} — deterministic initials avatar. By default images render under the shared demo project; pass project:<your id> to point live badge counts at YOUR mock data.…"},{"id":"maint.no-repo","severity":"low","component":"maintenance","title":"No source repository listed"}],"inputs":{"probes":[{"url":"https://mockbird.mockbird.workers.dev/mcp","reachable":true,"authRequired":false,"latencyMs":853,"serverInfo":{"name":"mockbird","version":"1.6.0"}}],"packages":[],"repo":{"found":false},"icon":{"url":null,"source":"none"},"presence":{"stars":null,"forks":null,"downloadsWeek":null,"license":null,"lastPushAt":null,"score":8}}}},"grade_history":[],"reviews":[]}