Skip to main content
Glama

muninn-mcp

Read-only Model Context Protocol server for one Muninn Minecraft backend.

One process always represents exactly one game backend. It has one Muninn base URL, one backend bearer token, and one discovered server_id. Run a separate process for each backend because installed plugins and capabilities can differ.

The default MCP transport is the official stateful Streamable HTTP transport from the MCP TypeScript SDK. Stdio remains available as a fallback.

Requirements

  • Node.js 20 or newer

  • a reachable Muninn plugin HTTP API

  • the backend bearer token from plugins/Muninn/config.yml

This implementation targets Muninn plugin API 0.1.0 at plugin commit 6ef77aafb1cb0f634020d48ca5621885bb103940.

Related MCP server: Discord Message Finder MCP

HTTP-first start

npm ci
npm run build

MUNINN_BASE_URL=http://127.0.0.1:8781 \
MUNINN_AUTH_TOKEN='<Muninn backend token>' \
MUNINN_EXPECTED_SERVER_ID=survival \
MUNINN_MCP_AUTH_TOKEN='<separate MCP client token>' \
npm start

Defaults:

  • transport: http

  • bind: 127.0.0.1

  • port: 3000

  • MCP endpoint: http://127.0.0.1:3000/mcp

  • readiness endpoint: http://127.0.0.1:3000/healthz

The incoming MUNINN_MCP_AUTH_TOKEN is deliberately separate from MUNINN_AUTH_TOKEN. The first protects MCP clients → this process; the second protects this process → the Minecraft backend. Never reuse them.

An HTTP MCP client connects to the URL and supplies the static token:

{
  "mcpServers": {
    "muninn-survival": {
      "url": "http://127.0.0.1:3000/mcp",
      "headers": {
        "Authorization": "Bearer <MUNINN_MCP_AUTH_TOKEN>"
      }
    }
  }
}

The exact client configuration envelope is client-specific; the URL, standard Authorization header, and Streamable HTTP protocol are not.

Readiness needs no token and exposes no configuration secrets:

curl http://127.0.0.1:3000/healthz

The process first discovers the backend through /health and /capabilities. It only starts listening after backend identity and capabilities have passed fail-fast validation.

Stdio fallback

MUNINN_TRANSPORT=stdio \
MUNINN_BASE_URL=http://127.0.0.1:8781 \
MUNINN_AUTH_TOKEN='<Muninn backend token>' \
MUNINN_EXPECTED_SERVER_ID=survival \
npm start

Example stdio client entry:

{
  "mcpServers": {
    "muninn-survival": {
      "command": "node",
      "args": ["/absolute/path/to/muninn-mcp/dist/index.js"],
      "env": {
        "MUNINN_TRANSPORT": "stdio",
        "MUNINN_BASE_URL": "http://127.0.0.1:8781",
        "MUNINN_AUTH_TOKEN": "<Muninn backend token>",
        "MUNINN_EXPECTED_SERVER_ID": "survival"
      }
    }
  }
}

Configuration

MCP transport

Variable

Default

Meaning

MUNINN_TRANSPORT

http

http or stdio.

MUNINN_MCP_BIND

127.0.0.1

HTTP listener hostname or IP.

MUNINN_MCP_PORT

3000

HTTP listener port, 1–65535.

MUNINN_MCP_PATH

/mcp

Exact Streamable HTTP endpoint path.

MUNINN_MCP_AUTH_TOKEN

unset

Incoming static bearer. Optional only on loopback; required for every non-loopback HTTP bind.

MUNINN_MCP_ALLOWED_HOSTS

loopback hosts

Comma-separated hostnames without ports. Required for wildcard binds such as 0.0.0.0.

MUNINN_MCP_ALLOWED_ORIGINS

none

Exact comma-separated browser origins allowed for CORS. Browser Origin requests are rejected by default.

For a private-network listener:

MUNINN_MCP_BIND=0.0.0.0 \
MUNINN_MCP_ALLOWED_HOSTS=minecraft-admin.internal,192.0.2.20 \
MUNINN_MCP_AUTH_TOKEN='<high-entropy token>' \
npm start

The built-in listener is plain HTTP. Do not expose it directly to the public internet. Keep it on loopback/private networking or place TLS and appropriate network controls in front of it.

Muninn backend

Variable

Required

Default

Meaning

MUNINN_BASE_URL

yes

Backend origin or API root. A bare origin gets /api/v1/ appended.

MUNINN_AUTH_TOKEN

yes

Bearer token accepted by the Muninn plugin.

MUNINN_EXPECTED_SERVER_ID

no

Fail-fast backend identity pin; strongly recommended.

MUNINN_TIMEOUT_MS

no

15000

Per-request timeout, 100–120000 ms.

MUNINN_DEFAULT_PAGE_SIZE

no

100

Explicit default for paginated tools.

MUNINN_MAX_PAGE_SIZE

no

100

MCP-side page cap, maximum 1000.

MUNINN_MAX_LOOKUP_SECONDS

no

2592000

MCP-side CoreProtect time-window cap.

MUNINN_MAX_RADIUS

no

128

MCP-side CoreProtect radius cap.

Backend limits remain authoritative and may be stricter.

HTTP security and lifecycle

  • Host validation is port-independent and deny-by-default.

  • Browser requests with an Origin header are denied unless the exact origin is allowlisted. CORS never uses * and never enables credentials.

  • Incoming auth uses constant-time comparison of SHA-256 token digests.

  • Request bodies are parsed only after MCP authentication and are capped at 256 KiB.

  • Neither backend nor incoming bearer values are logged or returned in errors, including nested backend payloads.

  • Each initialize request gets a cryptographically random stateful MCP session, its own official StreamableHTTPServerTransport, and its own McpServer.

  • Subsequent POST/GET/DELETE requests require a valid Mcp-Session-Id.

  • HTTP DELETE terminates a session. SIGINT/SIGTERM stop accepting requests, close all active transports/SSE streams, and close the HTTP server.

  • Sessions are in memory and are not resumable across process restarts; clients initialize again after a restart.

