Skip to main content
Glama
jspmern

remote-mcp-server

by jspmern
README.md
# MCP Remote Server

A TypeScript-based Model Context Protocol (MCP) remote server built with Express.js that provides tools, prompts, and resources over HTTP. This server demonstrates how to create an MCP server with HTTP transport, authentication middleware, and various MCP capabilities.

---

## Table of Contents

1. [Project Overview](#project-overview)
2. [Architecture & Diagram](#architecture--diagram)
3. [Key Features](#key-features)
4. [Installation & Setup](#installation--setup)
5. [Core Concepts](#core-concepts)
   - [Express Server Setup](#express-server-setup)
   - [Authentication Middleware](#authentication-middleware)
   - [MCP Server Creation](#mcp-server-creation)
   - [HTTP Transport](#http-transport)
6. [Components Breakdown](#components-breakdown)
   - [Tools Registration](#tools-registration)
   - [Prompt Templates](#prompt-templates)
   - [Resources](#resources)
7. [API Endpoints](#api-endpoints)
8. [Usage Examples](#usage-examples)
9. [Development & Deployment](#development--deployment)

---

## Project Overview

This project is an **MCP Remote Server** that exposes AI capabilities through HTTP endpoints. It uses the Model Context Protocol SDK to create a server that can be consumed by AI clients. The server provides:

- **Tools**: Functions that AI models can call to retrieve data
- **Prompts**: Reusable prompt templates for AI interactions
- **Resources**: Static or dynamic data resources accessible to clients
- **Authentication**: Token-based authentication for secure access

---

## Architecture & Diagram

### System Architecture Diagram

```
┌─────────────────────────────────────────────────────────────────┐
│                        Client (AI Model/App)                      │
└────────────────────────────┬────────────────────────────────────┘
                             │ HTTP Request
                             ▼
┌─────────────────────────────────────────────────────────────────┐
│                  Express.js Server (Port 3000)                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                   │
│  ┌──────────────────┐        ┌─────────────────────────────┐   │
│  │  Middleware      │        │   Route Handlers            │   │
│  ├──────────────────┤        ├─────────────────────────────┤   │
│  │ • express.json   │        │ • GET  /          (Hello)   │   │
│  │ • authMiddleware │        │ • POST /mcp       (MCP)     │   │
│  └──────────────────┘        └─────────────────────────────┘   │
│                                                                   │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │        MCP Server (StreamableHTTPServerTransport)        │   │
│  ├──────────────────────────────────────────────────────────┤   │
│  │                                                          │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │         Registered Tools                          │  │   │
│  │  │  • get_my_student_information                     │  │   │
│  │  │    └─> Returns student data from fakeData array   │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  │                                                          │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │         Registered Prompts                        │  │   │
│  │  │  • greeting_template                             │  │   │
│  │  │    └─> Generates dynamic greeting messages       │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  │                                                          │   │
│  │  ┌───────────────────────────────────────────────────┐  │   │
│  │  │         Registered Resources                      │  │   │
│  │  │  • company-policy                                │  │   │
│  │  │    └─> Company work hours and leave policies     │  │   │
│  │  └───────────────────────────────────────────────────┘  │   │
│  │                                                          │   │
│  └──────────────────────────────────────────────────────────┘   │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘
```

### Request Flow Diagram

```
Client Request with Bearer Token
         │
         ▼
    Express.js
         │
         ├─► authMiddleware
         │   ├─► Extract token from header
         │   ├─► Compare with MCP_TOKEN env var
         │   ├─► If valid: next()
         │   └─► If invalid: 401 Unauthorized
         │
    ┌────┴────┐
    ▼         │
 Valid        Invalid
   │          │
   ▼          ▼
Route      Error
Handler    Response
   │
   ├─► GET /  → "Hello TypeScript"
   │
   └─► POST /mcp
       ├─► Create StreamableHTTPServerTransport
       ├─► Create MCP Server
       ├─► Connect server to transport
       └─► Handle MCP Request/Response

```

---

## Key Features

| Feature | Description |
|---------|-------------|
| **MCP Integration** | Full Model Context Protocol SDK integration for tool/prompt/resource registration |
| **Express.js** | Lightweight HTTP server framework for handling requests |
| **Authentication** | Token-based Bearer token authentication middleware |
| **Tools** | AI-callable functions to retrieve student information |
| **Prompts** | Reusable prompt templates with dynamic variable substitution |
| **Resources** | Static resources like company policies accessible to clients |
| **TypeScript** | Full type safety with TypeScript for robust development |
| **Environment Config** | Uses dotenv for sensitive configuration management |
| **Zod Validation** | Schema validation for input parameters |

---

## Installation & Setup

### Prerequisites
- Node.js (v16+)
- npm or yarn

### Step 1: Install Dependencies

```bash
npm install
```

This installs:
- `@modelcontextprotocol/sdk`: MCP SDK for server creation
- `express`: HTTP server framework
- `zod`: Runtime type validation
- `dotenv`: Environment variable management

### Step 2: Environment Configuration

Create a `.env` file in the root directory:

```env
MCP_TOKEN=your_secret_token_here
```

This token is used for Bearer token authentication.

### Step 3: Build TypeScript

```bash
npm run build
```

This compiles TypeScript files from `src/` to `build/`

### Step 4: Run the Server

**Development Mode** (with auto-reload):
```bash
npm run dev
```

**Production Mode**:
```bash
npm start
```

Server will start on `http://localhost:3000`

---

## Core Concepts

### 1. Express Server Setup

Express is a minimal HTTP framework that handles incoming requests and routes them to appropriate handlers.

**Code Explanation:**

```typescript
import express from "express";

const app = express();
app.use(express.json()); // Middleware to parse JSON request bodies
```

**What happens:**
- Creates an Express application instance
- Adds JSON body parser middleware to automatically parse incoming JSON
- All subsequent middleware and route handlers have access to parsed request body

**Visual Flow:**

```
Request → Parse JSON Body → Available in req.body → Route Handler
```

---

### 2. Authentication Middleware

Middleware intercepts requests before they reach route handlers to perform security checks.

**Code Explanation:**

```typescript
export function authMiddleware(
  req: Request,
  res: Response,
  next: NextFunction
) {
  const token = req.headers.authorization;

  if (token !== `Bearer ${process.env.MCP_TOKEN}`) {
    return res.status(401).json({ message: "Unauthorized" });
  }

  next(); // Allow request to proceed
}
```

**How it works:**

```
1. Extract token from Authorization header
   Example: "Bearer abc123def456"

2. Compare with environment variable MCP_TOKEN

3. Decision:
   ├─► Match? → Call next() → Continue to route handler
   └─► No match? → Send 401 Unauthorized → Stop execution
```

**Example Request:**

```bash
# ✅ Valid request (has correct token)
curl -H "Authorization: Bearer your_secret_token_here" http://localhost:3000/mcp

# ❌ Invalid request (no token or wrong token)
curl http://localhost:3000/mcp
# Response: 401 - Unauthorized
```

---

### 3. MCP Server Creation

The `createServer()` function initializes the MCP server and registers all available capabilities.

**Code Structure:**

```typescript
function createServer() {
  // Step 1: Instantiate MCP Server
  const server = new McpServer({
    name: "remote-mcp-server",
    version: "1.0.0",
  });

  // Step 2: Register tools, prompts, resources
  server.registerTool(...);
  server.registerPrompt(...);
  server.registerResource(...);

  return server; // Step 3: Return configured server
}
```

**Purpose:**
- Creates a new MCP server instance
- Registers all available tools, prompts, and resources
- Returns the server for connection to HTTP transport

---

### 4. HTTP Transport

StreamableHTTPServerTransport handles the HTTP layer for MCP communication.

**Code Explanation:**

```typescript
app.post("/mcp", async (req, res) => {
  // Step 1: Create HTTP transport layer
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
  });

  // Step 2: Create MCP server
  const server = createServer();

  // Step 3: Connect server to transport
  await server.connect(transport);

  // Step 4: Process incoming HTTP request
  await transport.handleRequest(req, res, req.body);
});
```

**Process Flow:**

```
HTTP POST /mcp
    │
    ▼
Create Transport ──► Register handlers for streaming
    │
    ▼
Create MCP Server ──► Setup tools/prompts/resources
    │
    ▼
Connect ──► Server connects to transport layer
    │
    ▼
Handle Request ──► Transport processes MCP protocol
    │
    ▼
Send Response ──► HTTP Response back to client
```

---

## Components Breakdown

### Sample Data Structure

The server includes mock student data:

```typescript
const fakeData = [
  {
    "id": 1,
    "name": "Rahul Sharma",
    "age": 21,
    "address": "Mumbai, Maharashtra",
    "course": "B.Tech",
    "role": "Student"
  },
  // ... 9 more student records
];
```

This data is used by tools to simulate real database queries.

---

### Tools Registration

**Tools** are functions that AI models can call to perform actions or retrieve data.

#### Tool: `get_my_student_information`

**Purpose:** Retrieve a limited number of student records

**Code:**

```typescript
server.registerTool(
  "get_my_student_information",           // Tool name
  {
    description: "Get student information", // Description for AI model
    inputSchema: {
      limit: z.string(),                   // Parameter: limit as string
    },
  },
  async ({ limit }) => ({                  // Handler function
    content: [
      {
        type: "text",
        text: JSON.stringify(
          fakeData.slice(0, parseInt(limit) || 5) // Return up to 'limit' records, default 5
        ),
      },
    ],
  })
);
```

**Execution Flow:**

```
AI Model Call
    │
    ├─► Tool Name: get_my_student_information
    ├─► Input: { limit: "3" }
    │
    ▼
Handler Function
    │
    ├─► Parse limit: parseInt("3") = 3
    ├─► Get slice: fakeData.slice(0, 3)
    ├─► Convert to JSON string
    │
    ▼
Return Response
    │
    └─► {
          content: [{
            type: "text",
            text: "[student1, student2, student3]"
          }]
        }
```

**Example Usage:**

```javascript
// AI Model calls the tool
const result = await client.callTool("get_my_student_information", {
  limit: "2"
});

// Response:
{
  content: [{
    type: "text",
    text: '[{"id":1,"name":"Rahul Sharma","age":21,...},{"id":2,"name":"Priya Singh","age":22,...}]'
  }]
}
```

---

### Prompt Templates

**Prompts** are reusable message templates that AI models can use for consistent interactions.

#### Prompt: `greeting_template`

**Purpose:** Generate personalized greeting messages

**Code:**

```typescript
server.registerPrompt(
  "greeting_template",                           // Prompt name
  {
    description: "A template prompt for greeting", // Description
    argsSchema: {
      name: z.string()                           // Required parameter: name
    }
  },
  async ({ name }) => ({                         // Handler with parameter
    messages: [
      {
        role: "assistant",
        content: {
          type: "text",
          text: `Hello, ${name}! Welcome to the MCP Local Server.` // Dynamic message
        }
      }
    ]
  })
);
```

**How It Works:**

```
Request Prompt: greeting_template
    │
    ├─► Input Parameter: { name: "Alice" }
    │
    ▼
Template Processing
    │
    ├─► Substitute ${name} with "Alice"
    ├─► Generate message: "Hello, Alice! Welcome to the MCP Local Server."
    │
    ▼
Return Message
    │
    └─► {
          messages: [{
            role: "assistant",
            content: {
              type: "text",
              text: "Hello, Alice! Welcome to the MCP Local Server."
            }
          }]
        }
```

**Use Cases:**
- Greeting users with their name
- Generating consistent opening messages
- Personalizing AI responses

---

### Resources

**Resources** are static or dynamically generated data that AI models can access.

#### Resource: `company-policy`

**Purpose:** Provide company policies to AI models

**Code:**

```typescript
server.registerResource(
  "company-policy",                    // Resource name
  "company://policy",                  // Resource URI
  {},                                  // Input schema (empty = no parameters)
  async () => ({                       // Handler function
    contents: [
      {
        uri: "company://policy",       // Resource identifier
        text: `
Work Hours: 9 AM to 6 PM
Casual Leave: 12
Sick Leave: 8
`
      }
    ]
  })
);
```

**Access Pattern:**

```
Request Resource: company-policy
    │
    ▼
Retrieve Resource Data
    │
    ├─► Work Hours: 9 AM to 6 PM
    ├─► Casual Leave: 12 days
    └─► Sick Leave: 8 days
    │
    ▼
Return to Client
    │
    └─► AI model now has access to policies
```

**Use Cases:**
- Company policies and guidelines
- Knowledge bases
- Reference documents
- Configuration data

---

## API Endpoints

### 1. Health Check Endpoint

**Endpoint:** `GET /`

**Description:** Simple health check to verify server is running

**Response:**

```
200 OK
Body: "Hello TypeScript"
```

**Example:**

```bash
curl http://localhost:3000/
# Response: Hello TypeScript
```

---

### 2. MCP Endpoint

**Endpoint:** `POST /mcp`

**Authentication:** Required (Bearer token)

**Description:** Main MCP protocol handler for tools, prompts, and resources

**Request Headers:**

```
Authorization: Bearer {MCP_TOKEN}
Content-Type: application/json
```

**Request Body Structure:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_my_student_information",
    "arguments": {
      "limit": "3"
    }
  }
}
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "[...student data...]"
      }
    ]
  }
}
```

**Example:**

```bash
curl -X POST http://localhost:3000/mcp \
  -H "Authorization: Bearer your_secret_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_my_student_information",
      "arguments": { "limit": "2" }
    }
  }'
```

---

## Usage Examples

### Example 1: Call Tool via MCP

**Scenario:** AI model wants to retrieve 2 student records

**Request:**

```bash
curl -X POST http://localhost:3000/mcp \
  -H "Authorization: Bearer your_secret_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_my_student_information",
      "arguments": { "limit": "2" }
    }
  }'
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "[{\"id\":1,\"name\":\"Rahul Sharma\",\"age\":21,...},{\"id\":2,\"name\":\"Priya Singh\",\"age\":22,...}]"
      }
    ]
  }
}
```

---

### Example 2: Use Prompt Template

**Scenario:** AI model wants to greet a user with their name

**Request:**

```bash
curl -X POST http://localhost:3000/mcp \
  -H "Authorization: Bearer your_secret_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "prompts/get",
    "params": {
      "name": "greeting_template",
      "arguments": { "name": "Rajesh" }
    }
  }'
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "messages": [
      {
        "role": "assistant",
        "content": {
          "type": "text",
          "text": "Hello, Rajesh! Welcome to the MCP Local Server."
        }
      }
    ]
  }
}
```

---

### Example 3: Access Resource

**Scenario:** AI model needs to retrieve company policies

**Request:**

```bash
curl -X POST http://localhost:3000/mcp \
  -H "Authorization: Bearer your_secret_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "resources/read",
    "params": {
      "uri": "company://policy"
    }
  }'
