Skip to main content
Glama
VishalESW

eSeller World MCP Server

by VishalESW
README.md
# eSeller World MCP Server

A remote **Model Context Protocol** server that exposes the eSeller World backend REST API as read/write tools, so Claude can work directly with:

- **Site content** (`/api/content`)
- **Schema fields** (model definitions — via `schema_describe` / `schema://models`)
- **SEO metadata** (`/api/seo`)
- **URL structures** (`/api/redirects`)
- **Other content** — blogs, case studies, portfolios, guides, categories, authors, contacts

It is a thin wrapper over the existing Express API in `eSellerWorld-Backend-main` — **no backend changes required**. Transport is **Streamable HTTP** (stateless), suitable for remote/hosted Claude clients.

## ⚠️ Security model (read this)

The backend API has **no authentication of its own**. This MCP server is therefore the security boundary:

- Every request to `POST /mcp` must carry `Authorization: Bearer <MCP_AUTH_TOKEN>`; anything else gets `401`.
- The server refuses to start if `MCP_AUTH_TOKEN` is unset.
- Write tools (`*_create`, `*_update`, `*_delete`, `content_update`) mutate **live production** data and are annotated as destructive so the MCP host prompts before each call.

Note: the token protects *this* MCP entrypoint only. Anyone who knows the backend origin can still call it directly — consider adding auth to the backend too, and always deploy the MCP behind HTTPS.

## Setup

```bash
cp .env.example .env      # then edit values
npm install
npm run dev               # tsx watch, or: npm run build && npm start
```

Environment variables (`.env`):

| Var | Meaning |
|-----|---------|
| `BACKEND_API_URL` | Origin of the backend API, e.g. `http://localhost:7002` |
| `MCP_AUTH_TOKEN` | Bearer secret clients must send (`openssl rand -hex 32`) |
| `PORT` | Port to listen on (default 8080) |
| `BACKEND_TIMEOUT_MS` | Per-request backend timeout (default 15000) |

## Endpoints

- `POST /mcp` — the MCP JSON-RPC endpoint (bearer-protected).
- `GET /healthz` — unauthenticated liveness probe.

## Connecting a Claude client

Remote MCP config:

```json
{
  "mcpServers": {
    "esellerworld": {
      "url": "https://<your-host>/mcp",
      "headers": { "Authorization": "Bearer <MCP_AUTH_TOKEN>" }
    }
  }
}
```

In Claude Code you can also add it from the CLI:

```bash
claude mcp add --transport http esellerworld https://<your-host>/mcp --header "Authorization: Bearer <MCP_AUTH_TOKEN>"
```

## Smoke test with curl

```bash
# initialize (should return serverInfo)
curl -s -X POST http://localhost:8080/mcp \
  -H "Authorization: Bearer $MCP_AUTH_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

# without the token -> 401
curl -s -o /dev/null -w "%{http_code}\n" -X POST http://localhost:8080/mcp -d '{}'
```

## Deploy

Any Node host works (Render, Railway, Fly.io, a VPS behind Nginx). A `Dockerfile` is included:

```bash
docker build -t esellerworld-mcp .
docker run -p 8080:8080 --env-file .env esellerworld-mcp
```

Terminate TLS at the platform/reverse proxy and point clients at `https://<host>/mcp`.

## Tool catalogue

- **Content:** `content_list`, `content_get`, `content_version`, `content_update`*, `content_delete`*
- **SEO:** `seo_list`, `seo_get_by_path`, `seo_get_by_id`, `seo_create`*, `seo_update`*, `seo_delete`*
- **Redirects:** `redirects_list`, `redirect_get`, `redirect_check`, `redirect_create`*, `redirect_update`*, `redirect_toggle`*, `redirect_delete`*, `redirects_bulk_delete`*
- **Blogs:** `blogs_list`, `blog_get_by_slug`, `blog_get_by_id`, `blog_create`*, `blog_update`*, `blog_delete`*
- **Categories / Authors:** `categories_list`, `category_get`, `category_create`*…; `authors_list`, `author_get`, `author_create`*…
- **Case studies / Portfolios:** `case_studies_list`, `case_study_get_by_slug/id`, CRUD*; `portfolios_list`, `portfolio_get`, CRUD*
- **Guides:** `guide_collections_*`, `guide_faqs_*`, `guide_contents_*` (list/get + CRUD*)
- **Contacts (PII):** `contacts_list`, `contact_get`, `contact_update_status`*
- **Schema:** `schema_describe` + resource `schema://models`

`*` = write tool (mutates live data).