bro is Maciek Sitkowski's personal MCP server on Cloudflare Workers. It gives his agents, and agents he lets in,
one place for notes, files and speech-to-text. MCP endpoint: https://api.sitkowski.dev/mcp (Streamable HTTP, MCP revision
2026-07-28; 2025-era clients are served statelessly).
Maciek's own agent (the Cloudflare Worker bro) also reads and writes his notes and transcribes his audio through a
private Cloudflare service binding. That path has no public URL and cannot be reached from the internet; it runs the same
code and limits as memo_write, memo_search and transcribe, and its notes show its own
client name as source.
| Tool | Input | Result | What it does |
|---|---|---|---|
memo_write | { text } | { id, created_at } |
Saves a text note (up to 20000 characters) exactly as written. |
memo_search | { query, limit? } | { notes: [{ id, text, created_at, source }] } |
Finds notes, newest first. Every query word must match the start of a word in the note; if none match, the whole
query is tried as a substring. An empty query lists the newest notes. source names the client that saved the note. |
upload | { filename, source_url?, content_type? } |
{ url, upload_url, expires_at, size } |
Puts a file (up to 20971520 bytes) under https://api.sitkowski.dev/files/, public by link. With source_url, bro copies
that file. Without it, the result has a one-time upload_url: the caller's code sends the bytes there with one HTTP PUT
within 15 minutes, so file contents never pass through the model. |
transcribe | { url, language? } | { segments: [{ start, end, text }] } |
Fetches audio from the URL and turns speech into timestamped text with Cloudflare Workers AI
(@cf/openai/whisper-large-v3-turbo). start and end are seconds. An upload link works as input. |
access_list | {} | { grants: [{ id, client, client_id, created_at, current }] } |
Lists every client Maciek has let in, newest first. |
access_revoke | { grant_id } | { revoked: { id, client, … } } |
Takes back one client's access: its tokens stop working at once. Notes and files it wrote stay. |
Every tool declares an output schema, and every successful result returns matching structuredContent.
The text content mirrors it: the same JSON, except transcribe, which gives one [start] text line per
segment so long audio stays small. Expected failures (bad URL, file too large, audio that cannot be read) come back as tool
results with isError: true and a message that says what to change.
https://api.sitkowski.dev/.well-known/oauth-protected-resource/mcp; authorization server metadata at
https://api.sitkowski.dev/.well-known/oauth-authorization-server.client_id) or register at https://api.sitkowski.dev/register
(dynamic client registration). PKCE with S256 is required. Tokens are bound to the resource https://api.sitkowski.dev/mcp (RFC 8707).access_revoke.The MEGA.dev course POSTs messages to https://api.sitkowski.dev/away. bro accepts only POSTs signed with the course's
key (x-course-timestamp, x-course-signature), answers 2xx at once, reads which acts a message asks for
with Workers AI, and replies on the message's reply URL. Free acts it does alone; gated acts wait up to 60 minutes for
Maciek, who gets a phone ping (ntfy) with a link to approve or decline. The acts are records in D1, not calls to real systems.
| Act | What it does | Policy |
|---|---|---|
post_status | post a status line to the team channel | free |
ack_alert | acknowledge an open alert | free |
archive_report | move a finished report into the archive | free |
purge_cache | clear the build cache | free |
release_hold | release a held deploy to production | gated |
rotate_key | rotate a shared API key | gated |
/away (raw body, signature, sender, text, reply URL), the acts
done, held acts with Maciek's decision and any code he entered, and the replies sent, in Cloudflare D1. Kept until Maciek deletes them.