Skip to content

neuhausjulian/vibe-coding_mcp-server

Repository files navigation

vibe-coding MCP Server

A minimal MCP (Model Context Protocol) server prototype that validates architecture, testing strategy, authorization concept, and dev-tool support.

Overview

This prototype exposes a single tool: getCurrentUserProfile, which returns the profile of the current authenticated user based on an internal authorization context.

Architecture

The prototype is split into three layers:

  1. Core/Domain Layer (src/core/): Pure business logic (user data, lookup, auth helpers, mapping)
  2. MCP Tool Layer (src/tools/): MCP tool implementations
  3. Transport/Runtime Layer (src/): STDIO transport and server entry point

Prerequisites

  • Node.js 18+ (with ES modules support)
  • npm or yarn

Installation

npm install

Configuration

The server supports loading environment variables from a .env file. You can copy .env.example to .env and configure your settings:

cp .env.example .env
# Edit .env with your configuration

The npm start and npm run inspector commands automatically load variables from .env using dotenv-cli.

Development

Build

npm run build

This compiles TypeScript to JavaScript in the dist/ directory.

Test

Run all tests (unit + integration):

npm test

Run tests in watch mode:

npm run test:watch

Run Server

The server uses STDIO transport and supports two authorization modes. The server will fail to start if the auth configuration is invalid.

Valid configurations:

  • Dev mode: DEV_STATIC_AUTHORIZATION=true AND DEV_STATIC_AUTHORIZATION_USER_ID must be set
  • Production mode: DEV_STATIC_AUTHORIZATION is false/not set AND JWT_JWKS_URL AND JWT_EXPECTED_AUDIENCE must be set

Dev Mode (Static Authorization)

Enable dev mode for development and testing:

Option 1: Using .env file (recommended)

Create a .env file in the project root:

DEV_STATIC_AUTHORIZATION=true
DEV_STATIC_AUTHORIZATION_USER_ID=user_1

Then run:

npm start
# or
npm run inspector

Option 2: Using environment variables directly

# Enable dev mode and set user ID
DEV_STATIC_AUTHORIZATION=true DEV_STATIC_AUTHORIZATION_USER_ID=user_1 npm start

Or after building:

DEV_STATIC_AUTHORIZATION=true DEV_STATIC_AUTHORIZATION_USER_ID=user_1 node dist/index.js

Production Mode (JWT Authorization)

When DEV_STATIC_AUTHORIZATION is not set or set to false, the server uses JWT-based authorization. The JWT token must be passed by the caller as a tool argument:

Option 1: Using .env file (recommended)

Create a .env file in the project root:

DEV_STATIC_AUTHORIZATION=false
JWT_JWKS_URL=https://your-auth-provider.com/.well-known/jwks.json
JWT_EXPECTED_AUDIENCE=your-audience
JWT_USER_ID_FIELD=sub

Then run:

npm start
# or
npm run inspector

Option 2: Using environment variables directly

# Production mode - configure JWT settings
JWT_JWKS_URL=https://your-auth-provider.com/.well-known/jwks.json \
JWT_EXPECTED_AUDIENCE=your-audience \
npm start

Calling the tool in production:

{
  "name": "getCurrentUserProfile",
  "arguments": {
    "token": "your-jwt-token-here"
  }
}

Environment Variables:

Dev Mode:

  • DEV_STATIC_AUTHORIZATION: Set to true or 1 to enable dev mode
  • DEV_STATIC_AUTHORIZATION_USER_ID: User ID to use in dev mode (e.g., user_1, user_2)

Production Mode (JWT Configuration):

  • JWT_JWKS_URL: JWKS endpoint URL for token signature verification (required)
  • JWT_EXPECTED_AUDIENCE: Expected audience (aud) claim value (required)
  • JWT_USER_ID_FIELD: Field name in JWT payload containing user ID (default: sub)

Note: The JWT token itself is passed by the caller as the token parameter in the tool arguments, not via environment variables.

