Skip to main content
Glama
eagleffz

MCP Guidelines Server

by eagleffz

MCP Guidelines Server

A remote MCP server that serves versioned Enterprise & Architecture guidelines (security / architecture / compliance policies) to LLM clients (Claude Desktop, IDE integrations, …) over Streamable HTTP behind static Bearer-token auth. Guidelines are plain Markdown files with YAML frontmatter, indexed in-memory with SQLite FTS5 for ranked full-text search and hot-reloaded on change. Built on the official mcp SDK (FastMCP) and packaged for Docker (e.g. a Synology NAS behind a reverse proxy / Tailscale).

Features

  • Five core MCP tools + find_applicable and two prompts (see Tools).

  • Ranked full-text + tag search (SQLite FTS5, bm25) with highlighted snippets.

  • Hot-reload: edits in the guidelines directory are picked up without a restart (watchdog), with a POST /reload fallback for filesystems where inotify/FSEvents doesn't fire (NAS shares).

  • Schema validation: malformed frontmatter is logged and skipped — never crashes.

  • Static Bearer-token auth; unauthenticated MCP calls get 401. Scopes are modelled (data-model ready) but not enforced in Phase 1.

  • Structured JSON audit logging per tool call; optional Prometheus /metrics.

  • Per-token rate limiting and a /health endpoint for Docker/reverse-proxy.

  • Read-only by design: the server never writes guidelines.

Related MCP server: en-quire

Project layout

src/mcp_guidelines/
  server.py          # composition root: FastMCP, watcher lifecycle, ops routes, entrypoint
  loader.py          # read dir, parse frontmatter, validate, skip-on-error
  models.py          # Pydantic models (frontmatter contract + I/O shapes)
  index.py           # GuidelineIndex: in-memory cache + SQLite FTS5 search
  auth.py            # static bearer tokens, scope model, rate limiter
  tools.py           # MCP tool + prompt registrations
  config.py          # 12-factor env config
  metrics.py         # dependency-free Prometheus counters
  logging_setup.py   # JSON logging to stdout
guidelines/          # seed guidelines (security / architecture / compliance)
tests/               # loader, index/search, auth, tools (MCP protocol), HTTP (401)
Dockerfile  docker-compose.yml  .env.example  pyproject.toml

Installation

Requires Python ≥ 3.11.

# editable install with dev/test extras
pip install -e ".[dev]"
# or, with uv
uv sync

Running locally

AUTH_TOKENS=dev=secret GUIDELINES_PATH=guidelines mcp-guidelines
# equivalently: python -m mcp_guidelines

The MCP endpoint is served at http://<host>:<port>/mcp (Streamable HTTP). Clients MUST send Authorization: Bearer <token>.

curl -s localhost:8000/health           # {"status":"ok","documents":4,"revision":"…"}
# unauthenticated MCP call is rejected:
curl -s -o /dev/null -w '%{http_code}\n' -X POST localhost:8000/mcp \
  -H 'content-type: application/json' -d '{}'        # -> 401

Docker

# create your token(s) first (see "Token generation")
echo 'AUTH_TOKENS=team=PUT-A-REAL-TOKEN-HERE' > .env
docker compose up --build
curl localhost:8000/health               # -> 200, container reports "healthy"

docker-compose.yml mounts ./guidelines read-only into the container, passes config via env vars, defines a healthcheck against /health, and restarts unless stopped. Put the container behind your reverse proxy (Synology / Traefik / nginx) or expose it over Tailscale; terminate TLS there.

Configuration (environment variables)

All configuration is via env vars (12-factor); a .env file is read when present. See .env.example.

Variable

Default

Description

GUIDELINES_PATH

guidelines

Directory of guideline .md files (read-only).

AUTH_TOKENS

(empty)

Comma-separated name=token pairs. Empty ⇒ every MCP call is 401.

AUTH_TOKENS_FILE

(unset)

Path to a JSON secrets file (below); entries override AUTH_TOKENS.

LOG_LEVEL

INFO

DEBUG | INFO | WARNING | ERROR.

HOST

0.0.0.0

Bind address. 0.0.0.0 disables the SDK's DNS-rebind guard (intended behind a proxy).

PORT

8000

Listen port.

RATE_LIMIT

60

Requests per minute per token (0 disables).

ISSUER_URL

http://localhost:8000

OAuth issuer URL, used only for WWW-Authenticate/OAuth metadata.

