No description
- Python 98.9%
- Dockerfile 1.1%
| app | ||
| config/secrets | ||
| db | ||
| .env.example | ||
| docker-compose.override.yaml.example | ||
| docker-compose.yml | ||
| README.md | ||
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)
- Create a public client (no secret) in your realm, e.g.
claude-skills - Enable Standard Flow + PKCE (S256)
- Add Valid Redirect URI:
https://claude.ai/api/mcp/auth_callback - In
server.py, updateKEYCLOAK_ISSUERandKEYCLOAK_CLIENT_IDto 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
- Go to claude.ai → Settings → Connectors → Add custom connector
- URL:
https://your-domain/mcp - Auth type: OAuth 2.0 — claude.ai will discover the Keycloak auth server via
/.well-known/oauth-protected-resourceautomatically
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