Testing with MCP Inspector

  1. Build the server:

    npm run build
  2. Install MCP Inspector (if not already installed):

    npm install -g @modelcontextprotocol/inspector
  3. Configure MCP Inspector to use this server: Start a mcp inspector instance which will run its own instance of the mcp server. STDIO will be used for communication.

    • Server command: npx @modelcontextprotocol/inspector node dist/index.js
    • Before you connect to the mcp server, set environment variables for dev mode:
      • DEV_STATIC_AUTHORIZATION=true
      • DEV_STATIC_AUTHORIZATION_USER_ID=user_1 (or user_2)
  4. Inspect and test:

    • Connect to mcp server
    • List available tools (should show getCurrentUserProfile)
    • Call getCurrentUserProfile with empty input
    • Verify the returned profile matches the current user

Available Users (Fake Data)

Testing Scenarios

Valid User (Dev Mode)

DEV_STATIC_AUTHORIZATION=true DEV_STATIC_AUTHORIZATION_USER_ID=user_1 npm start
# Call getCurrentUserProfile → returns Alice's profile

User Not Found (Dev Mode)

DEV_STATIC_AUTHORIZATION=true DEV_STATIC_AUTHORIZATION_USER_ID=unknown npm start
# Call getCurrentUserProfile → returns "User not found" error

No Authenticated User (Production Mode - No Token)

# Don't set DEV_STATIC_AUTHORIZATION (or set to false)
# Don't set JWT_TOKEN
npm start
# Call getCurrentUserProfile → returns "No authenticated user" error

Valid User (Production Mode - JWT)

# Set JWT configuration
JWT_JWKS_URL=https://auth.example.com/.well-known/jwks.json \
JWT_EXPECTED_AUDIENCE=my-app \
JWT_USER_ID_FIELD=sub \
npm start
# Call getCurrentUserProfile with token argument:
# { "name": "getCurrentUserProfile", "arguments": { "token": "valid-jwt-token" } }
# → returns user profile from JWT token

Invalid JWT Token (Production Mode)

# Set JWT configuration
JWT_JWKS_URL=https://auth.example.com/.well-known/jwks.json \
JWT_EXPECTED_AUDIENCE=my-app \
npm start
# Call getCurrentUserProfile with invalid token:
# { "name": "getCurrentUserProfile", "arguments": { "token": "invalid-token" } }
# → returns "No authenticated user" error

No Token Provided (Production Mode)

# Set JWT configuration
JWT_JWKS_URL=https://auth.example.com/.well-known/jwks.json \
JWT_EXPECTED_AUDIENCE=my-app \
npm start
# Call getCurrentUserProfile without token argument:
# { "name": "getCurrentUserProfile", "arguments": {} }
# → returns "No authenticated user" error

No Authenticated User (Dev Mode, No User ID)

DEV_STATIC_AUTHORIZATION=true npm start
# DEV_STATIC_AUTHORIZATION_USER_ID not set
# Call getCurrentUserProfile → returns "No authenticated user" error

Project Structure

src/
├── core/              # Core/domain layer (pure logic)
│   ├── types.ts
│   ├── data.ts        # Fake user data
│   ├── user-lookup.ts
│   ├── user-lookup.test.ts  # Unit tests
│   ├── auth.ts
│   ├── auth.test.ts         # Unit tests
│   ├── profile-mapper.ts
│   └── profile-mapper.test.ts # Unit tests
├── tools/             # MCP tool layer
│   ├── getCurrentUserProfile.ts
│   └── getCurrentUserProfile.test.ts  # Unit tests
├── runtime/           # Runtime context
│   └── context.ts
└── index.ts           # Entry point (stdio transport)

tests/
└── integration/       # Integration tests
    └── getCurrentUserProfile.integration.test.ts

Test Structure

  • Unit Tests (src/**/*.test.ts): Test individual functions in isolation

    • Core layer: auth.test.ts, user-lookup.test.ts, profile-mapper.test.ts
    • Tool layer: getCurrentUserProfile.test.ts (tests tool logic and decision flow)
  • Integration Tests (tests/integration/*.integration.test.ts): Test multiple components working together

    • getCurrentUserProfile.integration.test.ts (tests auth + lookup + mapping integration)

Success Criteria

✅ Each function in the core/domain layer can be unit-tested independently
✅ The getCurrentUserProfile tool has reliable integration tests covering success and error paths
✅ Authorization concept (currentUserId → profile) is clearly expressed and tested
✅ Running server can be inspected and exercised via MCP Inspector
✅ Architecture can be extended later (Firebase, WebSocket, more tools) without redesign

About

Getting started with mcp servers

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published