{"_id":"@breaker-email/mcp","_rev":"5-a4e9fefb206f2ca498f2e64af186c309","name":"@breaker-email/mcp","dist-tags":{"latest":"0.1.5"},"versions":{"0.1.0":{"name":"@breaker-email/mcp","version":"0.1.0","_id":"@breaker-email/mcp@0.1.0","maintainers":[{"name":"robswei","email":"hello@robswei.com"},{"name":"dev-volumeapps","email":"dev@volumeapps.com"}],"bin":{"breaker-mcp":"dist/index.js"},"dist":{"shasum":"173e8020c3949485f7c4676b3553d00293815f09","tarball":"https://registry.npmjs.org/@breaker-email/mcp/-/mcp-0.1.0.tgz","fileCount":20,"integrity":"sha512-a/zpKJfJfsFsqFzpIIiu+2iyjGyamlrG4hOaJ7Zz7AE0kWdV5rO9zuKjMnm7LFtzQmdaz+rHl073BLdj1s7Qmg==","signatures":[{"sig":"MEUCIQDxtDSuOMXDg4WkIum2JQ3Q9riu9WtJDSofTV9PKi0OPQIgZdOQJokVC6fao8K70Op0HSQhSJFdCAZIvh7we+KXdOs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":70545},"main":"./dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"792f6aeb8d101a3eb844e189878fb9bb7175b4d2","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"tsc","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"dev-volumeapps","email":"dev@volumeapps.com"},"_npmVersion":"10.9.2","description":"MCP server for the Breaker public API","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^4.5.4","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.5.1","js-yaml":"^4.3.2","ts-jest":"^29.4.12","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^26.4.1","@types/js-yaml":"^4.0.9"},"_npmOperationalInternal":{"tmp":"tmp/mcp_0.1.0_1788966832848_0.34077015698695323","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@breaker-email/mcp","version":"0.1.1","keywords":["mcp","model-context-protocol","email","newsletter","claude","cursor","codex"],"_id":"@breaker-email/mcp@0.1.1","maintainers":[{"name":"robswei","email":"hello@robswei.com"},{"name":"dev-volumeapps","email":"dev@volumeapps.com"}],"homepage":"https://docs.breaker.email","bin":{"breaker-mcp":"dist/index.js"},"dist":{"shasum":"9a424f2c780254281404d43661b074e29082a53c","tarball":"https://registry.npmjs.org/@breaker-email/mcp/-/mcp-0.1.1.tgz","fileCount":22,"integrity":"sha512-JrHCfFlriGi+oiL8BcqqTpuS8hOT0uQV36/ytANjMUMhRweSurpuyVp+00r9SCi4a/5CREO9/DQbx7QYNbAjoA==","signatures":[{"sig":"MEUCIF7920e9unWjmHPngFre5cEE3lpJWS/HTXTVU8toYmY4AiEAk5L8g9w1wA2fw4l5AYPEulN89p7Rp+E5xjGWOqxGwNg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIH9Opr58L6Oj04j50QLLUVrBLneTzbgSxzozMArxjAadAiACJgxymJrx9JhguniUEIZQwHgtdfyjM6P0r6AW35a55g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76311},"main":"./dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"8f3b5d5bf34e473ac9aaeae4aee48ee8490c0c16","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"tsc","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"dev-volumeapps","email":"dev@volumeapps.com"},"_npmVersion":"10.9.2","description":"MCP server for working with your Breaker newsletter at app.breaker.email, over the public API documented at docs.breaker.email","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^4.5.4","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.5.1","js-yaml":"^4.3.2","ts-jest":"^29.4.12","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^26.4.1","@types/js-yaml":"^4.0.9"},"_npmOperationalInternal":{"tmp":"tmp/mcp_0.1.1_1789046400454_0.9840324808667305","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@breaker-email/mcp","version":"0.1.2","keywords":["mcp","model-context-protocol","email","newsletter","claude","cursor","codex"],"_id":"@breaker-email/mcp@0.1.2","maintainers":[{"name":"robswei","email":"hello@robswei.com"},{"name":"dev-volumeapps","email":"dev@volumeapps.com"}],"homepage":"https://docs.breaker.email","bin":{"breaker-mcp":"dist/index.js","breaker-mcp-http":"dist/http.js"},"dist":{"shasum":"6ab9feacb312bd7a9ad6aac9754e28efae7c758c","tarball":"https://registry.npmjs.org/@breaker-email/mcp/-/mcp-0.1.2.tgz","fileCount":32,"integrity":"sha512-Kw0mU7jULUm1ljBYigouiccktlzPWrXdZro62+HCXOsUCDgsX/hHZ2P8kC0jWxuO6Aa3GoXn7XTPF7czg0PM2A==","signatures":[{"sig":"MEUCICy1okiLwH+N3FByAjOY7fF/HRdo/+Ri7+ZasspKTB+ZAiEAjsMPnsTrpSv5dTgoN4P/bpn6qFSri3kEFZrg3xqwGfo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQD6XnKFzarZM7n+4PEnBQ4AztZ7U2TFGedq1MTQWr5XwAIhAKtihXSIQQrdWEAQV1btYdK0YJJHoli1cQFqqrWFjprM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":143804},"main":"./dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"6a382849dba33aa35bf54ce6a62b0846019b5503","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"tsc","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"dev-volumeapps","email":"dev@volumeapps.com"},"_npmVersion":"10.9.2","description":"MCP server for working with your Breaker newsletter at app.breaker.email, over the public API documented at docs.breaker.email","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^4.5.4","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.5.1","js-yaml":"^4.3.2","ts-jest":"^29.4.12","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^26.4.1","@types/js-yaml":"^4.0.9"},"_npmOperationalInternal":{"tmp":"tmp/mcp_0.1.2_1789660823422_0.9656260512479073","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@breaker-email/mcp","version":"0.1.3","keywords":["mcp","model-context-protocol","email","newsletter","claude","cursor","codex"],"_id":"@breaker-email/mcp@0.1.3","maintainers":[{"name":"robswei","email":"hello@robswei.com"},{"name":"dev-volumeapps","email":"dev@volumeapps.com"}],"homepage":"https://docs.breaker.email","bin":{"breaker-mcp":"dist/index.js"},"dist":{"shasum":"218475a7988e420d83c60727f7d21b43774c017b","tarball":"https://registry.npmjs.org/@breaker-email/mcp/-/mcp-0.1.3.tgz","fileCount":32,"integrity":"sha512-CPdLdCHrh+PQxWAihBcPzjP0/lA+h7MYKC7meEcWoSxK1ezUy2P4SBWscmzzU6vLhIdx1egzRKGEnVz80KRnUw==","signatures":[{"sig":"MEYCIQCyPRHfIuJb0hpvZn76Q3z1GwowuGv6WY29+ROa3NZMcgIhAJLZ1ukAppfi8PbdNcOrqFjXtyL3XGNTVrX4QAK9uoVP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIEW6WOl62O61qlewf6bZFWzkYKeTnq22YqbGeCwhDiwUAiEA2aPLGDVvTkHH31b+TZnwVcAyT0wEWIPWigF8L1BUDgI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":143917},"main":"./dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"edf63742efadddbc36dc60421209d05e3967e15f","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"tsc","prepack":"npm run build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"dev-volumeapps","email":"dev@volumeapps.com"},"_npmVersion":"10.9.2","description":"MCP server for working with your Breaker newsletter at app.breaker.email, over the public API documented at docs.breaker.email","directories":{},"_nodeVersion":"22.14.0","dependencies":{"zod":"^4.5.4","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.5.1","js-yaml":"^4.3.2","ts-jest":"^29.4.12","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^26.4.1","@types/js-yaml":"^4.0.9"},"_npmOperationalInternal":{"tmp":"tmp/mcp_0.1.3_1789732329696_0.6163376064743953","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"_id":"@breaker-email/mcp@0.1.5","bin":{"breaker-mcp":"dist/index.js"},"dist":{"shasum":"19264c836c5053ac529d6ee3476e89abeef38f12","tarball":"https://registry.npmjs.org/@breaker-email/mcp/-/mcp-0.1.5.tgz","fileCount":34,"integrity":"sha512-7QX8wKlXFJQHlrThtWxIYSvTiTJwCVwinfo2ssMP+SZA2MBpaiqkTgVPnlaUjyfPWSZVbEtgJuSIL0+/SY3OBg==","signatures":[{"sig":"MEUCIQDjZagqO2DVvF/r3CXu8tDOXmFmqxavY4S+eeAZsEP+vAIgQxrbfHhpQpZR4l4TS5qr9D1jVv76YR74qEGPFTdz61E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHVuechwTLHrvs8QHywmeyWjZjkrqVMUSVWlKA5KdNK6AiEAjsXuTjX/lBN/n57h/wkjN2tLO9wWpVJ9cmIP10Vz038="}],"unpackedSize":158380},"main":"./dist/index.js","name":"@breaker-email/mcp","type":"module","engines":{"node":">=20"},"gitHead":"572fa289b2d6b5c06ae121aac112ed8062796e8f","scripts":{"test":"NODE_OPTIONS=--experimental-vm-modules jest","build":"tsc","prepack":"npm run build","typecheck":"tsc --noEmit"},"version":"0.1.5","_npmUser":{"name":"dev-volumeapps","email":"dev@volumeapps.com"},"homepage":"https://docs.breaker.email","keywords":["mcp","model-context-protocol","email","newsletter","claude","cursor","codex"],"_npmVersion":"10.9.2","description":"MCP server for working with your Breaker newsletter at app.breaker.email, over the public API documented at docs.breaker.email","directories":{},"maintainers":[{"name":"robswei","email":"hello@robswei.com"},{"name":"dev-volumeapps","email":"dev@volumeapps.com"}],"_nodeVersion":"22.14.0","dependencies":{"zod":"^4.5.4","@modelcontextprotocol/server":"^2.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.5.1","js-yaml":"^4.3.2","ts-jest":"^29.4.12","typescript":"^6.0.3","@types/jest":"^30.0.0","@types/node":"^26.4.1","@types/js-yaml":"^4.0.9"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp_0.1.5_1790697184899_0.07893861968441773"}}},"time":{"created":"2026-09-09T15:13:52.634Z","modified":"2026-09-29T15:53:05.174Z","0.1.0":"2026-09-09T15:13:52.980Z","0.1.1":"2026-09-10T13:20:00.637Z","0.1.2":"2026-09-17T16:00:23.516Z","0.1.3":"2026-09-18T11:52:09.778Z","0.1.5":"2026-09-29T15:53:04.998Z"},"homepage":"https://docs.breaker.email","keywords":["mcp","model-context-protocol","email","newsletter","claude","cursor","codex"],"description":"MCP server for working with your Breaker newsletter at app.breaker.email, over the public API documented at docs.breaker.email","maintainers":[{"name":"robswei","email":"hello@robswei.com"},{"name":"dev-volumeapps","email":"dev@volumeapps.com"}],"readme":"# @breaker-email/mcp\n\nAn MCP server for the Breaker public API. It lets Claude and other MCP clients read your\nreporting, manage contacts and segments, and draft campaigns and automations, using the same\nREST API documented at [docs.breaker.email](https://docs.breaker.email).\n\nThis is a client of that API and nothing more. It holds no data and adds no behaviour of\nits own. Anything the API refuses, this refuses too.\n\nManage your newsletter and create API keys at\n[app.breaker.email](https://app.breaker.email).\n\n## Before you start\n\nCreate an API key at [app.breaker.email](https://app.breaker.email) under **Settings** then\n**API Keys**. A key looks like `bk_live_...` and belongs to one newsletter, so create one\nkey per newsletter you want to reach.\n\nMost clients run the server on your own machine over stdio, launched by `npx`: the key in\nyour client's config is the whole of the authentication, and there is no browser sign-in.\n\nWeb clients that connect to a URL rather than launching a program, such as claude.ai, use\nBreaker's hosted endpoint instead and need no key:\n\n```text\nhttps://api.breaker.email/mcp\n```\n\nAdd it as a remote MCP server or connector and sign in with your Breaker account when the\nclient asks. The sign-in picks one newsletter. The connection is listed, and can be\nremoved, in the app under **Settings**, **Integrations**, **AI Clients**. To host the\nsame endpoint yourself, see [Run it as a server](#run-it-as-a-server).\n\n## Install with your AI assistant\n\nPaste this to any AI coding assistant and it will do the rest.\n\n```text\nSet up the Breaker MCP server for me.\n\nBreaker is an email newsletter platform. This MCP server runs locally over stdio\nvia npx and authenticates with an API key — there is no browser sign-in and no\nhosted endpoint.\n\n1. Ask me for my Breaker API key before you write any config. It looks like\n   bk_live_... . If I don't have one, tell me to create it at\n   https://app.breaker.email under Settings then API Keys, and wait for me. You\n   cannot create a key yourself.\n\n2. Work out which MCP client you are running in and register the server using\n   that client's own method, named \"breaker\", at user scope where the client\n   has one.\n\n   Claude Code:\n     claude mcp add breaker --scope user \\\n       --env BREAKER_API_KEY=bk_live_my_key_here \\\n       -- npx -y @breaker-email/mcp\n\n   Codex:\n     codex mcp add breaker --env BREAKER_API_KEY=bk_live_my_key_here \\\n       -- npx -y @breaker-email/mcp\n\n   Any other client — add this to its MCP config file:\n     {\n       \"mcpServers\": {\n         \"breaker\": {\n           \"command\": \"npx\",\n           \"args\": [\"-y\", \"@breaker-email/mcp\"],\n           \"env\": { \"BREAKER_API_KEY\": \"bk_live_my_key_here\" }\n         }\n       }\n     }\n\n   VS Code uses the same shape under a \"servers\" key rather than \"mcpServers\".\n\n   BREAKER_API_KEY is required. Put the key in the env block — for a stdio\n   server this is the correct mechanism, not a workaround.\n\n3. Confirm it worked before calling it done. Check the breaker tools are listed,\n   then call newsletter_get, which takes no arguments and only reads. Tell me\n   which newsletter it returned. A 401 means the key is wrong or revoked — tell\n   me, don't retry. During setup, never call a tool that creates, updates or\n   deletes anything.\n\n4. A Breaker API key belongs to one newsletter. Once you know the name, offer to\n   rename the server to breaker-<newsletter> — lowercase, spaces and punctuation\n   replaced with dashes, so \"Founders' Brief (EU)\" becomes\n   breaker-founders-brief-eu. Useful if I run more than one newsletter. Only\n   rename if I say yes, and do it by removing and re-adding the server with the\n   same key.\n```\n\n## Install it yourself\n\n### Claude Code\n\n```bash\nclaude mcp add breaker --scope user --env BREAKER_API_KEY=bk_live_your_key_here -- npx -y @breaker-email/mcp\n```\n\nRunning more than one newsletter? Give each key its own server, named apart:\n\n```bash\nclaude mcp add breaker-my-digest --scope user --env BREAKER_API_KEY=bk_live_first_key -- npx -y @breaker-email/mcp\nclaude mcp add breaker-eu-brief --scope user --env BREAKER_API_KEY=bk_live_second_key -- npx -y @breaker-email/mcp\n```\n\n<details>\n<summary>Or edit the config file directly</summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"breaker\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@breaker-email/mcp\"],\n      \"env\": { \"BREAKER_API_KEY\": \"bk_live_your_key_here\" }\n    }\n  }\n}\n```\n\n</details>\n\n### Codex\n\n```bash\ncodex mcp add breaker --env BREAKER_API_KEY=bk_live_your_key_here -- npx -y @breaker-email/mcp\n```\n\nRunning more than one newsletter? Give each key its own server, named apart:\n\n```bash\ncodex mcp add breaker-my-digest --env BREAKER_API_KEY=bk_live_first_key -- npx -y @breaker-email/mcp\ncodex mcp add breaker-eu-brief --env BREAKER_API_KEY=bk_live_second_key -- npx -y @breaker-email/mcp\n```\n\n<details>\n<summary>Or edit <code>~/.codex/config.toml</code> directly</summary>\n\nCodex stores its config as TOML, not JSON.\n\n```toml\n[mcp_servers.breaker]\ncommand = \"npx\"\nargs = [\"-y\", \"@breaker-email/mcp\"]\n\n[mcp_servers.breaker.env]\nBREAKER_API_KEY = \"bk_live_your_key_here\"\n```\n\n</details>\n\n### Cursor\n\nAdd this to `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"breaker\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@breaker-email/mcp\"],\n      \"env\": { \"BREAKER_API_KEY\": \"bk_live_your_key_here\" }\n    }\n  }\n}\n```\n\nRunning more than one newsletter? Name each server `breaker-<newsletter>` and give it that\nnewsletter's own key.\n\n### Claude Desktop\n\nOpen **Settings**, **Developer**, **Edit Config**, and add:\n\n```json\n{\n  \"mcpServers\": {\n    \"breaker\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@breaker-email/mcp\"],\n      \"env\": { \"BREAKER_API_KEY\": \"bk_live_your_key_here\" }\n    }\n  }\n}\n```\n\nRestart Claude Desktop afterwards. Running more than one newsletter? Name each server\n`breaker-<newsletter>` and give it that newsletter's own key.\n\n### VS Code\n\nAdd this to `.vscode/mcp.json` in your workspace, or to your user config via the\n**MCP: Open User Configuration** command. Note the key is `servers`, not `mcpServers`:\n\n```json\n{\n  \"servers\": {\n    \"breaker\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@breaker-email/mcp\"],\n      \"env\": { \"BREAKER_API_KEY\": \"bk_live_your_key_here\" }\n    }\n  }\n}\n```\n\nRunning more than one newsletter? Name each server `breaker-<newsletter>` and give it that\nnewsletter's own key.\n\n<details>\n<summary>Any other MCP client</summary>\n\nAny client that speaks MCP over stdio can run this server. Point it at\n`npx -y @breaker-email/mcp` with `BREAKER_API_KEY` in the environment:\n\n```json\n{\n  \"mcpServers\": {\n    \"breaker\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@breaker-email/mcp\"],\n      \"env\": { \"BREAKER_API_KEY\": \"bk_live_your_key_here\" }\n    }\n  }\n}\n```\n\nIf you would rather not work out where your client keeps that file, paste the prompt from\n[Install with your AI assistant](#install-with-your-ai-assistant) into the assistant itself\nand let it find out.\n\n</details>\n\n## Run it as a server\n\nWeb-based clients cannot launch a process, so they need an endpoint to connect to. The same\npackage serves the same tools over HTTP. It is not a second executable, so `npx` keeps\nresolving the package to the stdio server; install it and run the file:\n\n```sh\nnpm install @breaker-email/mcp\nMCP_PUBLIC_URL=https://mcp.example.com/mcp node node_modules/@breaker-email/mcp/dist/http.js\n```\n\nEvery request carries its own credential in an `Authorization: Bearer` header, so one\nserver serves many callers and holds no key of its own. A request without a usable\ncredential is refused with `401` and a `WWW-Authenticate` challenge naming where to sign\nin. `GET /healthz` reports the version and tool count.\n\n| Variable | | |\n| --- | --- | --- |\n| `MCP_PUBLIC_URL` | required | The URL callers reach this endpoint on. Published as the resource identifier. |\n| `PORT` | optional | Defaults to `8790`. |\n| `BREAKER_API_URL` | optional | As below. |\n| `MCP_AUTHORIZATION_SERVER` | optional | The issuer to advertise for browser sign-in. Set it once an authorization server is in place; until then the endpoint serves callers that send a Breaker API key as the bearer credential. |\n\n## Configuration\n\n`BREAKER_API_KEY` is required by the stdio server; the HTTP server takes the credential\nfrom each request instead. `BREAKER_API_URL` is optional for both and defaults to\n`https://api.breaker.email/v1/public`. Set it to point at a development stack.\n\n## What it can do\n\n42 tools covering the API surface.\n\n- **Newsletter.** Read which newsletter the API key belongs to.\n- **Campaigns.** List and read campaigns, create a draft, change its title, subject and\n  preview text, read and replace its body, and preview the rendered email. The write tool\n  spells out the markup the Breaker editor adopts as real blocks, so an assistant can lay\n  out columns, buttons, images, dividers and merge tags that stay editable in the app.\n- **Automations.** List and read the triggered emails new contacts receive, create one for\n  an audience or a signup form, change its settings, read and replace its body, and preview\n  it. Switching one on stays with a person in the app, and deleting one is withheld.\n- **Reports.** Newsletter and per-campaign totals over a date window, per-contact\n  engagement, links and who clicked them, subscriber count and unsubscribes.\n- **Segments.** List and read segments, create one from a fixed list of contacts or from\n  rules, read and replace a dynamic segment's rules, add contacts to a static one, and\n  recalculate a dynamic one. The rule format is spelled out in the tool schema, so an\n  assistant can build \"opened something in the last 30 days and tagged VIP\" in one call.\n- **Contacts.** Create, find, read and update contacts, add and remove tags, read status\n  and per-campaign engagement, and list tags, custom fields and signup forms.\n\n## Development\n\n```bash\nnpm install\nnpm run build\nnpm test\nnpm run typecheck\n```\n\n`src/__tests__/toolSpecDrift.test.ts` checks the tool list against\n`backend/openapi/public.yaml`. Every operation in the spec has to be either exposed as a\ntool or listed as withheld with a reason, so an endpoint added to the API cannot be quietly\nignored here. This is why the package lives in the same repository as the spec.\n","readmeFilename":"README.md"}