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

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mwhobrey/wmcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server