Skip to main content
Glama
zh

Redmine MCP OAuth Server

by zh

title: Redmine MCP emoji: ๐Ÿ”ง colorFrom: blue colorTo: indigo sdk: docker app_port: 7860 pinned: false

Redmine MCP OAuth Server

A FastMCP HTTP server that exposes 53 Redmine REST endpoints as Model-Context-Protocol tools, behind an OAuth 2.1 Authorization Code flow with mandatory PKCE.

The user logs in with their own Redmine URL + API key โ€” the server holds no second account. The API key is validated against /users/current.json, then mapped to a bearer token used by every subsequent MCP tool call.

Current version: 1.7 (CHANGELOG.md)

Related MCP server: Redmine MCP Server

Contents

Features

  • OAuth 2.1 authorization-code flow with mandatory PKCE S256.

  • RFC 7591 Dynamic Client Registration so MCP clients can self-register.

  • RFC 8252 loopback redirect URIs auto-allowed (works with every desktop MCP client out of the box).

  • Refresh tokens with rotation (RFC 6749 ยง6) โ€” single-use, rolling 30-day TTL.

  • RFC 7009 revocation at POST /oauth/revoke.

  • CSRF-protected login form with itsdangerous-signed cookies.

  • SSRF defense on the user-supplied Redmine URL โ€” DNS-resolved IPs in private / loopback / link-local / multicast / reserved space are refused. httpx.AsyncClient(follow_redirects=False) closes 302 bypasses.

  • Per-IP rate limiting on /auth/login (5/min + 20/hour), /oauth/token (10/min), and /oauth/register (5/min).

  • Pluggable token store โ€” in-memory by default; opt-in Redis backend with Fernet at-rest encryption of API keys.

  • Structured JSON audit log to stdout, with per-request IDs.

  • Sanitized upstream errors โ€” Redmine's raw response bodies (version banners, plugin names, occasional stack traces) never reach the MCP client. Just Permission denied. / Not found. / Upstream Redmine error. / parsed 422 validation errors.

  • Confirm gate on every destructive tool (delete_* requires confirm=True).

  • Health & version endpoints (/healthz, /readyz, /version).

  • Portable Docker image โ€” runs unchanged on Hugging Face Spaces (port 7860), Render, Fly.io, Cloud Run, and self-hosted Docker.

Quick start (local Docker)

git clone <repo> && cd redmine_mcp_py
cp .env.example .env

# 1. Generate the secret that signs CSRF cookies
python3 -c 'import secrets; print(secrets.token_urlsafe(32))'
# Paste into .env as REDMINE_MCP_SECRET=...

# 2. (Optional) generate a Fernet key if you want Redis persistence later
python3 -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'

# 3. Run it
docker compose up --build

Open http://localhost:8000/healthz โ€” should return {"status": "ok"}. The MCP endpoint is http://localhost:8000/mcp.

Configuration

All knobs are env-var-driven. Defaults are safe for local dev and production alike, except where noted.

Required

Variable

Notes

REDMINE_MCP_SECRET

32+ random bytes; signs CSRF cookies. Generate with python -c 'import secrets; print(secrets.token_urlsafe(32))'. A fresh per-process value is auto-generated when unset, which means restarts invalidate in-flight CSRF cookies โ€” fine for dev, set it explicitly in production.

Variable

Default

Notes

REDMINE_MCP_ALLOWED_HOSTS

(empty)

CSV of Redmine hostnames the server is allowed to call. Empty = any public hostname (private/loopback IPs still blocked). The strongest SSRF defense.

REDMINE_MCP_TRUST_PROXY

false

Set true when behind a known reverse proxy (HF Spaces, Render, Caddy, nginx). Required for correct rate-limit attribution.

REDMINE_MCP_REDIS_URL

(empty)

e.g. redis://redis:6379/0. Enables the Redis-backed token store so sessions, codes, and rate counters survive restarts.

