Skip to main content
Glama
mwhobrey

wmcp

by mwhobrey

wmcp

MCP exposure infrastructure — how to run Model Context Protocol servers so Cursor, Claude Desktop, and Claude Code can reach them from WSL, Windows, or macOS.

This repo is the transport/wiring layer, plus an optional personas server (compose / list_prompts). It also ships a tiny example server (echo / ping) so you can verify the plumbing. Bring your own tools and prompt packs.

Requires Node.js ≥ 18.

What an MCP server is (short version)

An MCP server is a process that speaks Model Context Protocol — JSON-RPC messages describing tools, prompts, and/or resources. Clients (Cursor, Claude) call those tools during a chat.

The interesting part is not the tools themselves. It is how the client connects:

Transport

Who speaks it

How it runs

stdio

Cursor (local), Claude Desktop

Client spawns node dist/….js and talks over stdin/stdout

Streamable HTTP

Cursor, Claude Desktop (URL mode)

One long-lived Node HTTP server; client POSTs to http://host:port/<name>

Legacy SSE

Claude Code CLI

Same HTTP server; GET /<name>/sse + POST /<name>/message

wmcp implements all three from one codebase.

┌─────────────────┐     stdio      ┌──────────────────┐
│ Cursor / Claude │ ◄────────────► │ example-server   │  (per-process)
│   (local spawn) │                │ or stdio-bridge  │
└─────────────────┘                └──────────────────┘

┌─────────────────┐   HTTP/SSE     ┌──────────────────┐
│ Cursor / Claude │ ◄────────────► │   http-server    │──► example
│   (URL mode)    │                │   :8820          │──► personas (opt)
└─────────────────┘                └──────────────────┘

Typical setup when the real Node runtime lives in WSL:

  1. Run http-server inside WSL (systemd user unit or npm start).

  2. Point Windows/mac Cursor at http://localhost:8820/example (WSL localhost forwarding).

  3. Or, for stdio-only clients on Windows: wsl.exe … node dist/example-server.js.

On macOS / native Linux, skip the wsl.exe path — run Node locally and point Cursor at http://localhost:8820/<server> or a direct node dist/….js stdio command.

Related MCP server: Hello World MCP Server

Quick start

git clone https://github.com/mwhobrey/wmcp.git
cd wmcp
npm install
npm run build
npm start                    # HTTP front door on :8820
curl http://localhost:8820/health

stdio smoke test (separate terminal):

node dist/example-server.js
# or: node dist/stdio-bridge.js example

Wire Cursor

If transport is "sse" (the default in the example config), start the HTTP server first (npm start) and leave it running. Cursor connects to URLs; nothing is listening otherwise.

Option A — paste a minimal entry (safest; does not touch other MCP servers):

{
  "mcpServers": {
    "example": {
      "url": "http://localhost:8820/example"
    }
  }
}

Add that under your existing mcpServers in Cursor's MCP config, then reload MCP and call ping on example.

For stdio instead of HTTP:

{
  "mcpServers": {
    "example": {
      "command": "node",
      "args": ["/absolute/path/to/wmcp/dist/example-server.js"]
    }
  }
}

Option B — generate configs from this repo (WSL + Windows):

Warning: npm run sync:mcp overwrites ~/.cursor/mcp.json and, when /mnt/c is present, C:\Users\<windowsUser>\.cursor\mcp.json. Back up first if you already have other servers configured.

  1. Copy and edit config:

    cp config/mcp-servers.example.json config/mcp-servers.json
    # set projectRoot, nodePath, wslUser, windowsUser
  2. With the HTTP server running (for "transport": "sse"):

    npm run sync:mcp
  3. Reload MCP in Cursor. Call the ping tool on the example server.

transport in mcp-servers.json:

  • "sse" (default) → Cursor entries are { "url": "http://localhost:8820/example" }http-server must be up

  • "stdio" → Cursor spawns Node (or wsl.exe on Windows) — no shared HTTP process needed

Optional: personas server

Markdown prompt packs with hot reload. Tools:

Tool

Purpose

