SSRQ MCP Server
Exposes the Swiss Summary of Roman Law (SSRQ) authority files for persons and organisations, enabling search, lookup, and relation queries through MCP-compatible clients.
README
SSRQ — MCP Server
An MCP server that exposes the person and organisation authority file of the Sammlung Schweizerischer Rechtsquellen — Les sources du droit suisse / Le fonti del diritto svizzero, in English the Collection of Swiss Law Sources (SSRQ · SDS · FDS) — to Claude and other MCP-compatible clients.
The collection is published by the Rechtsquellenstiftung of the Swiss Law Society and comprises over 140 editions of legal-historical documents from the Middle Ages to 1798 (https://ssrq-sds-fds.ch). This server serves the authority file behind those editions: 23,674 persons, 7,047 organisations, and 138,298 name variants.
Architecture
ssrq__fuseki_*.ttl ──► SSRQ ETL ──► ssrq.db (SQLite)
persons ────┐
orgs ───────┼──► server.py
name_index ─┘ (mcp 2.0 MCPServer,
streamable HTTP)
│
http://<host>:8002/mcp
The server targets mcp 2.0, which renamed the high-level server class
(FastMCP → MCPServer) and removed mcp.server.fastmcp; requirements.txt pins the
major version accordingly.
The database is built by the SSRQ project's ETL pipeline from the RDF-TTL source dump;
this repository only serves it. Every connection is opened mode=ro with
PRAGMA query_only, so the server cannot write to the corpus.
Setup
1. Build the database
The database lives at /data/ssrq.db in the container. To rebuild it from the RDF-TTL
source (in the SSRQ project repository):
python ssrq_parse_ttl.py --input /path/to/ssrq__fuseki_*.ttl --db ssrq.db
db.SCHEMA_SQL holds the schema this server expects — it is the contract between the
ETL and the server, and the tests build their fixtures from it.
2. Install dependencies
pip install -r requirements.txt
3. Start the server
python server.py --db ssrq.db --host 0.0.0.0 --port 8002
Each flag also has an environment variable — SSRQ_DB, SSRQ_HOST, SSRQ_PORT — which
the flags override. Importing server.py never reads sys.argv, so it is safe to import
from tests or an ASGI loader.
4. Connect a client
Add to your claude_desktop_config.json (or equivalent):
{
"mcpServers": {
"ssrq": {
"url": "http://<server-ip>:8002/mcp",
"transport": "streamable-http"
}
}
}
Or for Claude Code:
claude mcp add ssrq --transport http --url http://<server-ip>:8002/mcp
Docker deployment
Build image
docker compose build
Run
docker compose up -d
The container serves on port 8002 and expects ssrq.db at /data/ssrq.db. Adjust the
volume path in docker-compose.yml if your data lives elsewhere.
Reverse proxy (nginx, optional but recommended)
server {
listen 443 ssl;
server_name ssrq-mcp.example.unibe.ch;
location / {
proxy_pass http://localhost:8002;
proxy_http_version 1.1;
# Required for the streaming responses
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
}
}
Note: the server has no authentication. By default
docker-compose.ymlpublishes port 8002 on all interfaces; if a proxy fronts it, bind it to loopback instead so the authority file is not reachable directly:SSRQ_BIND=127.0.0.1 docker compose up -dOtherwise restrict access at the firewall.
Available tools
| Tool | Description |
|---|---|
corpus_stats() |
Person/org/name-variant counts and the attested year range |
list_persons(limit=50, offset=0) |
Paginated list of the person authority file, by id |
search_persons(query, limit=50) |
Persons by standardised name, label, or spelling variant |
get_person(pid) |
Full person record by SSRQ id (e.g. per000001), with name variants |
get_persons_by_year(year_from, year_to, limit=100) |
Persons whose attested years overlap a range (max span 500 years) |
search_orgs(query, limit=50) |
Organisation authority by name |
get_org(oid) |
Full org record by SSRQ id (e.g. org000001), with name variants |
search_name_index(query, type_filter="", limit=50) |
Search all 138k name variants; type_filter is person, org, or empty for both |
get_name_variants(id) |
All name variants for a given person or org id |
related_persons(pid) |
Spouses, mothers, fathers, organisations, and places, resolved to records |
Available resources
| URI | Description |
|---|---|
ssrq://stats |
Corpus statistics (JSON) |
ssrq://orgs |
Organisation index — {total, returned, truncated, orgs: [...]}, capped at 9999 rows and flagged when truncated |
ssrq://person/{pid} |
Single person record (JSON) |
ssrq://org/{oid} |
Single organisation record (JSON) |
Query behaviour
Limits. Every limit is clamped to at most 500; a negative, zero, or non-numeric
value falls back to that tool's own default rather than returning the whole table. Use
list_persons(limit, offset) to page through the register.
Name search. search_persons, search_orgs, and search_name_index do a plain
case-insensitive substring match. SQL wildcards in the query are escaped, so searching for
100% finds a literal "100%" rather than matching every record. search_persons looks at
std_name, label, and both spelling-variant columns; historical spellings that differ
from the modern form are best reached through search_name_index.
Name index shape. Every row carries kind (person or org), so the result shape is
the same whether or not type_filter is set.
Missing records. get_person, get_org, and related_persons return
{"error": "... not found."} rather than raising.
Year ranges. get_persons_by_year matches on overlap: a person is returned when
first_year <= year_to and last_year >= year_from. Persons with no attested years are
never returned. An inverted range, or one spanning more than 500 years, comes back as an
error object.
Places. related_persons resolves spouse_ids, mother_ids, father_ids, and
org_ids against the persons and orgs tables. loc_ids point at the SSRQ place
authority, which this database does not currently carry: those ids are returned as bare
{"id": ...} entries together with a places_note. If a places (or locations) table
is added to the database later, they are resolved to full records automatically.
Database schema
| Table | Contents |
|---|---|
persons |
id, uri, etype, label, label_lang, std_name, forename, surname, sex, first_year, last_year, years, org_ids, spouse_ids, mother_ids, father_ids, loc_ids, orig_names, std_names |
orgs |
id, uri, etype, label, std_name, surname, alias_of, org_type |
name_index |
name_text, ssrq_id, is_orig (138k variant → canonical mappings) |
Key notes
- Person IDs:
per000001–per999999(23,674 total) - Org IDs:
org000001–org999999(7,047 total) orig_names/std_names— original and normalised spelling variants (comma-joined)is_orig=1inname_indexmeans the name is the original spelling;is_orig=0is a normalised variant. Original spellings sort first in every variant listing.- The relation columns (
org_ids,spouse_ids,mother_ids,father_ids,loc_ids) are comma-joined id lists;related_personsresolves them all in one call.
Tests
pip install -r requirements-dev.txt
pytest test_ssrq_mcp.py
Unit tests build their own throwaway database and run with no setup. The DB and server tests skip unless you point them at the real database and a running server:
SSRQ_DB=/data/ssrq.db SSRQ_SERVER=http://localhost:8002 pytest test_ssrq_mcp.py
The suite also runs standalone, with grouped output and a non-zero exit on failure:
python test_ssrq_mcp.py --unit --db /data/ssrq.db --server http://localhost:8002
Note that the DB tests assert corpus-size floors (≥20,000 persons, ≥6,000 organisations, ≥100,000 name variants) — they will fail against a small sample database.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.