Content
# danbooru-mcp
Standalone MCP server for local Danbooru tag embedding search and validation.
The intended workflow is:
1. The LLM client splits the user request into short visual units.
2. The LLM calls this MCP server for Danbooru tag candidates.
3. The LLM chooses the best candidates and writes the prompt.
4. The LLM calls this MCP server again to validate the final tags.
The server does not call an LLM. It only provides local embedding search,
metadata lookup, and tag validation.
## Tools
- `search_tags`: search candidates for one short search unit.
- `search_tags_batch`: search candidates for multiple short search units.
- `validate_tags`: validate final tags against the local CSV and optionally
search suggestions for invalid tags.
- `get_tag_info`: return category, frequency, Korean definition, and aliases.
- `health`: check local CSV/index paths.
## Files
The project is self-contained. By default it uses paths under this directory:
```text
danbooru-tags.csv required source CSV
models/ downloaded embedding model
data/lancedb_b/ built LanceDB index
.env optional local overrides
```
The CSV must have this header/order:
```csv
name,category,post_count,description
```
Category meanings:
```text
0 general
1 artist
3 copyright
4 character
5 meta
```
## Install
Recommended:
```bash
cd /path/to/danbooru-mcp
uv sync
```
Alternative:
```bash
pip install -e .
```
If you need a specific CUDA build of torch, install that first according to your
GPU environment, then install this package.
## Setup
1. Put `danbooru-tags.csv` in the project root.
2. Download the embedding model:
```bash
uv run danbooru-mcp-download-model
```
This downloads `intfloat/multilingual-e5-large` to `models/multilingual-e5-large`.
3. Build the default index, variant `b`:
```bash
uv run danbooru-mcp-build-index
```
Variant `b` embeds English tag name + Korean aliases. It is the default because
mixed Korean/English prompt units tend to work well with it.
Optional variants:
```bash
uv run danbooru-mcp-build-index a
uv run danbooru-mcp-build-index c
uv run danbooru-mcp-build-index --all
```
Variants:
```text
a = English tag name + Korean definition + aliases
b = English tag name + Korean aliases
c = Korean definition + aliases, falling back to English tag name when needed
```
## Run
Stdio transport:
```bash
uv run danbooru-mcp
```
MCP config example:
```json
{
"mcpServers": {
"danbooru": {
"command": "uv",
"args": ["run", "danbooru-mcp"],
"cwd": "/path/to/danbooru-mcp",
"env": {
"EMBEDDING_DEVICE": "cpu"
}
}
}
}
```
For GPU search/model loading:
```json
{
"env": {
"EMBEDDING_DEVICE": "cuda"
}
}
```
HTTP transport:
```bash
CUDA_VISIBLE_DEVICES=1 uv run danbooru-mcp --transport http --host 127.0.0.1 --port 8000
```
The MCP endpoint is `POST http://127.0.0.1:8000/mcp`. You can also use the
dedicated script:
```bash
CUDA_VISIBLE_DEVICES=1 uv run danbooru-mcp-http
```
HTTP environment variables:
```text
DANBOORU_MCP_TRANSPORT=stdio|http|sse
DANBOORU_MCP_HOST=127.0.0.1
DANBOORU_MCP_PORT=8000
DANBOORU_MCP_HTTP_PATH=/mcp
DANBOORU_MCP_SSE_PATH=/sse
DANBOORU_MCP_MESSAGES_PATH=/messages
DANBOORU_MCP_CORS_ORIGIN=*
DANBOORU_MCP_MAX_BODY_BYTES=10485760
```
SSE transport:
```bash
CUDA_VISIBLE_DEVICES=1 uv run danbooru-mcp --transport sse --host 127.0.0.1 --port 8000
```
The SSE stream endpoint is `GET http://127.0.0.1:8000/sse`. The server sends
an `endpoint` event containing the session-specific message URL, for example
`/messages?session_id=...`. MCP clients then `POST` JSON-RPC messages to that
URL and receive JSON-RPC responses through `message` events on the SSE stream.
You can also use the dedicated script:
```bash
CUDA_VISIBLE_DEVICES=1 uv run danbooru-mcp-sse
```
## Environment
Copy `.env.example` to `.env` if you want local overrides:
```bash
cp .env.example .env
```
Supported variables:
```text
EMBEDDING_DEVICE=cpu|cuda
DATA_DIR=/path/to/data
MODELS_DIR=/path/to/models
DANBOORU_TAGS_CSV=/path/to/danbooru-tags.csv
DANBOORU_INDEX_VARIANT=b
EMBED_BATCH_SIZE=256
MIN_FREQUENCY=50
```
## Recommended LLM Workflow
Avoid sending a long full sentence as one `query`. Embeddings will average many
concepts together and the top candidates become noisy.
Better:
```json
{
"queries": ["은발", "트윈테일", "빨간 눈", "비 오는 거리", "우산"],
"top_k": 8,
"categories": ["general"]
}
```
Search responses are compact by default to keep MCP context small. Results
normally include only `tag` and `score`. Pass `"include_details": true` when
you need category, frequency, definition, hierarchy, or aliases.
Then choose from returned candidates and validate the final list:
```json
{
"tags": ["grey_hair", "twintails", "red_eyes", "rain", "umbrella"]
}
```
The validator accepts underscore and space forms. If the CSV canonical tag is
`grey hair`, `grey_hair` is normalized to `grey hair`.
## Notes
- First search loads the embedding model and can take several seconds.
- Building the index is the expensive step. GPU is recommended.
- The server writes MCP protocol messages only to stdout. Model progress output
is redirected to stderr so stdio MCP clients are not corrupted.
## Credit
https://github.com/joykst96/danbooru-tag-rag