Capability-aware tools

Only tools whose endpoint is present in an enabled module's capability report are registered. CoreProtect tools also require the corresponding feature flag. Restart the process after backend plugin/capability changes to refresh tools/list.

All tools are annotated read-only, non-destructive, and idempotent. The Paper batch endpoint uses HTTP POST but does not mutate game state.

Core and composite

  • server_status

  • investigate_block — bounded Paper/CoreProtect/WorldGuard context with independent probe results

CoreProtect primitives

  • coreprotect_block_lookup

  • coreprotect_container_lookup

  • coreprotect_item_lookup

  • coreprotect_inventory_lookup

  • coreprotect_chat_lookup

  • coreprotect_command_lookup

  • coreprotect_session_lookup

  • coreprotect_sign_lookup

  • coreprotect_username_lookup

  • coreprotect_queue_lookup

Paper primitives

  • paper_get_container

  • paper_batch_containers (1–64 locations)

  • paper_get_player_inventory

  • paper_get_player_ender_chest

  • paper_get_player_state

  • paper_get_player_stats

  • paper_list_players

  • paper_get_server_info

  • paper_list_entities

  • paper_get_block

CMI primitives

  • cmi_list_players

  • cmi_get_player

  • cmi_get_player_homes

  • cmi_list_warps

  • cmi_list_jails

WorldGuard primitives

  • worldguard_list_regions

  • worldguard_get_region

  • worldguard_regions_at

  • worldguard_flags_at

Paginated tools always send explicit bounded offset/limit values and return the backend's has_more marker for deliberate follow-up.

Errors

Muninn envelopes become readable MCP tool errors with stable codes, safe details, HTTP status, backend ID, guidance, and retryability where applicable: UNAUTHORIZED, NOT_FOUND, BAD_REQUEST, SYNC_TIMEOUT, MODULE_DISABLED, FEATURE_UNAVAILABLE, LIMIT_EXCEEDED, PLAYER_OFFLINE, and INTERNAL.

Transport-side errors include TIMEOUT, NETWORK_ERROR, CANCELLED, INVALID_RESPONSE, and SERVER_ID_MISMATCH.

HTTP routing/auth errors use bounded JSON/JSON-RPC bodies and never echo Host, Origin, authorization values, request bodies, or internal exceptions.

Verification

npm ci
npm run check
npm test

The suite covers:

  • HTTP-default and stdio process startup/shutdown;

  • official StreamableHTTPClientTransport initialize, initialized notification, tools/list, tools/call, SSE, and DELETE lifecycle;

  • incoming auth 401, Host/Origin/CORS policy, invalid methods and sessions;

  • non-zero invalid configuration;

  • recursive secret redaction;

  • all 29 atomic tool-to-endpoint mappings and capability filtering.

Real plugin Docker harness

The cross-project test starts the adjacent real Paper+CoreProtect+CMI+WorldGuard fixture, starts the built HTTP MCP process, connects through the official Streamable HTTP client, calls paper_get_server_info, and removes all temporary processes/containers:

npm run test:e2e:harness

By default the plugin checkout is expected at ../muninn-plugin:

MUNINN_PLUGIN_DIR=/absolute/path/to/muninn-plugin npm run test:e2e:harness

An already-running backend can be tested directly:

MUNINN_E2E_BASE_URL=http://127.0.0.1:8781 \
MUNINN_E2E_AUTH_TOKEN='<backend token>' \
MUNINN_E2E_SERVER_ID=survival \
npm run test:e2e

The stdio fallback remains covered by the normal test suite.

Releases and npm publication

Release Please watches conventional commits on main, maintains a release PR, updates CHANGELOG.md, package.json, package-lock.json, and the release manifest, then creates a vX.Y.Z GitHub Release when that release PR is merged. The same workflow checks and tests the released commit before publishing @vanilla-game/muninn-mcp as a public npm package with provenance.

The package is not published yet, so the first release needs a short-lived npm granular access token with permission to create packages in the vanilla-game scope. Store it as the NPM_TOKEN GitHub Actions secret. After the bootstrap publish succeeds, configure npm Trusted Publishing for:

  • GitHub organization: Vanilla-Game

  • repository: muninn-mcp

  • workflow filename: release-please.yml

  • allowed action: npm publish

Then remove the NPM_TOKEN repository secret. Future releases use GitHub OIDC through the workflow's id-token: write permission instead of a long-lived npm credential. The npm package's repository URL must continue to match this GitHub repository exactly.

By default Release Please uses the workflow's GITHUB_TOKEN. An optional RELEASE_PLEASE_TOKEN GitHub secret can supply a GitHub App or fine-grained PAT when repository policy requires release PR events to trigger other workflows.

License

MIT

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

Maintenance

Maintainers
Response time
Release cycle
1Releases (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.

Related MCP Servers

  • F
    license
    C
    quality
    C
    maintenance
    An MCP server that exposes Discord bot actions as tools for LLM clients.
    4
    29
    1
  • A
    license
    -
    quality
    A
    maintenance
    A local MCP server that reads Discord servers and channels and optionally sends messages with explicit allowlists, read-only by default.
    44
    MIT

View all related MCP servers

Related MCP Connectors

  • Scans MCP servers for tool poisoning, prompt injection and supply chain risks.

  • An MCP server for deep research or task groups

  • Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.

View all MCP Connectors

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/Vanilla-Game/muninn-mcp'

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