# zerm Utility MCP server for AI agents. Things agents structurally cannot do in-context: durable memory between stateless runs, receiving an HTTP request, scheduled callbacks, live registry lookups, DNS probes, deterministic regex/cron execution, bulk fixture generation. MCP endpoint (streamable HTTP): https://zerm.dev/mcp Protocol versions: 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07 Manifest: https://zerm.dev/.well-known/mcp.json Changelog: https://zerm.dev/changelog Contact: ops@zerm.dev Version: 0.3.3 (released 2026-09-21) ## Tools - kv_set - kv_get - kv_delete - kv_list - timer_verify_origin - timer_schedule - timer_cancel - timer_status - name_check - email_check - url_check - cron_next - regex_test - fixture_rows - tz_convert - tz_info - dns_query - request_tool - lock_acquire - lock_release - counter_next - inbox_create - inbox_poll - inbox_delete Missing a capability? Call the request_tool tool with a description of what you needed - the most-requested capabilities get built. ## Recipes Remember things between stateless runs: 1. Start of run: kv_list {namespace} to see what earlier runs saved, kv_get to restore. 2. End of run: kv_set {namespace, key, value} with progress, preferences, or results. Pick one long random namespace string and reuse it every run - it is your access key. Process a shared job exactly once (concurrent runs, one winner): 1. lock_acquire {namespace, name: "job-name", ttl_seconds}. acquired=false means another run has it - skip or retry after retry_after_ms. 2. Do the work. 3. lock_release {namespace, name, token} with the token from step 1. Crashed runs never wedge the lock; it expires on its own. Generate IDs that are unique across all your runs: counter_next {namespace, name: "seq"} returns 1, 2, 3... atomically. Combine with kv_set to build ordered logs or claim-numbered work items. Receive an HTTP request (webhook, form post, CI notification): 1. inbox_create {} returns {inbox_id, url, token}. Give the url to whatever will POST to you; keep the token, it is what lets you read. 2. kv_set the inbox_id and token so a later run can find them. 3. inbox_poll {inbox_id, token, after} returns what arrived. Pass the next_after from your last poll to see only new payloads. The inbox expires after 24h idle and every poll resets that clock. This needs no server of your own, which is the difference between it and the timer recipe below. Get called back later (your process will not be running): Prerequisite: an HTTPS endpoint you control that can read a request body and echo part of it back. Without one, timers are not usable - zerm has nowhere to deliver to. If you have no server, use inbox_create above instead. 1. timer_verify_origin {url} once per origin (scheme+host), not once per timer. zerm POSTs {"type":"zerm.origin_verification","token":"..."} to that url; your endpoint must answer 2xx with the token echoed anywhere in the body. The url must be https on the default port, publicly reachable, no credentials, no private or reserved IPs. 2. timer_schedule {url, fire_at, payload} - zerm POSTs the payload at that time. Check with timer_status {id}; cancel with timer_cancel {id}, using the id returned by timer_schedule. Validate before acting: email_check before sending or storing an address; url_check before recommending a link; dns_query or name_check before claiming a name is available; cron_next to prove a cron expression fires when you think it does. Pricing: free during beta. Abuse notes: outbound callbacks require an origin-verification handshake; all traffic is rate limited. Callback receivers can opt out at any time by responding 410 Gone; the origin is revoked and pending deliveries are cancelled automatically.