gedcom-mcp
# gedcom-mcp
A small [MCP](https://modelcontextprotocol.io) server that reads and searches
a GEDCOM 5.5.1 file. It gives an AI agent a fast, structured way to look up
individuals, families, sources, and multimedia references in a family tree,
and to suggest folder slugs for an archive of per-person pages.
It is tolerant of the custom tags that **Ancestry.com** exports emit
(`_APID`, `_TREE`, `_PRIM`, `_OID`, and `M/D/YYYY` dates), but it works with
any spec-compliant GEDCOM.
No family data is bundled with this server — you point it at your own `.ged`
file via an environment variable.
## Install
Requires Python 3.10+ and [`uv`](https://docs.astral.sh/uv/).
```sh
git clone https://github.com/<you>/gedcom-mcp.git
cd gedcom-mcp
uv sync
```
## Configuration
One required environment variable:
| Variable | Description |
| --- | --- |
| `GEDCOM_FILE` | Absolute path to the `.ged` file to load. |
The file is parsed lazily on the first tool call and cached in memory.
## Tools
| Tool | What it does |
| --- | --- |
| `info` | File path, Ancestry tree id (if present), counts by record type. |
| `find_individual(query, limit=25)` | Token search over INDI names (incl. AKAs). |
| `get_individual(id)` | Full INDI record: events, residences, sources, multimedia, family links, suggested slug, `external_ids`. |
| `find_family(husband_query, wife_query, marriage_year, limit=25)` | Match FAM records by spouses and/or year. |
| `get_family(id)` | Full FAM record with husband/wife/children resolved. |
| `list_children(individual_id)` | Children across all spouse families. |
| `list_ancestors(individual_id, generations=4)` | Bounded ancestor walk. |
| `list_descendants(individual_id, generations=4)` | Bounded descendant walk. |
| `get_sources(individual_id)` | SOUR citations attached to the person and their events, including Ancestry `_APID` codes. |
| `suggest_slug(id)` | Suggest a stable folder slug for the record (see below). |
IDs may be passed with or without `@` delimiters (`I123` and `@I123@` are
equivalent).
## Running locally
```sh
GEDCOM_FILE="/path/to/your-tree.ged" uv run gedcom-mcp
```
It speaks MCP over stdio.
## Registering with an MCP client
Add an entry like this to your MCP client's server config (paths are
examples — adjust to your checkout and your `.ged` file):
```json
{
"mcpServers": {
"gedcom": {
"command": "uv",
"args": ["run", "--directory", "/path/to/gedcom-mcp", "gedcom-mcp"],
"env": {
"GEDCOM_FILE": "/path/to/your-tree.ged"
}
}
}
}
```
## Output conventions
The server returns plain JSON-shaped data. Dates are normalized to
ISO 8601 (`YYYY-MM-DD`, partial dates allowed). The agent is responsible for
turning these dicts into whatever it needs; the server stays out of
formatting decisions.
### Slug convention
`suggest_slug` produces a lowercase, hyphenated, ASCII slug intended as a
stable folder name for a per-record page:
- **Individual:** `<surname>-<given>-<birthyear>` (e.g. `smith-john-1901`)
- **Family:** `<husband-surname>-<wife-surname>-<marriageyear>`
`unknown` is used for a missing year. This convention is opinionated; if your
archive uses a different scheme, adapt `suggest_slug` / the `*_slug` helpers
in `src/gedcom_mcp/model.py`.
## License
MIT. See [LICENSE](LICENSE).
TDQS
Scored across 10 tools
Each tool has a distinct purpose: get_* fetches by ID, find_* searches by criteria, list_* traverses relations, and get_sources/suggest_slug handle dedicated concerns. The potential overlap between get_family and list_children is minor as they take different inputs and serve different queries.
Tools follow a consistent verb_noun pattern with get_ (by ID), find_ (search), and list_ (relation traversal). The 'info' tool breaks the pattern, and 'suggest_slug' uses a less common verb, but the overall structure is predictable.
Ten tools is well within the ideal range for a focused domain server. Each tool addresses a core genealogy query or workspace utility with no redundancy.
The server covers the full read-only lifecycle: retrieval by ID, search by name/family, ancestor/descendant traversal, source citations, and a slug utility. There are no obvious dead ends or missing operations for its stated purpose.