```

**Response:**

```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "contents": [
      {
        "uri": "company://policy",
        "text": "Work Hours: 9 AM to 6 PM\n\nCasual Leave: 12\n\nSick Leave: 8"
      }
    ]
  }
}
```

---

## Development & Deployment

### Project Structure

```
mcp_remote_server/
├── src/
│   ├── index.ts                 # Main server file
│   └── middlware/
│       └── auth.ts              # Authentication middleware
├── build/
│   ├── index.js                 # Compiled main file
│   └── middlware/
│       └── auth.js              # Compiled middleware
├── package.json                 # Project dependencies
├── tsconfig.json                # TypeScript configuration
└── README.md                    # This file
```

### Build Process

```
TypeScript Files (src/)
        │
        ▼
TypeScript Compiler (tsc)
        │
        ▼
JavaScript Files (build/)
        │
        ▼
Node.js Runtime
```

**Build Command:**

```bash
npm run build
```

This runs the TypeScript compiler and outputs JavaScript to the `build/` directory.

### Scripts

| Script | Command | Purpose |
|--------|---------|---------|
| `build` | `tsc` | Compile TypeScript to JavaScript |
| `start` | `node build/index.js` | Run compiled server |
| `dev` | `nodemon --watch src...` | Development mode with auto-reload |

### Development Workflow

1. **Edit TypeScript files** in `src/`
2. **Nodemon watches** for changes
3. **Auto-compiles** TypeScript
4. **Auto-reloads** Node.js process
5. **Test** changes immediately

### Environment Variables

Create `.env` file:

```env
# Server Configuration
PORT=3000

