@sendoka/dev-mcp
v0.7.0
Published
Keyless Model Context Protocol server for Sendoka — exposes public docs, OpenAPI schema, local validators, and dry-run helpers so AI coding assistants can explore the Sendoka API without an account.
Downloads
286
Maintainers
Readme
@sendoka/dev-mcp
Keyless Model Context Protocol server for Sendoka. Speaks MCP over stdio so any MCP-aware AI assistant (Claude Code, Cursor, Continue, Windsurf, etc.) can explore the Sendoka API without an account or key.
Mirrors the architecture pattern Shopify uses for @shopify/dev-mcp: ship as an npx package, expose only public surface (docs, OpenAPI schema, local validators), no remote infrastructure, no rate limits to worry about.
Install
claude mcp add sendoka-dev -- npx -y @sendoka/dev-mcp@latestFor other MCP clients, point them at the stdio command npx -y @sendoka/dev-mcp@latest.
What's included
| Tool | What it does |
| --- | --- |
| platform_overview | Start here. One-call functional map of the whole platform — capability areas (live from the API), auth model (keys, environments, scopes), conventions (ids, pagination, idempotency, errors, rate limits), and the webhook event catalog. |
| search_docs | Full-text search across the Sendoka developer docs. |
| read_doc | Read one guide in full, by slug or URL. |
| lookup_endpoint | Browse the public OpenAPI schema — list operations or zoom in on one, with $refs resolved inline. method, path and tag each narrow on their own. |
| lookup_error | Decode an error code (SENDER_NOT_VERIFIED, TENANT_NOT_USABLE, …) — HTTP status, type, meaning, and how to recover. Local table, no network call. |
| generate_snippet | Emit a copy-paste code sample for a Sendoka REST call (curl, node, python, go, ruby, php). |
| validate_payload | Check a send_sms / send_email body against the live OpenAPI schema plus the cross-field rules it cannot express — no API call. Reports unrecognised fields and what it could not check. |
| lint_message | Deliverability + compliance lints: TCPA opt-out, RFC 8058 unsubscribe, GSM-7 vs UCS-2, multi-segment SMS, spammy subjects. |
| normalize_phone | Canonicalize a phone number to E.164 with country flags (India DLT, UK alphanumeric, US 10DLC). |
| parse_email | Parse a Name <addr@x> string; surface role addresses, free providers, plus-addressing, suspicious TLDs. |
| render_template_dry | Preview a template render (subject + html + text) with the given variables — the same renderer Sendoka sends with, so {{var}}, dotted paths and {{#each}} / {{#if}} blocks all preview as they will send. |
| dry_run_send | One-shot pre-flight: schema validation + content lint + recipient parsing. Returns ready: true/false. |
What the local checks can and cannot tell you
validate_payload and dry_run_send run entirely locally, so they are fast and
keyless — and that bounds what they can prove.
They do check the live SendEmail / SendSms schema (field names, types,
formats, lengths, caps, fields the API rejects outright) and the cross-field
rules the schema cannot express: from XOR from_pool, subject XOR
template, the India DLT requirement for +91, scheduled_local needing
scheduled_at_tz, and the single-recipient rule for {{unsubscribe_url}}.
They cannot check anything that depends on account state: whether your
sending domain or number is verified, whether a recipient is suppressed, whether
your plan has quota left, or whether a template slug resolves. ready: true
means "no local check failed" — never "this send will succeed". Both tools list
this under not_checked on every response.
An unrecognised field is reported, not rejected. The API ignores unknown
keys, so a body carrying one still sends. That also means acceptance here is
never evidence a capability exists — if you are probing whether Sendoka supports
some field, unknown_fields is the answer, not valid.
Every tool runs locally or against the public documentation endpoints. None ever touch workspace data.
When to use this MCP vs the authenticated one
| Use case | Server |
| --- | --- |
| Learning the API, finding the right endpoint, generating sample code | dev-mcp (this one) |
| Linting a draft before sending | dev-mcp |
| Actually sending an SMS / email / audience blast | authenticated MCP — requires Authorization: Bearer sok_live_* |
| Reading workspace activity, usage, suppressions | authenticated MCP |
The agent can have both connected at once. Pattern after a typical session: search docs → look up endpoint → generate snippet → validate payload → lint → dry-run — and only then switch to the authenticated MCP to actually send.
Environment
| Variable | Default | Purpose |
| --- | --- | --- |
| SENDOKA_DEV_BASE | https://www.sendoka.com | Override to point at a self-hosted Sendoka deployment or a local dev server. |
Architecture
- Single
dist/cli.jsbinary; ~14 KB pure-Node TypeScript output, zero npm dependencies. - Line-delimited JSON-RPC 2.0 over stdin/stdout.
- OpenAPI schema is fetched once and cached in-process for 15 minutes.
- No telemetry, no remote calls except
/api/openapi.jsonand/api/docs/search.
Source
This package ships from the monorepo at packages/dev-mcp/.
