Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules
dist
build
dist-mcpb
test
.git
.github
*.md
*.mcpb
.env*
15 changes: 14 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,20 @@ jobs:
cache: npm
- run: npm ci
- run: npm run build
- name: Mock integration tests
- name: Mock integration tests (stdio)
run: node test/e2e.mjs
- name: Mock integration tests (streamable HTTP)
run: node test/http-test.mjs
- name: Mock integration tests (OAuth / lazy auth)
run: node test/oauth-test.mjs
- name: Live spec-discovery test
run: node test/discovery-test.mjs
- name: Validate desktop-extension manifest
run: npx mcpb validate manifest.json
- name: Build desktop extension (.mcpb)
run: npm run build:mcpb
- uses: actions/upload-artifact@v4
with:
name: kudosity-mcp-mcpb
path: dist-mcpb/*.mcpb
if-no-files-found: error
26 changes: 26 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Release assets

# When a GitHub Release is published, build the Claude Desktop extension and
# attach it to the release so users can download kudosity-mcp-<version>.mcpb.
on:
release:
types: [published]

permissions:
contents: write

jobs:
mcpb:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build:mcpb
- name: Attach .mcpb to the release
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "${{ github.event.release.tag_name }}" dist-mcpb/*.mcpb --clobber
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@ test/get.mjs
test/infra-test.mjs
test/lists-test.mjs
test/tier1-discovery-test.mjs

# MCPB staging + bundles
build/
dist-mcpb/
*.mcpb
16 changes: 16 additions & 0 deletions .mcpbignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Only dist/, node_modules/, manifest.json, package.json, icon.png, LICENSE and README.md belong in the bundle.
# scripts/build-mcpb.sh stages exactly those; this file covers a direct `mcpb pack .`.
src
test
scripts
.github
build
dist-mcpb
*.mcpb
tsconfig.json
server.json
smithery.yaml
glama.json
Dockerfile
.dockerignore
CHANGELOG.md
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.6.0

Remote transport + Claude Desktop extension, built for the Claude Connectors Directory.

- **Streamable HTTP transport** (`kudosity-mcp-http` / `node dist/http.js`): a stateless remote MCP server. Credentials are read per request from `Authorization: Basic key:secret`, `Authorization: Bearer key` or `x-api-key` (+ `x-api-secret`) and never stored. Without credentials the server initialises, lists tools and runs the discovery tools; API tools return instructions for adding the header.
- **Claude Desktop extension** (`.mcpb`): `manifest.json` + `npm run build:mcpb`. API key and secret are entered in the extension's settings (stored by Claude Desktop, masked), not pasted into chat.
- **Dockerfile** for hosting the HTTP server; `GET /healthz`.
- Tool factory refactor (`src/server.ts`) shared by both transports; no tool changes except annotations and wording:
- `send_sms`, `send_mms`, `send_whatsapp` now carry `destructiveHint: true` — sending is billable and irreversible, so clients ask before calling.
- Discovery tool descriptions name the API reference they query and say no credentials are needed.
- Secret-requiring tools say "Requires your API secret" instead of naming an environment variable.
- New test `test/http-test.mjs` (mock APIs, no network); CI validates the MCPB manifest and builds the bundle.

## 0.5.0

Initial public release.
Expand Down
19 changes: 19 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Remote (Streamable HTTP) Kudosity MCP server.
# docker build -t kudosity-mcp . && docker run -p 8080:8080 kudosity-mcp
# Credentials are supplied per request via headers — see README "Remote server".
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json tsconfig.json ./
COPY src ./src
RUN npm ci --ignore-scripts --no-audit --no-fund && npm run build && npm prune --omit=dev

FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production PORT=8080 HOST=0.0.0.0
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY package.json ./
USER node
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://127.0.0.1:8080/healthz >/dev/null || exit 1
CMD ["node", "dist/http.js"]
136 changes: 118 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# Kudosity MCP Server

An installable [Model Context Protocol](https://modelcontextprotocol.io) server that gives AI agents native tools to send **SMS, MMS and WhatsApp** messages, manage contacts and webhooks, and research the Kudosity API — powered by [Kudosity](https://kudosity.com).
A [Model Context Protocol](https://modelcontextprotocol.io) server that gives AI agents native tools to send **SMS, MMS and WhatsApp** messages, manage contacts and webhooks, and research the Kudosity API — powered by [Kudosity](https://kudosity.com).

Runs locally (or in your own infrastructure), authenticates with your Kudosity API key, and exposes one clean tool per action — so an agent calls `send_sms` instead of hand-building HTTP requests.
One tool per action — an agent calls `send_sms` instead of hand-building HTTP requests. Three ways to run it:

| | Best for | Credentials |
|---|---|---|
| **Local (`npx kudosity-mcp`)** | Claude Code, Cursor, VS Code, Gemini CLI, any stdio client | environment variables |
| **Claude Desktop extension (`.mcpb`)** | One-click install in Claude Desktop | entered once in the extension's settings |
| **Remote (Streamable HTTP)** | claude.ai / Claude mobile, team-wide connectors, hosted agents | OAuth sign-in, or a request header |

## Tools

Expand All @@ -16,6 +22,8 @@ Runs locally (or in your own infrastructure), authenticates with your Kudosity A
| `get_message` | read | Get a sent message and its status by channel + ID |
| `list_messages` | read | List sent/received messages with delivery status; filter by status, direction (sent/replies), recipient, dates |

Sending is billable and irreversible, so the three `send_*` tools are annotated `destructiveHint: true` — Claude and other clients ask before calling them.

**Webhooks**

| Tool | Type | Description |
Expand All @@ -24,7 +32,7 @@ Runs locally (or in your own infrastructure), authenticates with your Kudosity A
| `list_webhooks` | read | List configured webhooks |
| `delete_webhook` | write | Delete a webhook by ID |

**Contacts & lists** *(require `KUDOSITY_API_SECRET`)*
**Contacts & lists** *(need the API secret as well as the key)*

| Tool | Type | Description |
|---|---|---|
Expand All @@ -35,13 +43,13 @@ Runs locally (or in your own infrastructure), authenticates with your Kudosity A
| `remove_contact_from_list` | write | Remove a contact from a list |
| `delete_list` | write | Delete a contact list |

**Account** *(requires `KUDOSITY_API_SECRET`)*
**Account** *(needs the API secret)*

| Tool | Type | Description |
|---|---|---|
| `get_balance` | read | Get your account balance |

**API discovery** — research the whole Kudosity API, always current
**API discovery** — research the whole Kudosity API, always current, **no credentials needed**

| Tool | Type | Description |
|---|---|---|
Expand All @@ -54,15 +62,21 @@ The discovery tools read the live specs from `developers.kudosity.com`, so they

## Requirements

- Node.js 18+
- A Kudosity account and API key — **Settings → API Settings** in the Kudosity platform
- For contact and balance tools, also your API **secret** (same settings page)
- Node.js 18+ for the local and self-hosted options (Claude Desktop bundles its own)

## Install & configure

Runs via `npx` — no clone required.
### Claude Desktop — extension (one click)

### Claude Desktop / Claude Code
1. Download `kudosity-mcp-<version>.mcpb` from the [latest release](https://github.com/kudosity/mcp/releases/latest).
2. Open it with Claude Desktop (double-click, or drag it onto **Settings → Extensions**).
3. Enter your Kudosity API key, and optionally the API secret. Claude Desktop stores them for you; they are never pasted into a chat.

To build the extension yourself: `npm run build:mcpb` → `dist-mcpb/kudosity-mcp-<version>.mcpb`.

### Claude Desktop / Claude Code — `npx`

```json
{
Expand All @@ -79,6 +93,8 @@ Runs via `npx` — no clone required.
}
```

Or from the terminal: `claude mcp add kudosity -e KUDOSITY_API_KEY=your_api_key -- npx -y kudosity-mcp`

`KUDOSITY_API_SECRET` is optional — omit it if you only need messaging, webhooks, and discovery. It's required for the contact-list and balance tools.

### Cursor — `.cursor/mcp.json`
Expand Down Expand Up @@ -109,6 +125,73 @@ Runs via `npx` — no clone required.
}
```

## Remote server (Streamable HTTP)

The same 19 tools as a stateless remote MCP server — for claude.ai, Claude mobile, org-wide connectors, and hosted agents. Start it with `kudosity-mcp-http` (or `node dist/http.js`, or the [Dockerfile](./Dockerfile)); it serves MCP at `/mcp` and a health check at `/healthz`.

Credentials are supplied **per request** and never stored on the server. There are two ways to supply them.

### A. OAuth sign-in (Claude "Connect" button)

When `KUDOSITY_MCP_PUBLIC_URL` and `KUDOSITY_MCP_TOKEN_KEY` are set, the server also acts as a small OAuth 2.1 authorization server:

- Anyone can connect and use the discovery tools without signing in.
- The first time a tool needs your account, Claude shows a **Connect** card. You enter your Kudosity API key (and optional secret) on a consent page served from this server's domain — never in the chat.
- The key is verified with Kudosity, then sealed into an encrypted access token that Claude sends on later requests. The server holds no user data: rotating `KUDOSITY_MCP_TOKEN_KEY` invalidates every token.

Supports Dynamic Client Registration and Client ID Metadata Documents, PKCE (S256), refresh tokens, and the Claude Code loopback redirect. Discovery documents live at `/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server`.

Add it in Claude as a custom connector with just the server URL (**Settings → Connectors → Add custom connector**), or in Claude Code:

```bash
claude mcp add --transport http kudosity https://<your-host>/mcp
```

### B. Request header (no sign-in)

For a connector your whole team shares, or for scripts and tools that can set headers, send the credentials on every request:

| Header | Value | Covers |
|---|---|---|
| `Authorization` | `Basic <base64 of API_KEY:API_SECRET>` — leave the secret empty (`API_KEY:`) if you don't need lists/balance | everything |
| `x-api-key` (+ `x-api-secret`) | the raw key (and secret) | everything |
| `Authorization` | `Bearer API_KEY` | messaging, webhooks, reporting (header-only mode, i.e. when OAuth is not enabled) |

In Claude: **Add custom connector → No sign-in → Request headers**, header `authorization`, value `Basic …`. In Claude Code:

```bash
claude mcp add --transport http kudosity https://<your-host>/mcp \
--header "Authorization: Basic $(printf '%s:%s' "$KUDOSITY_API_KEY" "$KUDOSITY_API_SECRET" | base64)"
```

Without credentials the server still initialises and lists tools; discovery works, and tools that need your account return an error explaining how to add the header (or, in OAuth mode, start the sign-in).

### Self-hosting

```bash
npm install -g kudosity-mcp
PORT=8080 kudosity-mcp-http
# or
docker build -t kudosity-mcp . && docker run -p 8080:8080 -e KUDOSITY_MCP_PUBLIC_URL=https://mcp.example.com -e KUDOSITY_MCP_TOKEN_KEY="$(openssl rand -base64 32)" kudosity-mcp
```

Put it behind HTTPS (Claude only connects to `https://`). Then verify:

```bash
curl -s https://<your-host>/healthz
curl -s https://<your-host>/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

| Env var | Default | Description |
|---|---|---|
| `PORT` / `HOST` | `8080` / `0.0.0.0` | Listen address |
| `KUDOSITY_MCP_PATH` | `/mcp` | MCP endpoint path |
| `KUDOSITY_MCP_PUBLIC_URL` | — | Public origin, e.g. `https://mcp.example.com`. Enables OAuth together with the token key. |
| `KUDOSITY_MCP_TOKEN_KEY` | — | Secret used to encrypt tokens (`openssl rand -base64 32`). Rotate to revoke all tokens. |
| `KUDOSITY_MCP_CONSENT_RATE_LIMIT` | `10` | Consent-page submissions per IP per minute |
| `KUDOSITY_HTTP_ALLOW_ENV_CREDENTIALS` | unset | `true` lets requests without credentials fall back to `KUDOSITY_API_KEY`/`_SECRET` from the server's environment. **Single-tenant only** — never on a shared or public host. |

## Usage examples

- *"Send an SMS to 61438333061 from KudosityDemo saying the order shipped."*
Expand All @@ -123,14 +206,15 @@ Runs via `npx` — no clone required.

Kudosity has two API surfaces, and this server uses each where it's authoritative:

| Tools | Auth | Credentials |
| Tools | Kudosity auth | Credentials |
|---|---|---|
| Messaging, webhooks, discovery | `x-api-key` header | `KUDOSITY_API_KEY` |
| Contact lists, balance | HTTP Basic | `KUDOSITY_API_KEY` + `KUDOSITY_API_SECRET` |
| Messaging, webhooks, reporting | `x-api-key` header | API key |
| Contact lists, balance | HTTP Basic | API key + API secret |
| API discovery | none | — |

Credentials are read from environment variables and never written to disk. Treat them as secrets.
Locally, credentials are read from environment variables (or the extension's settings) and never written to disk. Remotely, they arrive per request in a header or an encrypted OAuth token, are used for that request, and are discarded. Treat them as secrets.

## Configuration
## Configuration (local)

| Env var | Required | Default | Description |
|---|---|---|---|
Expand All @@ -139,21 +223,37 @@ Credentials are read from environment variables and never written to disk. Treat
| `KUDOSITY_API_BASE_URL` | no | `https://api.transmitmessage.com` | Override the v2 API base URL |
| `KUDOSITY_V1_BASE_URL` | no | `https://api.transmitsms.com` | Override the v1 API base URL |

## Privacy Policy

This software is a thin client for the Kudosity API. What it does with your data:

- **What it collects.** Only the inputs you give a tool — recipient numbers, message text, media URLs, list and webhook details — and the API credentials you supply. It reads nothing else from your device, your files, or your conversation.
- **How it is used and stored.** Inputs are sent to the Kudosity API over HTTPS to perform the requested action, and the API's response is returned to your AI client. The server stores nothing: no database, no logs of message content or credentials. Locally, credentials live in environment variables or your client's settings store. Remotely, they are carried in the request (a header, or an encrypted OAuth token that only the server's key can open) and discarded when the request completes.
- **Third parties.** Data goes to Kudosity's API (`api.transmitmessage.com`, `api.transmitsms.com`) and, for the discovery tools, public API specifications are fetched from `developers.kudosity.com`. Nothing is sent anywhere else. No analytics or telemetry.
- **Retention.** None by this software. Messages, contacts and account data are retained by Kudosity under the [Kudosity Privacy Policy](https://kudosity.com/legal/privacy-policy).
- **Contact.** [help.kudosity.com](https://help.kudosity.com) or [GitHub issues](https://github.com/kudosity/mcp/issues).

## Support

- Help centre and tickets: [help.kudosity.com](https://help.kudosity.com)
- Bugs and feature requests: [github.com/kudosity/mcp/issues](https://github.com/kudosity/mcp/issues)
- API documentation: [developers.kudosity.com](https://developers.kudosity.com/docs/mcp)

## Local development

```bash
git clone https://github.com/kudosity/mcp
cd mcp
npm install
npm run build
KUDOSITY_API_KEY=your_api_key npm start
KUDOSITY_API_KEY=your_api_key npm start # stdio
npm run start:http # streamable HTTP on :8080
```

Test tool listing with the MCP Inspector, or run the checks:

```bash
npm test # mock integration tests (no credentials)
node test/discovery-test.mjs # live spec-discovery test (no credentials)
npm test # build + mock tests: stdio, HTTP, OAuth (no credentials, no network)
node test/discovery-test.mjs # live spec-discovery test (no credentials)
npm run build:mcpb # Claude Desktop extension → dist-mcpb/
```

## License
Expand Down
Binary file added icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading