Skip to main content
Glama
Shylendra

bearer-mcp-server

by Shylendra
README.md
# bearer-mcp-server

A **production-style** [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server with **bearer token authentication**, written in TypeScript with the official [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk).

It demonstrates all three core MCP primitives — **tools**, **resources**, and **prompts** — themed as a **developer platform API** with mock data (projects, deployments, API keys, metrics, logs, diagnostics).

Compatible with MCP protocol versions **2025-11-25** and **2026-07-28**.

It supports two transports out of the box:

- **stdio** — for desktop clients (Claude Desktop, MCP Inspector launching a subprocess). No auth.
- **Streamable HTTP** — for HTTP-based clients, with session management and bearer token authentication.

---

## What's inside

### Tools (model-controlled actions)

| Tool | Description |
|------|-------------|
| `echo` | Echoes text back — a connectivity and auth check. |
| `search_projects` | Search projects by name, language, status, or tags with pagination. |
| `get_project` | Get a single project by ID with full details including owner info. |
| `create_project` | Create a new project in the platform. |
| `deploy_service` | Trigger a deployment pipeline to a target environment. |
| `list_api_keys` | List API keys for a project (keys are masked). |
| `rotate_api_key` | Rotate (regenerate) an API key — full key shown only here. |
| `get_metrics` | Get 24-hour usage and performance metrics for a project. Returns **structured output**. |
| `search_logs` | Full-text search across simulated log entries with level/project filters. |
| `run_diagnostic` | Run a comprehensive health diagnostic on a project. Returns **structured output**. |

### Resources (application-controlled, read-only data)

| URI | Description |
|-----|-------------|
| `config://server` | Static JSON server config, version, auth mode, and feature flags. |
| `docs://api-reference` | Markdown API reference for the mock developer platform. |
| `projects://{id}` | Templated resource backed by mock project store (20+ projects), with **listing**. |
| `projects://{id}/metrics` | Metrics sub-resource for a project. |
| `users://{id}` | Templated user profile resource, with **listing**. |
| `status://system` | Live system status — services, regions, and active incidents. |

### Prompts (user-controlled message templates)

| Prompt | Arguments | Description |
|--------|-----------|-------------|
| `debug_deployment` | `projectName`, `errorMessage`, `environment` | Ask the model to diagnose a failed deployment. |
| `write_api_docs` | `endpoint`, `language`, `includeExamples` | Ask the model to generate API documentation. |
| `review_config` | `configType`, `configYaml` | Ask the model to review a configuration for security and correctness. |
| `incident_postmortem` | `service`, `severity`, `summary`, `duration` | Ask the model to draft a blameless postmortem. |

---

## Quick start

```bash
# 1. Install dependencies
npm install

# 2. Build the TypeScript
npm run build

# 3a. Run over Streamable HTTP (with bearer auth)
npm start

# 3b. ...or run over stdio for desktop clients
npm run start:stdio
```

> **Requires Node.js >= 18.**

### Development (no build step, auto-reload)

```bash
npm run dev:stdio   # stdio transport with tsx watch
npm run dev:http    # HTTP transport with tsx watch
```

---

## Authentication

The HTTP transport requires a **Bearer token** on all `/mcp` requests:

```
Authorization: Bearer <token>
```

The `/health` endpoint is exempt from authentication.

### Configuring tokens

**Option 1: Environment variable (simple)**

```bash
# macOS / Linux
MCP_BEARER_TOKENS=sk_abc123,sk_def456 npm start

# Windows PowerShell
$env:MCP_BEARER_TOKENS="sk_abc123,sk_def456"; npm start
```

**Option 2: Token file (rich — with scopes and names)**

```json
[
  { "token": "sk_abc123", "name": "ci-pipeline", "scopes": ["read:*", "write:deployments"] },
  { "token": "sk_def456", "name": "readonly-dashboard", "scopes": ["read:*"] }
]
```

```bash
MCP_TOKEN_FILE=./tokens.json npm start
```

**Option 3: Default dev token (zero-config)**

When neither `MCP_BEARER_TOKENS` nor `MCP_TOKEN_FILE` is set, a single dev token is available:

```
mcp-dev-token-0123456789abcdef
```

### Disabling authentication

```bash
MCP_REQUIRE_AUTH=false npm start
```

> ⚠️ Only disable auth for local testing behind trusted networks.

### stdio transport

Authentication is **not enforced** on the stdio transport — it runs as a local subprocess spawned by the MCP client.

---

## Testing

Run the local smoke test to build the server, start it over stdio, and verify the expected tools, resources, resource templates, and prompts:

```bash
npm run test:smoke
```

### Testing with the MCP Inspector

The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is the easiest way to explore the server:

```bash
# Launches the Inspector and this server (stdio) together
npm run inspect
```

For the **HTTP** transport, start the server (`npm run start:http`) then open the Inspector and connect with:

- **Transport type:** `Streamable HTTP`
- **URL:** `http://127.0.0.1:3000/mcp`
- **Headers:** Add `Authorization: Bearer mcp-dev-token-0123456789abcdef`

---

## HTTP transport details

| Method | Path | Purpose |
|--------|------|---------|
| `POST` | `/mcp` | JSON-RPC requests (`initialize` + all subsequent calls). Auth required. |
| `GET` | `/mcp` | Server-Sent Events stream for server-to-client notifications. Auth required. |
| `DELETE` | `/mcp` | Terminate a session. Auth required. |
| `GET` | `/health` | Plain health check (not part of MCP). No auth required. |

Sessions are tracked via the `Mcp-Session-Id` response/request header. The HTTP server binds to `127.0.0.1` by default, and the port defaults to **3000**. Both can be overridden:

```bash
PORT=3100 npm run start:http                 # macOS / Linux
HOST=0.0.0.0 PORT=3100 npm run start:http    # macOS / Linux, public interface
$env:PORT=3100; npm run start:http           # Windows PowerShell
$env:HOST="0.0.0.0"; npm run start:http      # Windows PowerShell, public interface
```

### Example: raw HTTP handshake with `curl`

```bash
curl -i -X POST http://127.0.0.1:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Authorization: Bearer mcp-dev-token-0123456789abcdef" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'
```

The response includes an `Mcp-Session-Id` header — pass it back as a request header on subsequent calls.

### Testing auth failure

Omitting the token or using an invalid one returns:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32001,
    "message": "Unauthorized: missing Bearer token in Authorization header"
  },
  "id": null
}
```

---

## Deployment

### Docker / Google Cloud Run

```bash
docker build -t bearer-mcp-server .
docker run -p 8080:8080 \
  -e MCP_BEARER_TOKENS=your_token_here \
  bearer-mcp-server
