MCP REST Demo Server
README.md
# REST vs MCP Demo (stdio + HTTP/SSE)
A minimal, runnable demo of the difference between a plain REST API and MCP
(Model Context Protocol) servers that wrap it — shown two ways: a **local**
MCP server reached over stdio, and a **remote-style** MCP server reached
over HTTP/SSE.
## Architecture
```
Local (stdio) transport
------------------------
mcp-client-stdio.js --spawns + talks MCP over stdio--> mcp-server-stdio.js
|
| HTTP
v
server-rest.js
(Express API :3001)
^
| HTTP
|
mcp-client-http.js --connects over the network (SSE)--> mcp-server-http.js
(listens :3002)
------------------------
Remote-style (HTTP/SSE) transport
```
Both MCP servers expose the exact same five tools and wrap the exact same
REST API on port 3001. Only the *transport* between client and server
differs:
| | `mcp-server-stdio.js` | `mcp-server-http.js` |
|---|---|---|
| Transport | stdio (stdin/stdout pipes) | HTTP + Server-Sent Events |
| How the client finds it | Client **spawns it** as a child process | Client **connects** to a URL (`http://localhost:3002/sse`) |
| Server lifecycle | Starts and dies with the client | Runs independently, on its own — start it once and any number of clients can connect over time |
| Can client/server be on different machines? | No — same machine, parent/child process | Yes — this is exactly how a genuinely remote MCP server would be reached |
| Endpoints | none (raw stdio) | `GET /sse` (open stream), `POST /messages` (send requests) |
The stdio version is what tools like Claude Desktop use for MCP servers
installed locally on your machine. The HTTP/SSE version is the same idea
as a **hosted/remote MCP server** — the kind you'd deploy once and let
multiple clients (or multiple people) connect to over the network, the
same way you'd deploy any web service.
## Files
- **server-rest.js** — the Express REST API for managing users (in-memory
storage). Identical for both demos; you can hit it directly with Postman
or curl. Runs on port **3001**.
- **mcp-server-stdio.js** — MCP server over stdio. Spawned directly by
`mcp-client-stdio.js`.
- **mcp-client-stdio.js** — spawns `mcp-server-stdio.js`, discovers its
tools via `tools/list`, and runs the test sequence below.
- **mcp-server-http.js** — MCP server over HTTP/SSE. Runs standalone on
port **3002**; you start it yourself, in its own terminal, before running
the HTTP client.
- **mcp-client-http.js** — connects to `http://localhost:3002/sse` over the
network (no spawning), discovers tools via `tools/list`, and runs the
identical test sequence.
Both MCP servers expose the same 5 tools:
- `list_users`
- `get_user` (parameter: `id`)
- `create_user` (parameters: `name`, `email`)
- `update_user` (parameters: `id`, `name`, `email`)
- `delete_user` (parameter: `id`)
## 1. Install dependencies
```bash
npm install
```
## 2. Start the REST API
In one terminal (required for **both** demos below):
```bash
npm run rest
```
You should see:
```
[REST] User API listening on http://localhost:3001
```
Leave this running.
### Try it with Postman / curl
```bash
curl http://localhost:3001/users
curl -X POST http://localhost:3001/users \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"john@example.com"}'
curl http://localhost:3001/users/1
curl -X PUT http://localhost:3001/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe"}'
curl -X DELETE http://localhost:3001/users/1
```
Watch the REST terminal — every request logs there.
## 3. Run the stdio (local) demo
With the REST API still running, in another terminal:
```bash
npm run client-stdio
```
You don't need to start the MCP server yourself — `mcp-client-stdio.js`
spawns `mcp-server-stdio.js` for you and talks to it over stdio.
If you want to see the stdio server run standalone (e.g. to try it from
the MCP Inspector or Claude Desktop instead of the bundled client):
```bash
npm run mcp-stdio
```
On its own it just sits there waiting for a client to speak JSON-RPC on
stdin — that's expected. Press Ctrl+C to stop it.
## 4. Run the HTTP/SSE (remote-style) demo
This one needs **two** terminals of its own, in order, because the HTTP
server doesn't get spawned automatically — it's meant to represent a
server running independently, somewhere else on the network.
**Terminal 2** — start the HTTP MCP server (with the REST API from step 2
still running in terminal 1):
```bash
npm run mcp-http
```
You should see:
```
[MCP-HTTP ...] MCP HTTP/SSE server listening on http://localhost:3002
[MCP-HTTP ...] SSE endpoint: GET http://localhost:3002/sse
[MCP-HTTP ...] Messages endpoint: POST http://localhost:3002/messages
```
Leave this running too.
**Terminal 3** — run the HTTP client:
```bash
npm run client-http
```
This connects to `http://localhost:3002/sse` (a plain network URL — no
spawning involved) and runs the same test sequence as the stdio client.
## Test sequence (identical for both transports)
1. List all users (expect empty)
2. Create user "John Doe"
3. List all users again (shows John)
4. Get John by ID
5. Update John's name to "Jane Doe"
6. Get the user again to verify the update
7. Delete the user
8. List all users one more time (expect empty)
Each step prints timing info and the raw tool result. You'll also see
`[MCP-SERVER]` / `[MCP-HTTP]` log lines (the stdio server's logs are
inherited into the client's terminal via stderr; the HTTP server's logs
appear in its own terminal) and `[REST]` log lines in the REST terminal —
so you can watch one logical operation flow through all three layers for
either transport.
## 5. Talk to it in plain English (free mock version)
`mock-ai-client.js` is a **free, no-API-key** stand-in for a real AI client.
There's no LLM involved — it's a handful of regexes that recognize a few
plain-English phrasings and map them onto the same 5 MCP tools, discovered
the same way (`tools/list`) as the other clients. It exists to show the
shape of "natural language in → pick a tool → call it via MCP → REST API →
result out" before spending anything on the real thing.
With the REST API running (step 2 above):
```bash
npm run mock-ai-client -- "list all users"
```
Or run it with no argument for an interactive prompt:
```bash
npm run mock-ai-client
```
Phrasings it understands:
- `list all users`
- `create a user named <name> with email <email>`
- `get user <id>`
- `update user <id>'s name to <name>`
- `update user <id>'s email to <email>`
- `delete user <id>`
Anything else prints a "didn't understand" message listing these examples —
unlike a real LLM-backed client, it can't generalize to phrasings it doesn't
recognize.
**This is not the real thing.** A genuine AI client would use the Anthropic
Messages API's tool-use feature: hand Claude the same `tools/list` output
(converted to Anthropic's tool format — just renaming `inputSchema` to
`input_schema`, since MCP already uses JSON Schema), let Claude decide which
tool to call and with what arguments based on your actual request, run it,
and feed the result back. That requires a separate Anthropic API key (billed
separately from any Claude subscription) and costs a small amount per
request — a few cents at most for casual use with a cheap model like Claude
Haiku 4.5. Ask if you want that version built.
## What this demonstrates
- The REST API works exactly like any normal HTTP service (Postman-testable),
and is unchanged between both demos — both MCP servers wrap the same API.
- Neither MCP client hardcodes a URL, HTTP verb, or JSON body shape — both
discover tool names, descriptions, and parameters via `tools/list`.
- **stdio = local**: the client owns the server's process lifecycle by
spawning it directly. Simple, but client and server must be on the same
machine.
- **HTTP/SSE = remote-capable**: the server runs independently and listens
on a port; the client just connects to a URL, the same way it would
connect to a server hosted anywhere else on the network. Multiple
clients can connect to the same running server over time.
- Either way, the MCP server is a thin translation layer: each tool call
becomes one HTTP call to the REST API, and the HTTP response becomes the
tool result.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues