- mcp/http.js: MCP por HTTP (sin estado). Cada petición lleva la contraseña de aplicación del propio usuario (Basic o Bearer); se valida contra WordPress (caché 5 min), exige permiso de edición y no se guarda. Límite por IP, /healthz, IP real reenviada a WordPress. - Herramientas comunes en mcp/src/tools.js (local y remoto); en remoto las fotos van por URL o base64 (sin acceso a archivos del servidor). - Dockerfile del MCP y servicio «mcp» en docker-compose.yml. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bilagun MCP server
Lets an AI assistant (Claude Desktop, Claude Code…) manage the Bilagun website in plain language, through the website's REST API. Examples:
- "Crea la ficha de Kira, perra de unos 2 años, tamaño mediano, muy cariñosa. Déjala en borrador."
- "Marca a Txuri como adoptada."
- "Sube esta foto como principal de Hartz."
- "Añade 'arena para gatos' a lo que necesitamos, en castellano y en euskera."
Tools
| Tool | What it does |
|---|---|
list_animals |
List animals (filter by language, status, species, text) |
get_animal |
Full record: story, profile, translation |
create_animal |
New animal (draft by default). With language: "eu" + translationOf it creates the Basque version and links it |
update_animal |
Change name, story, texts or profile fields |
set_status |
available / pending / adopted (both languages) |
upload_photo |
Upload a JPG/PNG/WebP (local file or URL) as main photo or to the gallery |
get_needs / set_needs |
Material needs list shown on the website (es / eu) |
It can't read the contact messages, delete content or change settings: that stays in the dashboard.
Two ways to run it
| Remote (recommended) | Local | |
|---|---|---|
| Where it runs | On the server, next to WordPress (service mcp in docker-compose.yml) |
On each person's computer |
| What each person needs | A URL and their own application password | Node 20+, this folder, npm install |
| Photos | By URL or dragged into the chat (base64) | Also local file paths |
In both cases every person uses their own WordPress user and application password. The remote server stores no credentials: it checks them against WordPress on each request and forwards them, so each person acts with their own permissions and access can be revoked from the dashboard.
1. Create the access (per person)
-
In WordPress create a user for the person (role Editor is enough).
-
Users → Profile → Application passwords → name it "Asistente" → Add. Copy it (shown only once).
-
Build the credential: base64 of
user:application-password:printf 'asistente:xxxx xxxx xxxx xxxx xxxx xxxx' | base64
2a. Remote server (Dokploy)
After deploying, in Dokploy add a domain to the service mcp, port 3000 (e.g. mcp.gureametsabilagun.pireon.dev, HTTPS on).
Check it: https://mcp.gureametsabilagun.pireon.dev/healthz → {"ok":true}.
Claude Code
claude mcp add --transport http bilagun https://mcp.gureametsabilagun.pireon.dev/mcp \
--header "Authorization: Basic <base64 from step 1>"
Other clients (Cursor, VS Code, Claude Desktop via mcp-remote…): use the same URL and header.
Clients that only allow a Bearer token can use Authorization: Bearer <same base64>.
claude.ai web/mobile "custom connectors" require OAuth login, which this server does not implement yet.
Server settings (environment): BILAGUN_URL (internal WordPress URL, default http://wordpress),
BILAGUN_PUBLIC_URL, RATE_LIMIT (requests per minute and IP, default 120).
It exposes POST /mcp (Streamable HTTP, stateless) and GET /healthz.
2b. Local server (stdio)
cd mcp && npm install
claude mcp add bilagun \
--env BILAGUN_URL=https://gureametsabilagun.pireon.dev \
--env BILAGUN_USER=asistente \
--env "BILAGUN_APP_PASSWORD=xxxx xxxx xxxx xxxx xxxx xxxx" \
-- node /absolute/path/to/mcp/index.js
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"bilagun": {
"command": "node",
"args": ["/absolute/path/to/mcp/index.js"],
"env": {
"BILAGUN_URL": "https://gureametsabilagun.pireon.dev",
"BILAGUN_USER": "asistente",
"BILAGUN_APP_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}
Application passwords only work over HTTPS (the production site already is).