```

Cloud Run sets the `PORT` environment variable and requires the container to listen on `0.0.0.0:$PORT`. The server detects Cloud Run via `K_SERVICE` and auto-binds appropriately.

### Vercel

The `api/` directory contains serverless MCP and health handlers. Deploy with the Vercel Git integration or CLI — set the *Framework Preset* to **Other** and leave *Build Command* / *Output Directory* empty.

---

## Using it with Claude Desktop

Add this to your `claude_desktop_config.json` (use the **absolute** path to `dist/stdio.js`):

```json
{
  "mcpServers": {
    "bearer-mcp-server": {
      "command": "node",
      "args": ["C:\\Users\\Shylendra\\git\\bearer-mcp-server\\dist\\stdio.js"]
    }
  }
}
```

Restart Claude Desktop, and the server's tools, resources, and prompts will appear.

---

## Project layout

```text
src/
├── server.ts          # createServer() factory + ServerCatalog
├── tools/             # Tool definitions (split by domain)
│   ├── index.ts       # registerTools() aggregator
│   ├── projects.ts    # search_projects, get_project, create_project
│   ├── deployments.ts # deploy_service
│   ├── api-keys.ts    # list_api_keys, rotate_api_key
│   ├── monitoring.ts  # get_metrics, search_logs, run_diagnostic
│   └── echo.ts        # echo tool
├── resources/
│   └── index.ts       # registerResources() — all 6 resources
├── prompts/
│   └── index.ts       # registerPrompts() — all 4 prompts
├── auth/
│   ├── middleware.ts  # Express bearer-token middleware
│   └── tokens.ts      # Token store, validation, loading
├── data/              # Mock data stores
│   ├── projects.ts    # 20 mock projects
│   ├── users.ts       # 5 mock user profiles
│   ├── api-keys.ts    # 8 mock API keys
│   ├── metrics.ts     # Deterministic metrics generator
│   ├── logs.ts        # Deterministic log generator
│   └── system.ts      # System status with incidents
├── stdio.ts           # stdio transport entry point
├── http.ts            # Streamable HTTP transport entry point (with auth)
├── banner.ts          # ANSI startup banner
└── logging.ts         # Structured JSON logging with redaction
api/
├── mcp.ts             # Vercel serverless MCP handler (with auth)
└── health.ts          # Vercel health check
index.ts               # Root HTTP router (node:http)
```

## Environment variables

| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | `3000` | HTTP listen port |
| `HOST` | `127.0.0.1` | Listen address (Cloud Run: auto `0.0.0.0`) |
| `MCP_REQUIRE_AUTH` | `true` | Enforce bearer token auth on HTTP |
| `MCP_BEARER_TOKENS` | — | Comma-separated valid tokens |
| `MCP_TOKEN_FILE` | — | Path to JSON file with token definitions |
| `MCP_CORS_ORIGIN` | `*` | CORS origin for browser access |
| `MCP_LOG_BODY_LIMIT` | `4000` | Max chars for request/response body logging |

## Notes

- **Authentication is enforced on HTTP transport by default.** Use `MCP_REQUIRE_AUTH=false` to disable for local testing.
- When using stdio, **never** write to `stdout` — it is reserved for the JSON-RPC protocol. Diagnostics go to `stderr` (`console.error`).
- Authorization headers are redacted in log output.

## License

MIT

TDQS

A3.9/5.0

Scored across 10 tools

Disambiguation5/5

Each tool targets a distinct resource and action: projects (create, get, search), deployments, API keys (list, rotate), metrics, logs, diagnostics, and connectivity. There is no overlap or ambiguity between tool purposes.

Naming Consistency4/5

Most tools follow a clear verb_noun snake_case pattern (create_project, search_logs, rotate_api_key). The only deviation is 'echo', which lacks a noun object, but this is a minor utility and does not undermine the overall pattern.

Tool Count5/5

With 10 tools, the server is well-scoped for a platform management API. Each tool covers a distinct aspect of project and deployment management, observability, and diagnostics, without unnecessary bloat.

Completeness3/5

The server covers project creation, retrieval, search, and deployment, but lacks update/delete operations for projects and API key creation/deletion. Deployment status tracking is also missing. These are notable gaps that agents may need to work around.

Maintenance

ActivityStale
ResponsivenessNo issues