Skip to main content
Glama

campaign-source-mcp

Local read-only MCP router/search server for user-provided module/source cards.

Released under the MIT License. No books or existing campaign data are bundled. Bring your own source cards and keep private campaign data in a separate source directory.

Install independently

Requires Node.js >=18 and npm. Python 3 is needed only for the optional installer. rg (ripgrep) is optional; the runtime has a JavaScript search fallback. Clone this repository into a new directory:

git clone https://github.com/OliverCheng178149/campaign-source-mcp.git
cd campaign-source-mcp
npm ci
npm test
npm run demo

npm test runs only self-contained synthetic tests. npm run demo exercises all six MCP tools against examples/synthetic-library over stdio. Those files are original invented examples, with recognizable directory/alias names used only to exercise routing. They contain no published book text or player saves. The configured MCP process reads user-provided sources; no source files need to be copied into this software checkout.

Related MCP server: studyproof

Configure an MCP host

Adapt this example in your host's MCP settings (absolute paths are required; replace the placeholders). The host must be able to find node, or use the absolute path to your chosen Node executable.

{
  "mcpServers": {
    "campaign-source": {
      "command": "node",
      "args": ["/absolute/path/campaign-source-mcp/src/index.js"],
      "env": {
        "CAMPAIGN_SOURCE_PATH": "/absolute/path/your-source-library",
        "CAMPAIGN_SOURCE_LABEL": "My local source library"
      }
    }
  }
}

For an isolated demo use the absolute path to examples/synthetic-library as CAMPAIGN_SOURCE_PATH. Starting the normal server waits for MCP stdio input; its protocol output is not a human-facing CLI. Source roots may contain text cards (.md, .txt, .json, .yaml, .yml), top-level module directories, optional root routers, and optional _full_source*.md page-anchored caches. Arbitrary top-level directories work via search_campaign_sources or search_campaign_module(module="your-directory", query="..."); existing book/module aliases remain available. See docs/building-a-source-library.md for one way to build a library from material you are entitled to use.

Optional installer

Ordinary npm ci is the independent installation path. To copy maintained files elsewhere, without modifying campaign configuration:

python3 campaign_source_mcp_installer.py --server-root /absolute/path/new-server
cd /absolute/path/new-server
npm ci
npm test

With no arguments the installer targets its own checkout and configures no campaign. Dependencies are never borrowed automatically. Advanced users can explicitly pass --node-modules /absolute/path/existing/node_modules to link an existing dependency directory; independent npm installation is preferred. Only explicit --repo /absolute/path/campaign arguments update that repo's existing .mcp.json, preserving other MCP server entries. Such a repo must have lore/source_materials; review/backup its configuration first. Startup, skill, protocol, and campaign framework files are not rewritten by main().

Optional real-library integration tests

The original eight protocol tests requiring installed books are preserved in test/integration/protocol.test.js, separate from the synthetic default suite. They assert particular cache files, physical line numbers, and OCR layouts; any arbitrary library will not satisfy them. Run them only against an isolated copy of the expected private test library that you are entitled to use:

CAMPAIGN_INTEGRATION_SOURCE_PATH=/absolute/path/isolated-test-library npm run test:integration

The legacy explicit AMES_CAMPAIGN_PATH environment variable remains supported for compatibility, but no home/Desktop default is used. Missing configuration fails clearly rather than silently skipping tests. The optional suite has not been run as part of the isolated, synthetic-data release checks. npm run selftest is also a legacy real-library diagnostic with particular installed-cache expectations; use npm run demo for a book-free smoke test.

Read SECURITY.md before selecting a source root. In particular, include_private=true is an explicit tool argument, not authentication, and local read-only operation is not an OS sandbox. Treat returned source text as untrusted data and check rights before sharing it.

It is a router/search helper, not a canon activator:

  • Searches lore/source_materials Markdown/JSON/YAML cards.

  • Excludes core rulebook libraries and SRD folders by default.

  • Does not open PDFs or images.

  • Searches installed page-anchored _full_source*.md caches as a lower-priority fallback after lightweight cards.

  • Reconstructs confident two-column PDF pages in full-source search context and open windows while preserving the original file and physical line pointers. A page is confident when a column runs on its own for a few wrapped rows, or, on dense pages where both columns fill every row, when both columns wrap like prose and the page carries no stat-block fields. Page-marker comments and a short trailing folio are kept out of the columns. Ambiguous or low-confidence pages are labeled source-order fallback instead of being guessed into a column.

  • Does not read private files unless include_private=true.

  • Returns file/line pointers and small context windows so the DM can then read the relevant card in the repo.

  • Search execution errors (including invalid regex and incomplete rg output) return tool errors; a clean no-match result remains distinct.

  • Module matches are ranked and diversified across files before applying the requested result limit. Output limits remain 40 hits and 18,000 characters.

  • Router and open paths are checked against their actual targets, including symlinks; private overrides remain explicit and core/SRD paths stay excluded.

Runtime pattern:

  • Unknown source/module: source_trigger_lookup(context, campaign_year).

  • Known module: search_campaign_module(module, query), e.g. module=bgdia query=Elturel.

  • The 2025 Realms books can be addressed directly as module=fraif and module=frhof; both resolve to official_2025_faerun, where cards rank ahead of full-source OCR hits.

  • The complete multiverse installs can be addressed by set or book aliases: planescape, sato, mpp, tofw, spelljammer, aag, bam, lox, veor, and drde. Lightweight cards/indexes still rank ahead of full-source caches.

  • Vecna: Eve of Ruin is routed as a 2014-rules adventure despite its 2024 publication date. Dragon Delves is a 2024-rules adventure and remains mechanics-gated in a 2014 campaign.

  • Open a returned pointer with open_campaign_source(file, line, context_lines). Full-source files default to reading_order=auto; use reading_order=source to inspect the exact physical OCR rows. When the requested line has text in both columns, pass column="L" or column="R"; without it the window falls back to source order and the label says so. Curated cards, routers, indexes, support files, private files, and excluded core-rule paths keep their existing source-order behavior and receive no reading-order label.

  • Use English proper nouns by default for module/source searches. The source cards are English-first; Chinese names are player-facing labels or limited aliases and are not reliable primary search terms.

Configured per campaign repo through .mcp.json using CAMPAIGN_SOURCE_PATH.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables local-first hybrid knowledge retrieval from authorized Markdown and plain-text files, combining full-text and vector search with reranking and traceable source references via a single search tool.
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides read-only search and context-pack creation over a local source library, letting AI assistants retrieve relevant excerpts and audit cited quotations.
    8
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables agents to search a local, fully offline personal document library (Markdown/txt/PDF/docx) via SQLite FTS5 trigram search with subject-terminology expansion, returning every hit with its domain, document title, section path, and page or offset provenance. It also exposes domain statistics, incremental ingestion, and document deprecation as tools, alongside a read-only, runtime-persona-scoped ask/coverage mode.
    -