quijutsu-mcp
# quijutsu-mcp
A read-only [Model Context Protocol](https://modelcontextprotocol.io) server for
[QuiJutsu](https://quijutsu.com), an anime trivia PvP game. It lets any MCP client (Claude
Desktop, Claude Code, Cursor, and others) browse QuiJutsu's Community Asset Library, see the
trust record behind each entry, and read player, tournament and contributor leaderboards.
It needs no account and no credentials. It talks to the live game through the same publishable
key the website ships to every browser, and that key can only reach a small, deliberately public
API.
## Quickstart
```bash
npx -y quijutsu-mcp
```
Claude Desktop (`claude_desktop_config.json`) or Claude Code (`.mcp.json`):
```json
{
"mcpServers": {
"quijutsu": {
"command": "npx",
"args": ["-y", "quijutsu-mcp"]
}
}
}
```
Or with the Claude Code CLI:
```bash
claude mcp add quijutsu -- npx -y quijutsu-mcp
```
Streamable HTTP is also built in:
```bash
PORT=3000 npx -y -p quijutsu-mcp quijutsu-mcp-http # MCP endpoint: http://localhost:3000/mcp
```
## Tools
All six are read-only (`readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`,
`openWorldHint: false`) and return `structuredContent` alongside a JSON text block.
| Tool | What it answers |
|---|---|
| `search_assets` | Search the library by name, type, anime title or Spirit Level. Paged, with `total_count`. |
| `get_asset_provenance` | Where an entry came from, how it was reviewed, how strong its source is, and how its Spirit Level was decided, including the full public vote tally. |
| `list_anime_titles` | Titles with public assets, titles open for contribution, and counts by type and Spirit Level. |
| `get_leaderboard` | Top players: casual by season points (monthly, annual, lifetime) or ranked by ELO. |
| `get_tournament_leaderboard` | Tournament standings with win/loss, ELO, accuracy and response time; filter by country. Defaults to the World Anime Tournament. |
| `get_contributor_leaderboard` | Players who build the library, ranked by published entries, sources found and accurate reviews. |
**Spirit Level** is how deep a fan needs to be to know something: 1 is common knowledge, 8 is deep
lore. It starts as a reviewer estimate and is taken over by the community vote; a level is
certified once it crosses the vote threshold.
## Example
> **You:** Is QuiJutsu's entry for Lelouch trustworthy, and who decided how hard it is?
The model calls `get_asset_provenance` with `{"name": "Lelouch"}`:
```json
{
"asset": { "asset_type": "character", "name": "Lelouch Lamperouge", "anime_title": "Code Geass" },
"provenance": {
"origin": "community",
"review_status": "passed",
"evidence_tier": "major",
"question_eligible": true
},
"spirit_level": {
"spirit_level": 5,
"spirit_level_source": "community",
"spirit_level_community_score": 5,
"spirit_level_vote_count": 5,
"spirit_level_certified": false,
"public_poll": {
"total_votes": 2,
"tally": [{ "level": 2, "votes": 1 }, { "level": 5, "votes": 1 }],
"threshold": 10000,
"certified": false
}
}
}
```
So: a player proposed it, independent reviewers confirmed it against a major source, the game may
build questions on it, and its level 5 rating comes from community votes but is not yet certified.
## How access is limited
```
MCP client ──stdio/HTTP──▶ quijutsu-mcp ──publishable key──▶ PostgREST /rpc/<fn>
│
SECURITY DEFINER functions granted to anon
│
tables: RLS on, no anon policy, no anon grant
```
- Every underlying table has row-level security with no anonymous policy. Querying a table
directly with this key returns a permission error.
- The public surface is a short list of `SECURITY DEFINER` Postgres functions with `EXECUTE`
granted to `anon`. This server calls only those, through `src/client.ts`.
- Rows are projected to an allow-list of fields (`pick()` in `src/client.ts`), not stripped. If a
function later gains a column such as a user id, it does not reach the client.
- The server refuses to start if given a secret or service-role key.
- Trivia questions, options and answers are the game itself and are never exposed.
- `npm run smoke` calls every tool against the live API and fails if a response contains a user
id, email, question field or per-viewer field.
## Configuration
Nothing is required. To point at a different QuiJutsu-compatible backend, set:
| Variable | Default |
|---|---|
| `QUIJUTSU_SUPABASE_URL` | QuiJutsu's live project |
| `QUIJUTSU_SUPABASE_ANON_KEY` | its publishable key |
| `QUIJUTSU_DEFAULT_TOURNAMENT_ID` | the World Anime Tournament |
| `PORT` | `3000` (HTTP transport only) |
## The private sibling
QuiJutsu also runs a private MCP server, `quijutsu-question-composer`, that lets authorised
admins compose trivia questions with an AI client. It is the harder problem: OAuth 2.1 against
Supabase Auth with JWKS-verified tokens, time-limited leases on blueprint targets so two composers
never write the same question, idempotency keys on every write so retries are safe, and a
multi-stage server-side evaluation pipeline before anything reaches human review. This public
server shares its conventions (Zod schemas with bounds and descriptions, tool annotations, a
uniform `isError` envelope) without any of its write access.
## Development
```bash
npm install # also builds via prepare
npm run smoke # live end-to-end test over stdio
```
## License
Code: MIT. Community Asset Library data is published under the
[Open Database License (ODbL) 1.0](https://opendatacommons.org/licenses/odbl/1-0/); attribute it
to QuiJutsu (quijutsu.com) when you reuse it.
TDQS
Scored across 6 tools
Each tool has a distinct target: asset search vs. provenance lookup vs. title discovery vs. three separate leaderboard populations. The only mild overlap is between search_assets and list_anime_titles (both help discovery), but descriptions explicitly position list_anime_titles as a 'call this first' helper and search_assets as filterable paging, so misselection is unlikely. The three leaderboard tools are clearly differentiated by audience (players, tournament, contributors).
All six names follow a clean verb_noun snake_case pattern (search_assets, get_asset_provenance, list_anime_titles, get_leaderboard, get_tournament_leaderboard, get_contributor_leaderboard). The leaderboard family shares a predictable prefix/suffix structure, making relationships obvious.
Six tools is well-scoped for a read-only community-asset-and-leaderboard lookup server. Each tool covers a distinct query surface (assets, provenance, titles, three leaderboard types) with no filler.
The read-only lookup lifecycle is largely covered: discovery, search, provenance/trust, and leaderboards. Minor gaps exist — there is no direct get_asset-by-id tool (only search plus optional asset_id on provenance) and no tools for contributing or reviewing assets, which the descriptions imply is a core community workflow.