Metadata-Version: 2.5
Name: lorehub-mcp
Version: 0.2.0
Summary: MCP server that lets AI agents read the Meta Areas of a LoreHub dialogue
Project-URL: Homepage, https://lorehub.app
Project-URL: Documentation, https://lorehub.app/mcp
Author: Lostwood Games
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,dialogue,game-development,lorehub,mcp,model-context-protocol,narrative
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Games/Entertainment
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: mcp<3,>=2.3
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# LoreHub MCP

<!-- mcp-name: io.github.lostwood-games/lorehub-mcp -->

An MCP server that lets AI agents (Claude, Cursor and any other MCP client) read the **Meta Areas** of a [LoreHub](https://lorehub.app) dialogue.

A director draws Meta Areas on the Dialogue Builder canvas: a shot, a location, a mood, with a note, a priority and meta rules such as `shot = close_up`. With this server, your agent reads those areas and the nodes inside them, and turns them into references, shot lists or mood boards. It only reads: it never changes your world.

More on the [LoreHub MCP page](https://lorehub.app/mcp) and in the [Meta Areas guide](https://lorehub.app/meta-areas-guide).

## Install

You need a LoreHub account with at least Viewer access to the world, and [uv](https://docs.astral.sh/uv/getting-started/installation/). Nothing else to install: `uvx` downloads and runs the server.

### Create an API key

In LoreHub, open **Profile → API keys**, give the key a name (for example "Claude Desktop") and select **Create key**. Copy the key, which starts with `lh_`: LoreHub shows it only once.

The key is read-only. LoreHub accepts it only for reading what your account can see, never to change anything, and never for your account, password or billing. You don't put your password anywhere. If a key leaks, or you stop using it, revoke it on the same page and it stops working at once.

```bash
uvx lorehub-mcp
```

Or with pip: `pip install lorehub-mcp`, then run `lorehub-mcp`.

### Claude Code

```bash
claude mcp add lorehub --env LOREHUB_API_KEY=lh_your-key -- uvx lorehub-mcp
```

### Claude Desktop

Settings → Developer → Edit Config, then add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "lorehub": {
      "command": "uvx",
      "args": ["lorehub-mcp"],
      "env": {
        "LOREHUB_API_KEY": "lh_your-key"
      }
    }
  }
}
```

### Cursor

Add the same block to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (one project):

```json
{
  "mcpServers": {
    "lorehub": {
      "command": "uvx",
      "args": ["lorehub-mcp"],
      "env": {
        "LOREHUB_API_KEY": "lh_your-key"
      }
    }
  }
}
```

Other MCP clients work the same way: run `uvx lorehub-mcp` over stdio with `LOREHUB_API_KEY` set.

### Upgrading from 0.1

0.1 signed in with `LOREHUB_LOGIN` and `LOREHUB_PASSWORD` (or `LOREHUB_TOKEN`). 0.2 no longer reads them. Create an API key, put it in `LOREHUB_API_KEY`, and delete the login and password from your MCP config. If that config was ever shared or synced, change your LoreHub password too.

## Find your world and dialogue ids

You don't need to look them up yourself. Ask the agent, for example *"List my LoreHub worlds, then find the dialogue Tom at Grandpa's and give me its Meta Areas"*, and it calls `list_worlds`, `list_dialogues` and `get_dialogue_meta` in turn.

To copy them by hand: open the dialogue in the Dialogue Builder. The address looks like `app.lorehub.app/<owner>/<world>/game/<story id>?dialogue=<dialogue id>`, so the dialogue id is after `?dialogue=`. The world id comes from `list_worlds`.

## Tools

| Tool | What it returns |
| --- | --- |
| `list_worlds()` | The worlds your account can open, with their ids and your role. |
| `list_dialogues(world_id, game_id?, name?)` | Stories and their dialogues with ids. `name` filters by dialogue name. |
| `get_dialogue_meta(world_id, dialogue_id, area?, include_nodes=true)` | Each Meta Area's title, note, priority and meta rules as `field name: value`, the nodes inside it, and the nodes where areas overlap (higher priority first). `area` filters by title text or area id. |

Example output of `get_dialogue_meta`:

```json
{
  "dialogue": "Tom at Grandpa's",
  "dialogue_id": "…",
  "areas": [
    {"title": "Grandpa's house: wide", "priority": 1,
     "rules": {"shot": "wide", "background": "grandpas_house"},
     "nodes": ["dlg.n_01", "dlg.n_04"], "id": "…"},
    {"title": "Close-up: Tom is crying", "note": "Tears, low light", "priority": 2,
     "rules": {"shot": "close_up", "background": "grandpas_house", "tom_emotion": "crying"},
     "nodes": ["dlg.n_04"], "id": "…"}
  ],
  "overlaps": [{"node": "dlg.n_04", "areas": ["Close-up: Tom is crying (P2)", "Grandpa's house: wide (P1)"]}]
}
```

## Configuration

| Variable | Default | |
| --- | --- | --- |
| `LOREHUB_API_KEY` | | Required. Your read-only API key from Profile → API keys. |
| `LOREHUB_API_URL` | `https://api.lorehub.app` | Must be `https://` and a `lorehub.app` host (plain `http://` only for `localhost`), so the key can't be sent anywhere else. |
| `LOREHUB_ALLOW_CUSTOM_API_URL` | | Set to `1` only if you run LoreHub on your own HTTPS host. |
| `LOREHUB_TIMEOUT` | `30` | Seconds per request. |
| `LOREHUB_LOG_LEVEL` | `INFO` | Logs go to stderr. |
| `LOREHUB_NODE_WIDTH`, `LOREHUB_NODE_HEADER_HEIGHT` | `200`, `32` | The canvas node card size. Leave them as they are. |

## How it works

The server makes GET calls to the LoreHub API with your API key: the dialogue's Meta Areas, its name and story, the story's meta schema (to turn rule ids into field names) and the node positions. A node is inside an area when the middle of its header is, the same rule the Dialogue Builder uses.

Security: ids must be GUIDs, so a crafted id can't reach other API endpoints. The server doesn't follow redirects, doesn't log the key, and doesn't pass the API's error text on to the agent. Area titles, notes and rule values are written by your world's collaborators, so the server tells the agent to treat them as data, not instructions.

Not yet: nodes come back as full ids, without their line text or speaker.

## License

MIT