REDMINE_MCP_FERNET_KEY

(empty)

Required when REDMINE_MCP_REDIS_URL is set. Encrypts API keys at rest. Generate with python -c 'from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())'.

Token lifetimes (seconds)

Variable

Default

Notes

REDMINE_MCP_TOKEN_TTL_SECONDS

86400

Access-token TTL.

REDMINE_MCP_REFRESH_TTL_SECONDS

2592000 (30d)

Refresh-token TTL. Rolls on each use.

REDMINE_MCP_CODE_TTL_SECONDS

300

Authorization-code TTL.

REDMINE_MCP_CLIENT_TTL_SECONDS

2592000 (30d)

DCR client record TTL (Redis only).

Rate limits (per IP)

Variable

Default

REDMINE_MCP_RATE_LOGIN_PER_MIN

5

REDMINE_MCP_RATE_LOGIN_PER_HOUR

20

REDMINE_MCP_RATE_TOKEN_PER_MIN

10

REDMINE_MCP_RATE_REGISTER_PER_MIN

5

Other knobs

Variable

Default

Notes

REDMINE_MCP_TIMEOUT_SECONDS

30

Per-call timeout for outbound Redmine HTTP.

REDMINE_MCP_ALLOWED_REDIRECTS

(empty)

CSV of OAuth redirect_uri values for non-loopback web MCP clients. Loopback URIs (http://127.0.0.1:*, localhost:*, [::1]:*) are auto-allowed per RFC 8252.

REDMINE_MCP_ALLOW_HTTP

false

Dev only. Permits http:// Redmine URLs, bare IP hosts, and drops the Secure flag from the CSRF cookie (needed for plain http://localhost).

PORT

7860

Listen port. HF Spaces uses 7860; Render/Fly/Cloud Run inject their own.

Deployment

Docker Compose (local or self-hosted)

docker-compose.yml ships with sensible local-dev defaults. Two profiles:

# In-memory store (default profile, ephemeral)
docker compose up --build

# Redis-backed store (sessions survive restart)
docker compose --profile redis up --build

The Redis profile starts a sibling redis:7-alpine with a persistent volume and a healthcheck. Set the corresponding env vars first:

REDMINE_MCP_REDIS_URL=redis://redis:6379/0
REDMINE_MCP_FERNET_KEY=<paste-Fernet.generate_key()-output>

Hugging Face Spaces

The README.md frontmatter (top of this file) is HF metadata; HF reads sdk: docker and app_port: 7860 and runs the bundled Dockerfile.

  1. Push the repo to a Space with sdk: docker.

  2. In Settings โ†’ Variables and secrets, set:

    • REDMINE_MCP_SECRET (required โ€” generate fresh)

    • REDMINE_MCP_TRUST_PROXY=true (HF sits behind a proxy)

    • REDMINE_MCP_ALLOWED_HOSTS=<your-redmine-host> (recommended)

  3. Restart the Space.

โš  HF Spaces free tier sleeps after 15 min idle โ€” cold start wipes the in-memory token store, forcing users to reconnect. For always-on behavior either upgrade to a paid tier or enable Redis (point REDMINE_MCP_REDIS_URL at an external Redis like Upstash, since HF doesn't provide one).

Render

The repo includes render.yaml for one-click Blueprint deploys.

  1. Push to GitHub/GitLab.

  2. Render dashboard โ†’ New + โ†’ Blueprint โ†’ connect the repo โ†’ Apply.

  3. In the service's Environment tab, fill in the two sync: false values:

    • REDMINE_MCP_ALLOWED_HOSTS (recommended โ€” CSV of permitted Redmine hostnames)

    • REDMINE_MCP_ALLOWED_REDIRECTS (leave empty for desktop MCP clients)

  4. First build takes ~3 min. You get https://redmine-mcp-XXXX.onrender.com.

The blueprint defaults to plan: free, which sleeps after 15 min idle like HF. Change to plan: starter ($7/mo) for always-on, or keep free and add Render's Key Value (Redis-compatible) addon for persistence across cold starts.

Fly.io, Cloud Run, Railway, plain VPS

The Dockerfile listens on ${PORT:-7860} and runs as UID 1000 with a baked-in HEALTHCHECK. It works unchanged on any platform that builds a Dockerfile.

Minimum env vars: REDMINE_MCP_SECRET, REDMINE_MCP_TRUST_PROXY=true (when behind a proxy), and ideally REDMINE_MCP_ALLOWED_HOSTS.

For self-hosted behind nginx / Caddy / Traefik, terminate TLS at the proxy and forward to the container's ${PORT}. Add proxy_set_header X-Forwarded-For $remote_addr; (nginx) or equivalent so rate-limit attribution works.

OAuth flow

User clicks "Connect" in Claude Desktop / Coworks / custom MCP client
  โ†“
GET  /oauth/register              (DCR โ€” client registers its redirect_uri)
  โ†“
GET  /auth/authorize?response_type=code
                    &client_id=<dcr-issued>
                    &redirect_uri=http://127.0.0.1:<port>/callback
                    &code_challenge=<S256(verifier)>
                    &code_challenge_method=S256
                    &state=<csrf-state>
  โ†’ server returns the HTML login form + a CSRF cookie
  โ†“
POST /auth/login                  (user submits Redmine URL + API key)
  โ†’ server validates creds against /users/current.json on that URL
  โ†’ server mints a single-use auth code, 302s to redirect_uri?code=...&state=...
  โ†“
POST /oauth/token                 (PKCE verification, code exchange)
  โ†’ server returns {access_token, refresh_token, token_type, expires_in}
  โ†“
Every MCP tool call carries the access_token as Bearer
  โ†’ looked up in the token store โ†’ Redmine API key extracted โ†’ upstream call
  โ†“
POST /oauth/token (grant_type=refresh_token) once the access token expires
  โ†’ old refresh_token consumed atomically (GETDEL in Redis), new pair issued
  โ†“
POST /oauth/revoke (optional, on logout)

The user only ever supplies their own Redmine credentials โ€” no second account is required on the MCP server side.

Adding the server to an MCP client

Claude Desktop, Claude Code, Coworks, โ€ฆ

Settings โ†’ Connectors โ†’ Add custom connector โ†’ URL = https://your-server/mcp.

OAuth Client ID and Secret can be left blank โ€” the server is a public OAuth client (token_endpoint_auth_method: none). The real credential is the user's Redmine API key, captured during /auth/login.

From the Anthropic API or other MCP SDKs

Use the standard MCP streamable-http transport pointed at https://your-server/mcp. The SDK handles DCR + PKCE automatically.

Tools implemented

All 53 tools accept structured arguments and return raw Redmine JSON (or {} for 204 No Content responses). Tools that mutate state require their respective Redmine role/permission. Destructive delete_* tools require confirm=True.

Category

Tools

Projects

list_projects, get_project, create_project, update_project, delete_project

Issues

list_issues, get_issue, create_issue, update_issue, delete_issue, copy_issue, move_issue, add_issue_watcher, remove_issue_watcher, get_issue_relations, create_issue_relation, delete_issue_relation, get_issue_journals

Users

list_users, get_user, create_user, update_user, delete_user

Time entries

list_time_entries, get_time_entry, create_time_entry, update_time_entry, delete_time_entry

Memberships

list_memberships, get_membership, create_membership, update_membership, delete_membership

Groups

list_groups, get_group, create_group, update_group, delete_group

Versions

list_versions, get_version, create_version, update_version, delete_version

Custom fields

list_custom_fields

Queries

list_queries

limit parameters are clamped to 1..100 (Redmine's hard server-side max). create_issue_relation.relation_type, create_version.status, and create_version.sharing use typing.Literal so the MCP tool schema surfaces the allowed values to the LLM.

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  MCP client          โ”‚  Claude Desktop / Coworks / custom SDK
โ”‚  (loopback callback) โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
           โ”‚ HTTPS
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FastAPI app (server.py)                                               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  RequestIDMiddleware   โ†’  contextvar request_id                   โ”‚  โ”‚
โ”‚  โ”‚  SecurityHeadersMiddleware โ†’ HSTS, CSP, X-Frame-Options, โ€ฆ        โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  auth/routes.py         โ”‚  โ”‚  53 MCP tools (FastMCP)            โ”‚   โ”‚
โ”‚  โ”‚  /auth/authorize        โ”‚  โ”‚  list_issues, create_project, โ€ฆ    โ”‚   โ”‚
โ”‚  โ”‚  /auth/login            โ”‚  โ”‚  call _redmine() โ†’ outbound httpx  โ”‚   โ”‚
โ”‚  โ”‚  /oauth/token           โ”‚  โ”‚  with SSRF re-validation + audit   โ”‚   โ”‚
โ”‚  โ”‚  /oauth/revoke          โ”‚  โ”‚                                    โ”‚   โ”‚
โ”‚  โ”‚  /oauth/register        โ”‚  โ”‚                                    โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                โ”‚                           โ”‚                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  auth/token_store.py โ€” TokenStore Protocol                      โ”‚   โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚   โ”‚
โ”‚  โ”‚  โ”‚ InMemoryTokenStore  โ”‚ OR โ”‚ RedisTokenStore                โ”‚  โ”‚   โ”‚
โ”‚  โ”‚  โ”‚ (default)           โ”‚    โ”‚ (Fernet-encrypted API keys)    โ”‚  โ”‚   โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  audit.py โ€” one-line JSON to stdout                             โ”‚   โ”‚
โ”‚  โ”‚  login_ok / login_rejected / token_issued / token_refreshed /   โ”‚   โ”‚
โ”‚  โ”‚  token_revoked / rate_limit_exceeded / redmine_call             โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                            โ”‚
                                            โ”‚ httpx, follow_redirects=False
                                            โ–ผ
                              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                              โ”‚  User's Redmine instance      โ”‚
                              โ”‚  X-Redmine-API-Key: <secret>  โ”‚
                              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Key invariants:

  • API keys are wrapped in RedactedStr (returns '***' from repr/ str); they only reach the outbound HTTP path via .reveal().

  • Every outbound URL is re-validated against the SSRF block-list on every call, not just at login.

  • The CSRF cookie is HttpOnly, SameSite=Lax, Secure (unless REDMINE_MCP_ALLOW_HTTP=true), path-scoped to /auth/.

  • Audit records never contain API keys, query params, request bodies, or response bodies โ€” only method, path, status, latency, and the operator's Redmine login.

Security

SECURITY.md documents the threat model, every defect found during the Phase 0 review, the fix, and the regression test that pins it.

Vulnerabilities should be reported privately to the maintainer rather than as a public GitHub issue.

Testing

pip install -r requirements.txt
pip install pytest pytest-asyncio respx
pytest

Currently 60 tests covering Phase 0 + Phase 1 (~2s on a laptop) plus 2 opt-in Redis tests, run with:

docker run --rm -d -p 6379:6379 --name redis-test redis:7-alpine
REDMINE_MCP_TEST_REDIS_URL=redis://localhost:6379/15 pytest
docker stop redis-test

Roadmap

TODO.md tracks remaining work. Phase 0 (critical security) and Phase 1 (high-priority hardening) are complete. Phase 2 (reliability + code quality: modularization, shared httpx client, retries, CI, ruff/mypy) and Phase 3 (operability: Prometheus metrics, pydantic-settings, multi-stage Dockerfile) are the next chunks.

License

MIT

A
license - permissive license
-
quality - not tested
B
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/zh/redmine_mcp_py'

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