No description
  • Python 98.9%
  • Dockerfile 1.1%
Find a file
2026-04-06 20:51:38 +02:00
app fix: log real client IP via X-Forwarded-For (proxy_headers=True) 2026-04-06 20:41:21 +02:00
config/secrets Initialize memory mcp for claude-skills 2026-04-06 20:37:48 +02:00
db Initialize memory mcp for claude-skills 2026-04-06 20:37:48 +02:00
.env.example add .env.example 2026-04-06 20:51:38 +02:00
docker-compose.override.yaml.example Initialize memory mcp for claude-skills 2026-04-06 20:37:48 +02:00
docker-compose.yml Initialize memory mcp for claude-skills 2026-04-06 20:37:48 +02:00
README.md Initialize memory mcp for claude-skills 2026-04-06 20:37:48 +02:00

claude-skills

Persistent skill memory for Claude — an MCP server that stores and retrieves per-skill key/value memories in MariaDB.

Skills (recipes, projects, …) can read and write their own memory namespace so that context survives across conversations.

Architecture

Claude Code / claude.ai
        │
        │ Bearer token (static)   or   Keycloak JWT (OAuth 2.0 + PKCE)
        ▼
  FastMCP / Starlette  (POST /mcp)
        │
        ▼
  MariaDB  ·  claude_skills.memories

Transport: Streamable HTTP (MCP 2025-03-26)
Auth (two-tier):

  • Claude Code / local: static Bearer token from config/secrets/local_api_token.txt
  • claude.ai Custom Connector: Keycloak OAuth 2.0 Authorization Code + PKCE — the server exposes /.well-known/oauth-protected-resource (RFC 9728) which points claude.ai to your Keycloak realm for the OAuth flow

MCP Tools

Tool Description
skill_memory_read(skill, key?) Read one key or all keys for a skill
skill_memory_write(skill, key, value) Save / overwrite a key (UPSERT)
skill_memory_append(skill, key, entry) Append to a list-style key
skill_memory_list(skill?) List all skills and their keys
skill_memory_delete(skill, key) Delete a single key

Setup

1. Prerequisites

  • Docker + Docker Compose v2
  • MariaDB (or MySQL) — can be a separate host or a container
  • (Optional) Keycloak for claude.ai OAuth

2. Database

Run db/schema.sql once as an admin user — adjust the host restriction and password before running:

# edit db/schema.sql: replace YOUR_APP_HOST_IP and CHANGE_ME
mysql -u root -p < db/schema.sql

3. Secrets

Create the three secret files (plain text, no trailing newline needed):

config/secrets/local_api_token.txt   # any strong random token
config/secrets/db_user.txt           # claude_skills
config/secrets/db_password.txt       # the password from schema.sql

Generate a token:

openssl rand -hex 32 > config/secrets/local_api_token.txt

4. Environment

cp .env.example .env
# edit .env: set DOMAIN and DB_HOST

5. Traefik (optional)

If you use Traefik as a reverse proxy:

cp docker-compose.override.yaml.example docker-compose.override.yaml
# edit: replace YOUR_DB_HOST_IP, verify network names

docker-compose.override.yaml is gitignored — all infra-specific labels live there, keeping the base docker-compose.yml portable.

6. Start

docker compose up -d
docker compose ps

Health check: curl http://localhost:8080/health

Keycloak Setup (for claude.ai)

  1. Create a public client (no secret) in your realm, e.g. claude-skills
  2. Enable Standard Flow + PKCE (S256)
  3. Add Valid Redirect URI: https://claude.ai/api/mcp/auth_callback
  4. In server.py, update KEYCLOAK_ISSUER and KEYCLOAK_CLIENT_ID to match

Claude Code Setup

Add to .mcp.json:

{
  "mcpServers": {
    "claude-skills": {
      "type": "http",
      "url": "https://your-domain/mcp",
      "headers": {
        "Authorization": "Bearer <content of local_api_token.txt>"
      }
    }
  }
}

claude.ai Custom Connector

  1. Go to claude.ai → Settings → Connectors → Add custom connector
  2. URL: https://your-domain/mcp
  3. Auth type: OAuth 2.0 — claude.ai will discover the Keycloak auth server via /.well-known/oauth-protected-resource automatically

Project Layout

.
├── app/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── server.py                  # FastMCP app + auth middleware
├── config/
│   └── secrets/                   # gitignored *.txt files
├── db/
│   └── schema.sql                 # DB + user + table DDL (run once)
├── docker-compose.yml             # generic base
├── docker-compose.override.yaml.example  # Traefik template (copy & adapt)
└── .env.example