compose

Merge layers into one system prompt (see order below)

list_prompts

List loaded prompts by category

Also exposes MCP prompts (list / get) for clients that use that capability.

Compose merge order (each layer optional except when base is left on):

  1. base (personas/base) — omitted if base: false

  2. team — repo/org policy card

  3. persona — role

  4. skill — mode

  5. script — playbook

Sections are joined with ---. Template args apply to every included layer.

Enable on the HTTP front door:

cp env.example .env   # then set WMCP_ENABLE_PERSONAS=1
# PERSONAS_DIR=/absolute/path/to/prompts   # optional; default ./prompts

npm start
# → http://localhost:8820/personas

Cursor URL entry:

{
  "mcpServers": {
    "personas": {
      "url": "http://localhost:8820/personas"
    }
  }
}

Or run stdio directly (no WMCP_ENABLE_PERSONAS required):

npm run start:personas
# or: node dist/stdio-bridge.js personas

Sample prompts ship under prompts/ (personas/, skills/, scripts/, teams/). Replace them with your own — edits hot-reload; no restart needed.

Frontmatter shape:

---
name: engineer
description: Short description for list_prompts
category: persona
args:
  - name: stack
    description: Primary tech stack
    required: false
---

# Role: Engineer

{{stack}}Primary stack: {{stack}}.{{/stack}}

Template syntax: {{var}}, {{var|default}}, and {{var}}…{{/var}} (block omitted when unset).

Adding your own MCP server

  1. Create src/my-server.ts — construct an MCP Server, register tools, expose getServer().

  2. Register a factory in src/registry.ts.

  3. Add a servers.my entry in config/mcp-servers.json with "script": "my-server.js".

  4. npm run build && npm run sync:mcp (and restart http-server if using URL mode).

The HTTP and stdio layers stay unchanged. They only need a name → () => Server factory.

Layout

src/
  example-server.ts   # reference MCP tools (echo, ping)
  personas-server.ts  # optional compose / list_prompts
  registry.ts         # name → factory map (+ env toggles)
  http-server.ts      # Streamable HTTP + legacy SSE multiplexer
  stdio-bridge.ts     # named stdio launcher
  env-flags.ts
  is-main-module.ts
prompts/              # sample prompt pack (swap for yours)
config/
  mcp-servers.example.json
scripts/
  sync-mcp-config.mjs
  fix-permissions.mjs
systemd/
  wmcp.service

Environment

Variable

Default

Purpose

MCP_PORT

8820

HTTP listen port

MCP_SSE_PING_MS

30000

SSE keep-alive comment interval (0 disables)

WMCP_ENABLE_PERSONAS

off

Register personas on the HTTP front door (1/true/yes/on)

PERSONAS_DIR

./prompts

Markdown prompt root (personas/, skills/, scripts/, teams/)

See env.example. Load via .env in the project root (dotenv) or export in the shell / systemd unit.

systemd (optional)

# edit User / paths in systemd/wmcp.service first
mkdir -p ~/.config/systemd/user
cp systemd/wmcp.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now wmcp
systemctl --user status wmcp

To enable personas under systemd, set WMCP_ENABLE_PERSONAS=1 in .env (or Environment= in the unit).

Design notes

  • One HTTP process, many logical servers — routes by path prefix; each request gets a fresh MCP Server instance for Streamable HTTP (stateless).

  • Fail per server at boot — a broken factory is skipped; others still serve.

  • Personas are optional — off by default so the public repo stays a transport template; flip the env when you want compose/list_prompts on HTTP. Direct npm run start:personas always works.

  • Private prompt packs stay private — point PERSONAS_DIR at an external directory, or replace prompts/ locally and don't commit company content.

License

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    A simple demonstration server for the Model Context Protocol that provides tools for creating and managing greetings with support for multiple transport methods (stdio, HTTP, SSE).
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A minimal, general-purpose implementation of the Model Context Protocol (MCP) for Node.js and Bare runtime, enabling creation of AI-interactive servers with tools, resources, and multiple transport options.
    6 npm
    2
    MIT