---
title: "Ring MCP Server"
description: "Connect Cursor (and other MCP hosts) to your Ring clone via ring-mcp — founders learn how AI + Telegram operate the same project; developers wire the gateway and stdio client"
locale: "en"
---
# Ring MCP Server (`ring-mcp`)

**Operate one Ring Platform clone from natural language** — in Cursor, Claude Desktop, or any [MCP](https://modelcontextprotocol.io/docs/getting-started/intro) host — without opening the admin UI for every CRUD task.

`ring-mcp` is a **stdio MCP server** under `AI-RING/ring-mcp/`. It does **not** open PostgreSQL. It calls your clone’s **Bearer service gateway** at `/api/mcp/v1/*`, which runs as a synthetic **SUPERADMIN** and reuses Ring’s existing services.

> **Info**
> Use **Founder** / **Developer** tabs in the docs sidebar. Founders: how MCP and Telegram both remote-control **your** project. Developers: env, `mcp.json`, gateway paths, and tool inventory.

```mermaid
flowchart LR
  subgraph remotes["Your remotes"]
    Cursor["Cursor / Claude\nring-mcp stdio"]
    TG["Telegram Admin Bot\nphone NL ops"]
  end
  subgraph clone["Your Ring clone"]
    GW["/api/mcp/v1/*\nBearer RING_MCP_ACCESS_KEY"]
    BOT["/api/telegram/admin-bot/webhook"]
    SVC["Ring services + DB"]
  end
  Cursor -->|Bearer token| GW --> SVC
  TG --> BOT --> SVC
```

| Remote | Who uses it | How it reaches the clone |
|--------|-------------|---------------------------|
| **ring-mcp** | Founders + hired developers in an AI IDE | stdio MCP → `RING_API_BASE_URL` + `RING_MCP_ACCESS_KEY` → `/api/mcp/v1/*` |
| **Telegram Admin Bot** | Admins on the phone | Whitelisted Telegram chat → webhook → Ring services ([Manage via Telegram](/docs/features/manage-via-telegram.md)) |

They are **sibling remotes**, not the same process. Both target **one white-label instance** (your store, newsroom, users). Kingdom tools (`legiox-*`, `ringdom-*`, `reggie-*`) are a different scope.

### For founders

## Why this matters for your clone

You already have a Ring project (GreenFood, PetFriend, Vikka, …). You want to:

1. Ask Cursor: “list open opportunities”, “approve this vendor”, “draft a news post”
2. Ask Telegram: “approve draft”, “who signed up today” — without a laptop

**MCP is the IDE remote.** **Telegram is the phone remote.** Point both at the **same** clone URL and keep tokens/secrets out of git.

  
- **[Manage via Telegram](/docs/features/manage-via-telegram.md)** — Phone twin: whitelist, webhook, approve/reject news without a laptop.

  
- **[Admin console](/docs/features/admin.md)** — Full three-pane UI when chat remotes are not enough.

  
- **[VideoConductor](/docs/features/video-conductor.md)** — Same generative stack as `ring-video-create` on MCP.

  
- **[WalletConductor](/docs/features/wallet-conductor.md)** — MCP credit tools hit the same ledger as the wallet UI.

### Founder checklist — connect MCP to your project

**1. Pick the clone URL**

Local: `http://localhost:3000`. Production: `https://your-clone.example.com`. That becomes `RING_API_BASE_URL` — it must be **your** project, not another tenant.

**2. Create one long random service token**

On the Ring clone, set `RING_MCP_ACCESS_KEY` (comma-separated if you need several keys). Restart the app. Never commit the real value.

**3. Register ring-mcp in Cursor**

In kingdom `.cursor/mcp.json` (or Cursor Settings → MCP):

- `command`: `node`
- `args`: absolute path to `AI-RING/ring-mcp/ring-mcp-server.js`
- `env`: `RING_API_BASE_URL`, `RING_MCP_ACCESS_KEY`, optional `RING_CLONE_NAME`

**4. Smoke-test**

Ask the agent: “Run `ring-health` and `ring-whoami`.” You should see your clone name and a superadmin service actor. Then try a read-only list (entities or opportunities).

**5. Keep Telegram as the phone twin**

Wire [Manage via Telegram](/docs/features/manage-via-telegram.md) (`ADMIN_BOT_*`) separately. Same clone, different channel — whitelist only trusted Telegram chat IDs.

> **Tip**
> One clone → one MCP entry. Running GreenFood and PetFriend? Register **two** servers (e.g. `ring-mcp-greenfood`, `ring-mcp-petfriend`) with different URLs and tokens.

> **Warning**
> MCP runs as **synthetic SUPERADMIN**. Treat the access key like a root password. Prefer confirm-gated destructive tools (`confirm: true`) and audit who holds the key.

### Typical founder prompts

{`"Which Ring clone am I connected to? Run ring-whoami."
"List the first 20 entities on this clone."
"Create a draft news post titled Platform update."
"Add 50 credits to user  — I confirm."`}

### For developers

## Architecture

{`You (chat) → MCP host (Cursor) → ring-mcp (stdio)
         → Bearer RING_MCP_ACCESS_KEY → /api/mcp/v1/* → Ring services → DB`}

| Layer | Path |
|-------|------|
| stdio MCP server | `AI-RING/ring-mcp/ring-mcp-server.js` (**58** `ring-*` tools) |
| HTTP gateway | `app/api/mcp/v1/**` |
| Token verify | `lib/auth/service-token.ts` → `verifyServiceToken` |
| Actor context | `lib/auth/mcp-actor-context.ts` (AsyncLocalStorage SUPERADMIN) |
| Package README | `AI-RING/ring-mcp/README.md` |
| Per-tool MDX | `/docs/mcp/*` (e.g. [ring-video-create](/docs/mcp/ring-video-create.md)) |

Kingdom MCP (different scope): `legiox-mcp`, `ringdom-mcp`, `reggie-mcp`.

### Env SSOT (verified)

**On the Ring clone** (`env.local.template`):

| Variable | Required | Role |
|----------|----------|------|
| `RING_MCP_ACCESS_KEY` | Yes | Comma-separated Bearer tokens accepted by the gateway |
| `RING_MCP_SERVICE_USER_ID` | No | Synthetic actor id (default `ring-mcp-service`) |
| `RING_MCP_SERVICE_USER_EMAIL` | No | Synthetic actor email |
| `RING_MCP_SERVICE_USER_NAME` | No | Synthetic actor display name |

**On ring-mcp (Cursor `mcp.json` env):**

| Variable | Required | Role |
|----------|----------|------|
| `RING_API_BASE_URL` | Yes | Clone origin (no trailing path) |
| `RING_MCP_ACCESS_KEY` | Yes | Must match one token on the clone |
| `RING_CLONE_NAME` | No | Label for `ring-whoami` |

> **Warning**
> Older docs mentioned `RING_MCP_SERVICE_TOKENS`. Gateway code reads **`RING_MCP_ACCESS_KEY` only** (`lib/auth/service-token.ts`).

### Wire Cursor

**Enable gateway on the clone**

{`RING_MCP_ACCESS_KEY=replace-with-long-random-string
# RING_MCP_SERVICE_USER_ID=ring-mcp-service
# RING_MCP_SERVICE_USER_EMAIL=ring-mcp@system.local
# RING_MCP_SERVICE_USER_NAME=Ring MCP Service`}

Restart Next.js after changing env.

**Install & self-test**

{`cd /path/to/ringdom/AI-RING/ring-mcp
npm install
node ring-mcp-server.js --test
# expect: {"ok":true,"tools":58,...}`}

**Register stdio server**

{`{
  "ring-mcp": {
    "command": "node",
    "args": ["/absolute/path/ringdom/AI-RING/ring-mcp/ring-mcp-server.js"],
    "env": {
      "RING_API_BASE_URL": "http://localhost:3000",
      "RING_MCP_ACCESS_KEY": "replace-with-long-random-string",
      "RING_CLONE_NAME": "ring-platform.org"
    }
  }
}`}

**Smoke**

{`RING_API_BASE_URL=http://localhost:3000 \\
RING_MCP_ACCESS_KEY=your-token \\
npm run smoke --prefix AI-RING/ring-mcp`}

Or ask the agent to call `ring-health` + `ring-whoami`.

### Multi-clone profiles

Register separate MCP entries (`ring-mcp-connect`, `ring-mcp-platform`, …) each with its own `RING_API_BASE_URL` + token. Do not reuse one token across production tenants.

### Tool map (58 tools)

Sensitive mutations require **`confirm: true`**.

| Domain | Tools (prefix `ring-`) |
|--------|-------------------------|
| Meta | `health`, `whoami` |
| Entities | `entity-list/get/search/create/update/delete` |
| Opportunities | `opportunity-*` + `opportunity-match` |
| News | `news-*` + `news-score/approve/reject` + `news-generate` |
| Store | `store-product-*`, `vendor-*`, `order-*` |
| Users | `user-*` + `user-set-role` |
| Credit / payments | `credit-*`, `payment-*` |
| Notify / chat | `notification-list`, `notify-send`, `fcm-send`, `conversation-list`, `message-send` |
| Media | `image-create`, `video-create` |

Full parameter tables: [ring-image-create](/docs/mcp/ring-image-create.md), [ring-video-create](/docs/mcp/ring-video-create.md), [generative newsroom](/docs/development/generative-newsroom.md).

### Gateway modules

| Path | Role |
|------|------|
| `app/api/mcp/v1/meta/` | health / whoami |
| `app/api/mcp/v1/entities/` … `users/` … | Domain CRUD |
| `app/api/mcp/v1/images/generate` | ImageConductor |
| `app/api/mcp/v1/videos/generate` | VideoConductor |
| `app/api/mcp/v1/news/generate` | TextConductor newsroom |

### Telegram vs MCP (integrator truth)

| Concern | ring-mcp | Telegram Admin Bot |
|---------|----------|--------------------|
| Transport | MCP stdio + HTTP Bearer | Telegram webhook |
| Auth | `RING_MCP_ACCESS_KEY` | `ADMIN_BOT_*` + chat whitelist |
| Actor | Synthetic SUPERADMIN | Mapped Ring admin/superadmin user |
| Code | `AI-RING/ring-mcp` + `app/api/mcp/v1` | `lib/telegram/admin-bot/` |
| Docs | This page | [Manage via Telegram](/docs/features/manage-via-telegram.md) |

Telegram does **not** spawn `ring-mcp-server.js`. Both eventually mutate the same clone data through Ring services.

### Troubleshooting

| Symptom | Fix |
|---------|-----|
| `401 Invalid service token` | Match MCP env token to clone `RING_MCP_ACCESS_KEY`; restart Ring |
| `RING_MCP_ACCESS_KEY is not configured` | Set on **Ring app**, not only MCP |
| `tools: 0` / MCP missing in Cursor | Absolute path in `mcp.json`; run `--test`; reload MCP |
| Wrong clone data | Check `RING_API_BASE_URL` / `RING_CLONE_NAME` |
| Generative tools fail | Provider keys (`XAI_API_KEY`, …) on the **clone**, not in ring-mcp |

## Related

- [features/manage-via-telegram](/docs/features/manage-via-telegram.md) — Same-workflow: phone-side admin bot for the same clone ops surface.

- [development/community-tooling](/docs/development/community-tooling.md) — See-also: kingdom MCP vs per-clone ring-mcp scope.

- [development/generative-videos](/docs/development/generative-videos.md) — Deep-dive: ring-video-create end-to-end on the clone.

- [features/admin-wiki](/docs/features/admin-wiki.md) — Next-step: ring-wiki-* tools for project knowledge self-build and search.

- [development/docs-components](/docs/development/docs-components.md) — See-also: MDX authoring reference including RelatedArticle.