RESOURCE_SERVER_URL

(unset)

Optional protected-resource metadata URL.

METRICS_ENABLED

true

Expose Prometheus metrics at /metrics.

Token generation

Generate a strong random token and add it to AUTH_TOKENS:

python -c "import secrets; print(secrets.token_urlsafe(32))"
# AUTH_TOKENS=alice=<token1>,bob=<token2>

Secrets file (AUTH_TOKENS_FILE)

For per-token scopes or to keep tokens out of the environment, point AUTH_TOKENS_FILE at a JSON file. File entries override AUTH_TOKENS.

{
  "tokens": [
    { "name": "alice", "token": "…", "scopes": ["read:all"] },
    { "name": "secaudit", "token": "…", "scopes": ["read:security"] }
  ]
}

Scopes are recorded on the token and surfaced to the audit log. Phase 1 does not enforce them — any valid token may read everything. Enforcement is a later phase (set required_scopes in build_auth_settings and/or check tok.scopes in tools._begin). Swapping in real OAuth is a drop-in replacement of StaticTokenVerifier with an introspection verifier (same TokenVerifier protocol).

Guideline frontmatter schema

Each guideline is a Markdown file with a YAML frontmatter block. Place files under category subdirectories of GUIDELINES_PATH (the directory layout is for humans; category comes from the frontmatter, not the path).

---
id: arch-api-design            # required, unique, stable slug ([a-z0-9-])
title: API Design Guidelines   # required
category: architecture         # required, slug (e.g. security|architecture|compliance)
tags: [rest, versioning, http] # optional
version: 2.1.0                 # required, SemVer
status: active                 # required: draft | active | deprecated
owner: platform-team           # required
updated: 2026-06-01            # required, ISO date
applies_to: [backend, api]     # optional: scope/domains (drives find_applicable)
supersedes: arch-api-v1        # optional
---

# API Design Guidelines

… actual content …
  • id and category must be slugs; version must be SemVer; status is one of the three literals. Files that fail validation (bad YAML or schema) are logged and skipped — the server keeps running.

  • Unknown extra frontmatter keys are allowed and ignored.

  • status: deprecated guidelines still appear in search, flagged with a warning (and supersedes when set).

Tools and prompts

Tool

Input

Output

list_guidelines

category?, tag?, status?

summaries (id, title, category, tags, version, status)

get_guideline

id

{ metadata, content, path }

search_guidelines

query, category?, limit?

ranked hits with score, snippet, deprecation warning

list_categories

categories with counts

get_guideline_metadata

id

frontmatter only (token-sparing)

find_applicable

applies_to: [...], category?

active guidelines overlapping the context, ranked by overlap

Prompts: apply_guideline(id, code) (check code against one guideline) and review_against_category(category, code) (review against all active guidelines in a category).

Connecting a client

Use any MCP client that speaks Streamable HTTP. Point it at http://<host>:<port>/mcp with header Authorization: Bearer <token>, e.g.:

npx -y @modelcontextprotocol/inspector
# URL: http://localhost:8000/mcp   Header: Authorization: Bearer <token>

Operational endpoints

Endpoint

Method

Auth

Purpose

/health

GET

public

Liveness/readiness: {status, documents, revision} (Docker healthcheck).

/metrics

GET

public

Prometheus text exposition (when METRICS_ENABLED).

/reload

POST

Bearer

Force a full re-read of the guidelines directory (hot-reload fallback).

/mcp

POST

Bearer

The MCP Streamable HTTP endpoint.

Maintaining guidelines

Guidelines live in a versioned Git repo (keep version/updated current). To add or change one:

  1. Drop or edit a .md file under a category directory in GUIDELINES_PATH.

  2. The file watcher applies the change within moments — no restart needed.

  3. If your filesystem doesn't deliver watch events (some NAS shares), trigger a reload explicitly:

    curl -X POST -H 'Authorization: Bearer <token>' localhost:8000/reload

The server never writes guidelines; all maintenance is via Git/the filesystem.

Development & tests

pip install -e ".[dev]"
pytest -q

Tests cover the loader (skip-on-error), the FTS5 index (ranked search, snippets, category filter, deprecation flagging, hot-reload add/edit/delete), auth (token verification, env+file principal merge, rate limiter), every tool over the real in-memory MCP protocol, and the HTTP surface (/health, the 401 auth gate, and /reload).

Related MCP Connectors

Related MCP Servers