# Authentication
MCP_TOKEN=your_very_secret_token_here_change_in_production
```

**Security:** Never commit `.env` to version control. Add to `.gitignore`:

```
.env
.env.local
```

### Deployment

**Production Deployment Steps:**

1. **Set environment variables** on server
2. **Run build:**
   ```bash
   npm run build
   ```
3. **Start server:**
   ```bash
   npm start
   ```
4. **Use process manager** (pm2, systemd, etc.):
   ```bash
   pm2 start build/index.js --name "mcp-server"
   ```

**Docker Deployment:**

```dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY build/ ./build/

ENV MCP_TOKEN=your_token_here

EXPOSE 3000

CMD ["node", "build/index.js"]
```

---

## Summary

This MCP Remote Server demonstrates:

✅ **HTTP-based MCP Protocol** - Communicate with AI models over HTTP
✅ **Tool Registration** - Create callable functions for AI
✅ **Prompt Templates** - Reusable message patterns
✅ **Resources** - Access to data and policies
✅ **Authentication** - Secure access with Bearer tokens
✅ **Type Safety** - Full TypeScript support
✅ **Easy Development** - Hot-reload with Nodemon

---

## References

- [Model Context Protocol Documentation](https://modelcontextprotocol.io/)
- [Express.js Guide](https://expressjs.com/)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
- [Zod Validation](https://zod.dev/)

---

**Last Updated:** June 4, 2026