# Gramps Evidence (pypi · gramps-evidence-mcp)

Read/write a self-hosted Gramps Web family tree where every fact carries a citation.

- Trust score: 66/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-01

## Components

- pypi · `gramps-evidence-mcp`: 66/100 (this document), [markdown](https://verifymcp.io/servers/ianderso-gramps-evidence-mcp/gramps-evidence-mcp.md), [page](https://verifymcp.io/servers/ianderso-gramps-evidence-mcp/gramps-evidence-mcp)

## Channel facts

- Registry: `pypi`
- Package: `gramps-evidence-mcp`
- Version: `1.1.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-01.

- **Supply Chain Security**: 50/100
  - Malware scan not yet available for this package.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised build step with no custom scripting around it.
  - 1 of 32 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 100/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to ianderso/gramps-evidence-mcp).
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 0 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 74/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 14063 tokens (~158/item across 89 items; 89 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 3/100
  - Stability observed for 1 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
- **Tool Safety**: 95/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 4 of 5 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "consolidated_timeline" implies "merge" and declares readOnlyHint instead, contradicting what its own name says it does.
  - An AI judge read all 90 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

## Install

### How do I install the Gramps Evidence MCP server?

Gramps Evidence runs locally as a PyPI package, launched with uvx gramps-evidence-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add ianderso-gramps-evidence-mcp -- uvx gramps-evidence-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "ianderso-gramps-evidence-mcp": {
      "command": "uvx",
      "args": [
        "gramps-evidence-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "ianderso-gramps-evidence-mcp": {
      "command": "uvx",
      "args": [
        "gramps-evidence-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add ianderso-gramps-evidence-mcp -- uvx gramps-evidence-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ianderso-gramps-evidence-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "gramps-evidence-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add ianderso-gramps-evidence-mcp --command uvx --arg gramps-evidence-mcp
```

### Hermes

```yaml
mcp_servers:
  ianderso-gramps-evidence-mcp:
    command: "uvx"
    args: ["gramps-evidence-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "ianderso-gramps-evidence-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "gramps-evidence-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add ianderso-gramps-evidence-mcp -t stdio -c uvx -a gramps-evidence-mcp
```

### Other

```json
{
  "mcpServers": {
    "ianderso-gramps-evidence-mcp": {
      "command": "uvx",
      "args": [
        "gramps-evidence-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-01 (score 66, 0)

- [security improvement] Malware scan: unverified → pass
- [functional regression] Schema quality: 12495 → 14063
- [functional improvement] Stability: unverified → 0.03
- [functional] Package version: 1.0.1 → 1.1.0

### 2026-09-30 (score 66)

First indexed and scored.

## MCP tools (89)

### `add_person` (~284 tokens)

Create a new person, optionally with cited birth and/or death events.

Use this to add someone to the tree. Good practice: attach the birth event
with a citation to the *specific* record that proves it (a birth or baptism
certificate, a census entry), setting the citation's confidence honestly.
If you only have a legacy-tree hint with no underlying record, either omit
the event or set require_citation=False so it's flagged for follow-up.

Returns the new person's handle and gramps_id.

Input parameters:

- `birth`: Optional birth event. Include a citation unless recording as unsourced. The event type defaults to 'Birth'.
- `death`: Optional death event; type defaults to 'Death'.
- `gender`: female, male, or unknown.
- `given` (string, required): Given/first name(s), e.g. 'John Robert'.
- `name_prefix` (string): Surname prefix, e.g. 'van', 'de'.
- `name_suffix` (string): Suffix, e.g. 'Jr.', 'III'.
- `require_citation` (boolean): If True (default), any birth/death event MUST carry a citation or the call fails. Set False to record the event anyway, stamped with the UNSOURCED attribute so list_unsourced_facts can find it later.
- `surname` (string): Family name / surname.

### `add_event_to_person` (~148 tokens)

Add a dated/placed event (fact) to an existing person.

Use for facts beyond birth/death: residence, occupation, census, baptism,
immigration, marriage-adjacent events, etc. The event's citation should point
at the record establishing the fact. Adding a 'Birth'/'Death' event will set
the person's primary birth/death reference if not already set.

Input parameters:

- `event` (required): The event to add (type, date, place, citation).
- `person` (string, required): Person handle or gramps_id (e.g. 'I0007').
- `require_citation` (boolean): Require a citation (default). False records it UNSOURCED.

### `add_family` (~168 tokens)

Create a family linking parents and children, with an optional cited marriage.

All members must already exist (create them first with add_person). Creating
the family automatically links each person's family/parent-family lists, so
you don't need to update the individuals separately. Cite the marriage event
to a marriage record where possible.

Input parameters:

- `children`: Child handles or gramps_ids.
- `father`: Father: handle or gramps_id.
- `marriage`: Optional marriage event; type defaults to 'Marriage'. Cite it.
- `mother`: Mother: handle or gramps_id.
- `relationship` (string): Family relationship type, e.g. 'Married', 'Unmarried', 'Civil Union'.
- `require_citation` (boolean): Require a citation on the marriage event (default).

### `add_source` (~190 tokens)

Create a Source (a body of evidence: a record set, book, certificate, website).

In the Gramps evidence model a Source is what you cite *through* a Citation.
Create the source once, then create citations against it for each fact it
supports. Optionally link it to a Repository (where the source is held).

Input parameters:

- `abbreviation`: Short abbreviation.
- `author`: Author/creator of the source.
- `call_number`: Call number / reference within the repository.
- `media_type` (string): Medium of the source at that repository, e.g. 'Book', 'Microfilm', 'Electronic'. Only used with repository.
- `publication_info`: Publication info (publisher, date, series).
- `repository`: Repository handle/gramps_id that holds this source.
- `title` (string, required): Source title, e.g. '1900 U.S. Federal Census'.

### `add_citation` (~86 tokens)

Create a standalone Citation on a Source (or reuse an existing one).

Usually you don't call this directly -- pass a CitationInput to add_person /
add_event_to_person / add_family instead, which creates the citation and
attaches it to the fact in one step. Use this when you want a reusable
citation handle to attach to several facts.

Input parameters:

- `citation` (required): Citation details.

### `add_repository` (~113 tokens)

Create a Repository (an institution or place that holds sources).

Repositories sit at the top of the evidence model: Repository -> Source ->
Citation -> fact. Create these for archives, libraries, cemeteries, or
websites you'll cite sources from.

Input parameters:

- `name` (string, required): Repository name, e.g. 'National Archives (NARA)'.
- `repository_type` (string): Type: 'Library', 'Archive', 'Cemetery', 'Church', 'Website', etc.
- `url`: Optional website URL.

### `add_note` (~129 tokens)

Create a research/general note, optionally attached to an object.

Use notes for research logs, reasoning about conflicting evidence, or
transcriptions. Attach to a person/event/source by giving target + target_type.

Input parameters:

- `note_type` (string): Note type, e.g. 'General', 'Research'.
- `target`: Optional object handle/gramps_id to attach the note to.
- `target_type`: Type of the target: 'person', 'family', 'event', 'source', 'citation', 'place', 'repository', 'media'.
- `text` (string, required): The note text.

### `attach_media` (~275 tokens)

Attach an image or document to an object -- a new upload, or one already
in the tree.

With file_path, the bytes are uploaded into the tree's managed media
directory (so don't point at files you don't want copied); if that exact
file is already present it is reused rather than duplicated. With media_ref,
an existing Media object is linked.

One image should be ONE Media object, linked from each object it belongs to
and cited once per fact it proves. Uploading the same photograph separately
for the husband and the wife creates duplicates that have to be unpicked
later. The write is verified afterwards: `verified: false` means nothing
attached, whatever the rest of the result says.

Input parameters:

- `description` (string): What the document IS, in archival terms. Only used when uploading a new file.
- `file_path`: Absolute path to a local image, PDF, audio or video file to upload. Use this OR media_ref.
- `media_ref`: Handle or gramps_id of a Media object ALREADY in the tree. Prefer this when the same document supports several people.
- `target` (string, required): Object handle/gramps_id to attach media to.
- `target_type` (string): Type of the target object: 'person', 'event', 'source', etc.

### `cite_event` (~134 tokens)

Attach a citation to an event that ALREADY exists.

Use this to source an event you didn't create with an inline citation -- e.g.
one added through the Gramps web UI, or an unsourced event surfaced by
list_unsourced_facts. The citation is resolved/created (existing handle/id, or
an inline source_title + page + confidence) and appended to the event's
citation list (no duplicates). Does not change any other event field.

Input parameters:

- `citation` (required): Citation to attach to the event.
- `event` (string, required): Event handle or gramps_id (e.g. 'E0007').

### `update_event` (~370 tokens)

Edit an existing event in place: its type, date, place or description.

Only what you pass changes. The event keeps its id, citations, notes, media
and every person sharing it, so correct a wrong type or an unsupported place
here rather than replacing the event. Citations: cite_event.

Input parameters:

- `allow_new_type` (boolean): Accept an event_type the tree does not have yet, creating it as a custom type. Only for a deliberate new type, never a typo.
- `clear_date` (boolean): Remove the event's date.
- `clear_place` (boolean): Remove the event's place, e.g. one no source states. An empty place string is refused rather than read as this.
- `date`: New date, Gramps style: '1899', '12 JAN 1899', 'ABT 1900', 'BEF 1950'; 'BET 1898 AND 1901' happened once within the range; 'FROM 4 MAY 1864 TO 16 SEP 1864' lasted the whole span; 'FROM 1880' or 'TO 1…
- `description`: New free-text description. Omit to leave unchanged.
- `event` (string, required): Event handle or gramps_id (e.g. 'E0007').
- `event_type`: New event type, e.g. 'Census', 'Visit'. Must already be a standard or custom type in the tree (list_object_types) unless allow_new_type is set. Omit to leave unchanged.
- `place`: New place: existing handle/gramps_id, exact title, or exact unique name — created only if nothing matches. Omit to leave unchanged.

### `add_event_ref` (~160 tokens)

Share an existing event with another person, in a role.

For one census entry, residence or burial that several people took part in:
each references the same event, so its citations and later corrections serve
all of them. Refused if the person already has it. A new fact is
add_event_to_person.

Input parameters:

- `event` (string, required): Handle or gramps_id of the EXISTING event, e.g. 'E0007'.
- `person` (string, required): Handle or gramps_id of the person to add the event to.
- `role` (string): The person's role in it: 'Primary', 'Witness', 'Informant', 'Godparent', 'Family', 'Clergy', or a custom role the tree already has.

### `delete_object` (~164 tokens)

Permanently delete an object from the tree by handle or gramps_id.

DESTRUCTIVE. The server also removes every reference to it. Refused when it
is the only holder of a note or image (pass carry_to to move them), and for a
source with citations, which the server would delete with it.

Input parameters:

- `carry_to`: Another object of the same type to receive the notes and images that only this one holds. Without it, such a delete is refused.
- `object_type` (string, required): Type to delete: 'person', 'family', 'event', 'place', 'source', 'citation', 'repository', 'media', 'note', 'tag'.
- `target` (string, required): Handle or gramps_id of the object to delete.

### `tag_object` (~190 tokens)

Attach a named Tag to an object, creating the Tag if it doesn't exist yet.

Tags are lightweight cross-cutting labels ('Verified', 'Needs review',
'DNA-confirmed'). Matching is by exact name; an existing tag is reused.

Input parameters:

- `color`: Optional hex color for a newly-created tag, e.g. '#FF8800'. Defaults to '#4444FF'. Ignored if the tag already exists.
- `object_type` (string, required): Type of the object to tag: 'person', 'family', 'event', 'source', 'citation', 'place', 'repository', 'media', 'note'.
- `tag` (string, required): Tag name (found-or-created by exact match), e.g. 'Verified'. To REMOVE a tag: detach_object(child_kind='tag', child=<tag name>).
- `target` (string, required): Handle or gramps_id of the object to tag.

### `add_attribute` (~123 tokens)

Add a typed key/value attribute to an object.

Sources and citations use a SrcAttribute; everything else uses an Attribute.
The right class is chosen automatically from object_type.

Input parameters:

- `name` (string, required): Attribute type/name, e.g. 'Occupation', 'National ID'.
- `object_type` (string, required): Type of the object: 'person', 'event', 'family', 'media', 'source', 'citation'.
- `target` (string, required): Handle or gramps_id of the object.
- `value` (string, required): Attribute value, e.g. 'Blacksmith'.

### `add_url` (~151 tokens)

Add a web URL to a person, place, or repository.

Only these three object types carry a URL list. For sources/citations, record
a web address as an attribute (add_attribute) instead.

Input parameters:

- `description` (string): Optional link description.
- `object_type` (string, required): Type of the object: 'person', 'place', or 'repository' only.
- `target` (string, required): Handle or gramps_id of the object.
- `url` (string, required): The URL, e.g. 'https://www.findagrave.com/memorial/123'.
- `url_type` (string): URL type, e.g. 'Web Home Page', 'Web Search', 'E-mail'.

### `update_url` (~229 tokens)

Edit or remove ONE existing URL entry on a person, place, or repository.

add_url can only append -- this corrects an entry already there (the classic
case: a Find a Grave link filed under the wrong type). The other fields on
the object are untouched.

Input parameters:

- `description`: New link description. Omit to keep.
- `match` (string, required): Case-insensitive substring identifying WHICH url entry to edit, tested against each entry's path and description (e.g. 'findagrave.com/memorial/123'). Must match exactly one entry; matching none or s…
- `object_type` (string, required): Type of the object: 'person', 'place', or 'repository' only.
- `remove` (boolean): Remove the matched entry instead of editing it.
- `target` (string, required): Handle or gramps_id of the object.
- `url`: New URL path. Omit to keep.
- `url_type`: New URL type, e.g. 'Find A Grave', 'Web Home Page'. Omit to keep.

### `set_private` (~109 tokens)

Set (or clear) the Gramps private flag on an object.

Private records are withheld from bulk output (queries, searches, tree
walks, timelines, reports) unless a call passes include_private.

Input parameters:

- `object_type` (string, required): Type of the object: 'person', 'family', 'event', 'source', etc.
- `private` (boolean): True to mark private (default), False to un-mark.
- `target` (string, required): Handle or gramps_id of the object.

### `update_source` (~114 tokens)

Edit an existing source's title, author, publication info, and/or abbreviation.

Only the fields you provide are changed; the rest are left as-is.

Input parameters:

- `abbreviation`: New abbreviation. Omit to leave unchanged.
- `author`: New author. Omit to leave unchanged.
- `publication_info`: New publication info. Omit to leave unchanged.
- `source` (string, required): Source handle or gramps_id (e.g. 'S0001').
- `title`: New title. Omit to leave unchanged.

### `link_repository` (~138 tokens)

Link an existing source to an existing repository that holds it.

Adds a repository reference (with an optional call number) to the source.
Both objects must already exist. Duplicate links to the same repository are
skipped.

Input parameters:

- `call_number`: Call number / reference within the repository.
- `media_type` (string): Medium of the source at the repository, e.g. 'Book', 'Microfilm', 'Electronic', 'Unknown'.
- `repository` (string, required): Repository handle or gramps_id (e.g. 'R0001').
- `source` (string, required): Source handle or gramps_id (e.g. 'S0001').

### `link_repositories` (~79 tokens)

Link many sources to their repositories in one call -- a sweep.

Each row is link_repository: its own write and transaction, so a failed row
does not stop the rest. Each row reports linked, already_linked, missing or
error.

Input parameters:

- `items` (array, required): Rows of {source, repository, call_number?, media_type?}.

### `add_event_to_family` (~118 tokens)

Add a dated/placed event (fact) to an existing family.

Use for family-level facts: marriage, divorce, residence, census. The event
is added with the 'Family' role. Cite it to the record establishing the fact.

Input parameters:

- `event` (required): The event to add (type, date, place, citation).
- `family` (string, required): Family handle or gramps_id (e.g. 'F0001').
- `require_citation` (boolean): Require a citation (default). False records it UNSOURCED.

### `add_child_to_family` (~149 tokens)

Add an existing person as a child of an existing family.

Links the child both ways: a ChildRef is added to the family and the family
is added to the child's parent-family list. The child must already exist.
Duplicate children are skipped.

Input parameters:

- `child` (string, required): Child person handle or gramps_id.
- `family` (string, required): Family handle or gramps_id (e.g. 'F0001').
- `frel` (string): Relationship to the father, e.g. 'Birth', 'Adopted', 'Stepchild'.
- `mrel` (string): Relationship to the mother, e.g. 'Birth', 'Adopted', 'Stepchild'.

### `update_child_ref` (~156 tokens)

Change a child's relationship to the father or mother -- a stepson held
as a birth child -- in place.

The child keeps the link's citations, notes and its place in the birth
order, which detaching and re-adding the child loses.

Input parameters:

- `child` (string, required): The child's person handle or gramps_id.
- `family` (string, required): Family handle or gramps_id (e.g. 'F0001').
- `frel`: Relationship to the father: 'Birth', 'Adopted', 'Stepchild', 'Foster', 'Sponsored', 'Unknown', 'None'. Omit to keep.
- `mrel`: Relationship to the mother, the same values. Omit to keep.

### `check_family_links` (~110 tokens)

Audit the links between people and families, in both directions.

Finds a family a person lists twice, a child a family lists twice, a link
one side holds and the other lacks, and links to objects that do not
exist. Each finding says how to repair it. Reports only.

Input parameters:

- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `limit` (integer): Maximum findings to return.

### `add_alternate_name` (~243 tokens)

Add an alternate (non-primary) name to a person, cited to the record using it.

Use for maiden/married names, aliases, anglicized forms, or nicknames-of-record.
The person's primary name is left unchanged. Correct or remove one later
with update_alternate_name.

Input parameters:

- `citation`: The record that gives this form of the name. It goes on the name itself -- 'this record spells it so' -- not on the person. Cite an existing name with cite_object(object_type='name').
- `given` (string): Given/first name(s) for the alternate name.
- `name_prefix` (string): Surname prefix, e.g. 'van', 'de'.
- `name_suffix` (string): Suffix, e.g. 'Jr.', 'III'.
- `name_type` (string): Kind of alternate name, e.g. 'Also Known As', 'Birth Name', 'Married Name'.
- `nickname` (string): Nickname.
- `person` (string, required): Person handle or gramps_id (e.g. 'I0001').
- `surname` (string): Family name / surname.

### `get_person` (~98 tokens)

Get full detail for one person: name, gender, events (with citation counts),
family links, and media count.

Direct lookup is allowed even for living/private individuals (this is your own
local tool); only bulk/list tools filter them. Use this to inspect someone
before adding facts, or to check whether an event is already cited.

Input parameters:

- `person` (string, required): Person handle or gramps_id, e.g. 'I0001'.

### `search_people` (~142 tokens)

Search people by name substring and optional birth-year range.

Bulk output: probably-living people (born < 110 years ago with no recorded
death) and records marked private are returned as redacted stubs (ids only)
unless include_private is set. Fetch a specific person by id with
get_person if you need their detail.

Input parameters:

- `birth_year_max`: Latest birth year.
- `birth_year_min`: Earliest birth year.
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `name` (string, required): Name substring to match (case-insensitive).

### `get_family` (~45 tokens)

Get a family: relationship type, parent handles, child handles, event count.

Input parameters:

- `family` (string, required): Family handle or gramps_id, e.g. 'F0001'.

### `get_ancestors` (~94 tokens)

Walk a person's ancestors up to N generations (a nested parents tree).

Living/private ancestors appear as redacted stubs unless include_private is set.

Input parameters:

- `generations` (integer): How many generations up.
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `person` (string, required): Root person handle or gramps_id.

### `get_descendants` (~93 tokens)

Walk a person's descendants up to N generations (a nested children tree).

Living/private descendants appear as redacted stubs unless include_private is set.

Input parameters:

- `generations` (integer): How many generations down.
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `person` (string, required): Root person handle or gramps_id.

### `list_unsourced_facts` (~126 tokens)

Audit: list events that lack a citation or are tagged UNSOURCED.

This is the core quality query for a fully-cited tree -- run it to find
facts that still need a source. Returns each offending event with its person,
type, date, and the reason ('no-citation' or 'tagged-unsourced').

Input parameters:

- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `person`: Optional: restrict to one person (handle/gramps_id).

### `db_stats` (~39 tokens)

Counts of people, families, events, citations, sources, repositories,
places, media, and notes in the tree. A quick health/overview check.

### `list_tags` (~41 tokens)

List all tags in the tree with their handle, name, and color.

Use to see what labels already exist before tagging (tag_object matches by
exact name).

### `get_source` (~70 tokens)

Get a source: title, author, publication info, abbreviation, linked
repositories, media/note counts, attributes, and citation count.

Use to inspect a source before citing through it or editing it.

Input parameters:

- `source` (string, required): Source handle or gramps_id, e.g. 'S0001'.

### `get_repository` (~54 tokens)

Get a repository: name, type, URLs, address count, and (if available)
the number of sources it holds.

Input parameters:

- `repository` (string, required): Repository handle or gramps_id, e.g. 'R0001'.

### `get_event` (~60 tokens)

Get an event: type, date, place handle, description, citation count, and
attributes. Use to inspect an event before citing or editing it.

Input parameters:

- `event` (string, required): Event handle or gramps_id, e.g. 'E0001'.

### `query_objects` (~503 tokens)

Query any collection with a server-side filter. The workhorse for audits.

Use this instead of fetching a collection and filtering it yourself:
whole-collection pulls are slow on any real tree, and the filter runs in
the database. Typical audit questions it answers directly:

\* uncited high-confidence claims: citations where `confidence >= 3 AND page = ""`
\* documents with no image: sources where `media_list.length = 0`
\* anonymous media: media where `desc = ""`

To ask "what cites this source?" use get_backlinks -- a source has no
citation_list, because citations point at IT, and reading citation_list on a
source reports zero for every source in the tree.

Private records and living people come back as redacted stubs.

Input parameters:

- `gql`: GrampsQL filter, applied server-side over the RAW object JSON. Single '=' for equality (NOT '=='), '~' for substring, '<list>.length' for sizes, combined with AND/OR. Examples: 'confidence >= 3 AND p…
- `gramps_ids`: Fetch these specific gramps_ids (e.g. ['S0001','S0002']).
- `handles`: Fetch these specific handles in one request.
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `keys`: Comma-separated fields to return, e.g. 'gramps_id,title,media_list'. Strongly recommended -- whole objects are large. NEVER build a write payload from a keys= result: writes replace the whole record.
- `limit` (integer): Max rows to return.
- `object_type` (string, required): One of: person, family, event, place, source, citation, repository, media, note, tag.
- `page` (integer): Page of results, 1-based.
- `sort`: Sort key; prefix '-' for descending (e.g. '-change').

### `get_backlinks` (~103 tokens)

List everything that references this object, grouped by type.

The right way to ask "is this source actually cited?", "which facts rest on
this citation?", or "is it safe to delete this?" -- an object with zero
backlinks is orphaned; one with backlinks will leave dangling references if
deleted.

Input parameters:

- `object_type` (string, required): Type of the object being pointed AT.
- `ref` (string, required): Handle or gramps_id of that object.

### `find_duplicates` (~203 tokens)

Find likely-duplicate objects. Reports only -- it never merges anything.

Duplicates are not merely untidy: a duplicate SOURCE makes a single-sourced
fact look corroborated, which is a false evidentiary claim. But the reverse
error is just as real -- an index entry and the register page it indexes are
TWO documents and must stay separate. This tool finds candidates; deciding
which are truly the same document is yours. Merge with merge_objects.

Input parameters:

- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `kind` (string, required): media_checksum (same file uploaded twice), source_title (same document entered twice), citation_page (same source+page cited more than once, flagging any graded differently), vital_events (a person w…
- `limit` (integer): Max groups to return.

### `list_object_types` (~66 tokens)

The tree's type vocabularies (event types, attribute types, and so on).

Check an unfamiliar type string here first: Gramps accepts an unrecognised
one as a NEW custom type rather than rejecting it, so a typo permanently
enters the tree's vocabulary.

### `get_object` (~125 tokens)

Read any object's raw record -- including places, media, notes and
citations, which have no shaped getter.

Returns the record as stored, which is what you want before editing one. For
people and sources the shaped getters (get_person, get_source) are easier to
read.

Input parameters:

- `keys`: Comma-separated fields to return. Omit for the whole record.
- `object_type` (string, required): person, family, event, place, source, citation, repository, media, note, or tag.
- `ref` (string, required): Handle or gramps_id.

### `update_citation` (~284 tokens)

Edit a citation's locator, confidence, date, or the source it points at.

A page-less citation on a long document is not a locator, and a confidence
is a per-instance judgement, not a property of the source class.

IMPORTANT: a citation carries ONE confidence, and it belongs to ONE claim.
Every fact attached to this citation shares whatever you set here. If the
same page supports a second, different claim (a census page proving both
"this child appears here" and "these are her parents"), make a SECOND
citation on the same source and page -- do not re-grade this one.

Input parameters:

- `citation` (string, required): Citation handle or gramps_id (e.g. 'C0001').
- `confidence`: Re-grade this citation. very_high is for an original record read from an image, and nothing else.
- `date`: Date recorded/accessed.
- `page`: The locator: WHERE in the source this fact appears ('p. 45, entry 12', 'ED 12, sheet 4A, dwelling 57', memorial number). Omit to leave unchanged.
- `source`: RE-POINT this citation at a different source (handle or gramps_id). Use when a fact was cited to a compiled bucket but the real record is in the tree, or when a container source has been split.

### `update_citations` (~93 tokens)

Re-write many citations' pages or confidences in one call -- a sweep.

Each row is update_citation: its own write and transaction. A row whose
live page no longer starts with expect_page_prefix is reported as drifted,
not overwritten. Rows report applied, unchanged, drifted, missing or error.

Input parameters:

- `items` (array, required): Rows of {citation, page?, confidence?, expect_page_prefix?}.

### `update_media` (~102 tokens)

Edit a media object's description, date, or path.

Input parameters:

- `date`: Date of the document/photo.
- `description`: What this document IS ('1900 US census, Cedar Flat, Brannock Co., Ohio, ED 12 sheet 4A'). Files are stored under checksum names, so without this the media list says nothing about the document.
- `media` (string, required): Media handle or gramps_id.
- `path`: Stored path/filename.

### `update_person` (~234 tokens)

Edit a person's gender, primary name, or privacy flag.

Replacing the primary name preserves the old one as an 'Also Known As': a
name in the tree came from some record, and dropping it loses the link to
whatever document used it. To add a name without replacing the primary one,
use add_alternate_name.

Input parameters:

- `gender`: female, male, or unknown.
- `keep_old_as_alternate` (boolean): False only to fix a data-entry error -- a name split wrongly between given and surname, a typo no record contains -- where keeping the old form would invent a variant. The name is then corrected in p…
- `name`: New PRIMARY name. The current primary name is kept as an alternate rather than discarded, unless keep_old_as_alternate is False.
- `person` (string, required): Person handle or gramps_id (e.g. 'I0001').
- `private`: Gramps private flag.
- `reason`: Why the old form is not kept. Required with keep_old_as_alternate=False.

### `update_alternate_name` (~205 tokens)

Correct, retype or remove one alternate name, in place.

Edited in place, the name keeps its citations. The primary name is
update_person(name=...); a new name is add_alternate_name.

Input parameters:

- `given`: New given name(s). Omit to keep.
- `match` (required): Which alternate name, e.g. {'surname': 'Calloway', 'type': 'Also Known As'}. get_person lists them with their index.
- `name_prefix`: New surname prefix.
- `name_suffix`: New suffix.
- `name_type`: New type, e.g. 'Married Name' for a name filed as 'Also Known As'.
- `nickname`: New nickname.
- `person` (string, required): Person handle or gramps_id.
- `remove` (boolean): Remove the name. Refused while it carries citations or notes; of identical duplicates, one is removed.
- `surname`: New surname. Omit to keep.

### `update_object_fields` (~157 tokens)

Set scalar fields on any object -- the escape hatch for places, notes,
repositories and the rest.

Only scalar fields are settable. Structural lists (citation_list,
event_ref_list, media_list, ...) are refused on purpose: replacing one
wholesale is exactly how references get silently dropped. Each has its own
tool -- cite_object, detach_object, tag_object, attach_media.

Input parameters:

- `fields` (object, required): Scalar fields to set, e.g. {'name': 'Cedar Flat, Brannock, Ohio, USA'} on a place, or {'text': '...'} on a note.
- `object_type` (string, required): Type of object to edit.
- `ref` (string, required): Handle or gramps_id.

### `update_place` (~348 tokens)

Edit a place's type, parent enclosure, name, title, or coordinates.

This is the tool update_object_fields deliberately refuses to be: place_type
and the enclosure are structural, so they get guard rails here -- the parent
must already exist, setting it cannot create an enclosure cycle, and a place
holding several dated enclosures (a territory-to-state succession) is
refused rather than silently flattened. Aim for every place typed, every
non-country place parented, and street addresses on events rather than in
the place tree.

Input parameters:

- `code`: Place code (postal etc.).
- `latitude`: Latitude, e.g. '40.1532'.
- `longitude`: Longitude, e.g. '-82.4101'.
- `name`: New place NAME (the short local name, e.g. 'Cedar Flat'). Omit to leave unchanged.
- `parent`: Handle or gramps_id of the ENCLOSING place (e.g. the county a city sits in). Must already exist -- never created from a name. Replaces the current single enclosure; refused if the place carries sever…
- `place` (string, required): Place handle or gramps_id (e.g. 'P0001').
- `place_type`: New place type: 'Country', 'State', 'County', 'City', 'Town', 'Village', 'Cemetery', etc. Omit to leave unchanged.
- `remove_parent` (boolean): Clear the enclosure instead of setting one.
- `title`: New full TITLE (e.g. 'Cedar Flat, Brannock County, Ohio, USA') -- the string event-place resolution matches against.

### `cite_object` (~251 tokens)

Attach a citation to any object that carries one -- not just events.

cite_event covers facts; this covers the rest. The important case is the
FAMILY, whose citation supports a claim no event makes: that these two
people were a couple. Person-level citations are for evidence about the
individual as a whole (an identity document) rather than about one dated
fact -- prefer citing the specific event where one exists.

A NAME is cited with object_type='name': "this record gives this spelling"
is narrower than evidence about the person. To cite a parent-child link,
use cite_child_link: that is a different claim and needs its own citation.

Input parameters:

- `citation` (required): Citation to attach.
- `name`: With object_type='name': which of the person's names, e.g. {'surname': 'Bittner', 'type': 'Birth Name'} or {'primary': true}. Must match exactly one.
- `object_type` (string, required): person, family, event, place, media, source, citation, or name (one of a person's names: ref is the person, name says which).
- `ref` (string, required): Handle or gramps_id of the object to cite.

### `cite_child_link` (~208 tokens)

Cite the parent-child link itself, on the family's ChildRef.

"This child belongs to these parents" is a DIFFERENT claim from "this child
appears in this record", and it needs its own citation object. Reusing the
child's existing citation handle makes the link inherit a confidence that
was assigned to another claim entirely, so the link displays a confidence
its evidence never earned.

Note what a ChildRef citation asserts: BOTH sides of the link. A census
naming only the mother does not document the father. Where only one parent
is evidenced, cite that parent's relationship instead of implying both.

Input parameters:

- `child` (string, required): The child's person handle or gramps_id.
- `citation` (required): Citation for the PARENTAGE claim. Create a new one (source + page + confidence) rather than reusing a citation handle from elsewhere -- see the warning below.
- `family` (string, required): Family handle or gramps_id (e.g. 'F0001').

### `uncite` (~242 tokens)

Detach a citation from an object, deleting it if it is left orphaned.

Detaching without deleting is how orphan citations accumulate: the fact the
citation supported is gone, but the citation sits in the database still
looking like evidence of something. Use this when a citation was attached to
the wrong fact, or when a superseded bucket citation is replaced by the real
record.

Input parameters:

- `carry_to`: Citation (handle or gramps_id) to receive the notes and images only this citation holds, so it can be deleted without losing them.
- `citation` (string, required): Citation handle or gramps_id to remove.
- `delete_if_orphan` (boolean): Delete the citation if nothing else references it after detaching. Leave True unless you are keeping it deliberately. A citation that holds the only link to a note or image is kept unless carry_to is…
- `name`: With object_type='name' (ref is the person): which of the person's names to detach the citation from.
- `object_type` (string, required): Type of the object to detach from.
- `ref` (string, required): Handle or gramps_id of that object.

### `merge_objects` (~351 tokens)

Merge two objects that are the same thing. Dry-run by default.

This uses Gramps' own server-side merge: every reference to `drop` is
re-pointed at `keep` and the subordinate lists are unioned, in one
transaction. Do NOT do this by hand: a manual merge that misses one of the
lists the dropped object carries loses what was on it.

Before merging, be sure they really are one thing. Two records OF the same
event are two documents: an index entry and the register page it indexes
stay separate, and merging them would turn two independent citations into
one, silently weakening every fact that rested on both. Conversely, the same
census page entered once per household member IS one document, and leaving
the duplicates makes single-sourced facts look corroborated.

Reversible: the merge is one transaction, so list_transactions +
undo_transaction can back it out.

Input parameters:

- `drop` (string, required): Handle or gramps_id of the object absorbed into it.
- `dry_run` (boolean): True (default) reports what would move without changing anything. Set False to apply.
- `enclosures` (string): Places only: the survivor otherwise gets both places' parents. 'auto' drops an undated parent that encloses another (a state beside its county) and refuses if two unrelated undated parents remain; or…
- `keep` (string, required): Handle or gramps_id of the object that SURVIVES.
- `object_type` (string, required): person, family, event, place, source, citation, repository, media, or note.

### `detach_object` (~275 tokens)

Remove a reference from an object: an event from a person, an image from a
source, a tag, a note, a child from a family.

The reference is removed; the object itself survives unless
delete_if_orphan is set AND nothing else points at it -- which is checked,
because deleting something other facts still reference leaves dangling
handles behind.

Input parameters:

- `call_number`: Repository only: detach just the link with this call number, when a source is held twice in one repository. Omit to detach every link.
- `child` (string, required): Handle or gramps_id of the thing to detach; a tag may be given by name.
- `child_kind` (string, required): What to detach: event, media, note, tag (removes a tag), citation, child (a person from a family), person (a person_ref), repository, enclosure (a parent of a place), or -- on a person, to repair a l…
- `delete_if_orphan` (boolean): Also delete the detached object if nothing else references it. Off by default -- detaching and deleting are different decisions.
- `parent` (string, required): Its handle or gramps_id.
- `parent_type` (string, required): Type of the object holding the reference.

### `add_media` (~184 tokens)

Upload a document as a standalone Media object, reusing an identical file
already in the tree.

One image, one Media object -- then attach it wherever it belongs with
attach_media(media_ref=...) and cite it once per fact it proves. Uploading
the same photograph once per person it depicts is the duplicate pattern that
later has to be unpicked by hand.

Input parameters:

- `dedup_by_checksum` (boolean): Reuse an existing Media object if the identical file is already in the tree. Leave True.
- `description` (string, required): What the document IS -- archival identity, not the person it mentions ('1900 US census, Cedar Flat, Brannock Co., Ohio, ED 12 sheet 4A'). Files are stored under checksum names.
- `file_path` (string, required): Local path to the image, PDF, audio or video file to upload.

### `ocr_media` (~121 tokens)

Run OCR on a document image, server-side, to locate text within it.

A finding aid, not evidence. OCR output is a machine's guess at the writing,
and it is at its worst on exactly the handwritten records that matter most.
Use it to find WHERE something appears in a long scan; read the image before
citing what it says.

Input parameters:

- `lang` (string): Tesseract language code ('eng', 'deu', 'swe', 'nor', ...).
- `media` (string, required): Media handle or gramps_id.

### `export_backup` (~125 tokens)

Write a full-tree export to disk. Take one before any bulk write.

Cheap insurance: a few seconds and one file. A bulk write that goes wrong
cannot always be undone transaction by transaction; a dump can be
re-imported.

Input parameters:

- `dest_path`: A new file in an existing directory; an existing file is never replaced. Omit for a timestamped file in the cache directory.
- `export_format` (string): 'gramps' (Gramps XML, lossless -- use this for a safety dump), 'ged', 'json', or 'csv'.

### `list_transactions` (~73 tokens)

Recent writes to the tree: what changed, when, by which user.

Each entry's transaction_id is what undo_transaction takes. Useful for
"what did that bulk pass actually do?" and for finding the transaction to
reverse when it did the wrong thing.

Input parameters:

- `limit` (integer): How many, newest first.

### `undo_transaction` (~136 tokens)

Undo a past transaction, after checking whether it can be undone cleanly.

A conflict means an object was edited again after this transaction; undoing
anyway throws that later edit away. The conflict check is free and runs
first, so the default tells you what you are dealing with before anything
changes.

Input parameters:

- `dry_run` (boolean): True (default) only checks whether the undo is clean. Set False to actually undo.
- `force` (boolean): Undo even when there are conflicts. This DISCARDS edits made to those objects after the transaction. Use deliberately.
- `transaction_id` (integer, required): From list_transactions.

### `list_reports` (~85 tokens)

List the reports this Gramps instance can generate.

Gramps ships a full report engine — Ahnentafel, descendant reports, family
group sheets, kinship, fan and relationship charts, statistics, and an
end-of-line report that lists exactly where research stops. Each entry
names the option keys it accepts; read the defaults with
get_report_options before overriding any.

### `get_report_options` (~67 tokens)

Read one report's default options before running it.

Reports take a full option dict, not a partial one, so the way to change
a single setting is to read these defaults and override that key.

Input parameters:

- `report_id` (string, required): Report id, e.g. 'ancestor_report'.

### `run_report` (~170 tokens)

Generate a report and return the file it produced.

Living people and private records are left out (living_people 0,
incl_private false) unless you pass those options or include_private;
Gramps' own default includes both.

Usually runs in the background, returning a task_id to poll with get_task.

Input parameters:

- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `locale` (string): Language code for the report output.
- `options`: Overrides for the report's defaults, merged over them. Common keys: 'pid' (the central person's gramps_id), 'maxgen', 'off' (output format), 'living_people'.
- `report_id` (string, required): Report id, from list_reports.

### `list_filter_rules` (~93 tokens)

List the filter rules Gramps offers in a namespace.

This is the vocabulary that `query_records` and GrampsQL cannot reach:
"is a descendant of", "has a common ancestor with", "matches another
filter". Read it before building a custom filter with create_filter.

Input parameters:

- `namespace` (string): Plural namespace: people, families, events, places, sources, citations, repositories, media, notes.

### `list_custom_filters` (~63 tokens)

List the custom filters already saved on this instance.

A saved filter can be reused by name from `query_objects` and the
timelines, so a complicated selection is defined once.

Input parameters:

- `namespace` (string): Restrict to one namespace. Omit for all.

### `create_filter` (~182 tokens)

Save a reusable custom filter built from Gramps' own rules.

Worth doing for a selection you will run repeatedly — an audit scope, a
branch of the tree — because the filter then has a name rather than being
retyped each time.

Input parameters:

- `comment` (string): Note on the filter's purpose.
- `function` (string): How rules combine: 'and', 'or', or 'one'.
- `invert` (boolean): Return everything the rules do NOT match.
- `name` (string, required): Filter name, used to apply it later.
- `namespace` (string, required): Singular, capitalised: Person, Family, Event, Place, Citation, Source, Repository, Media, Note.
- `rules` (array, required): Rules, each {'name': <rule>, 'values': [...], 'regex': false}. Rule names come from list_filter_rules.

### `delete_filter` (~56 tokens)

Delete a saved custom filter.

Deletes the filter definition only. Nothing in the tree is touched.

Input parameters:

- `name` (string, required): Name of the filter to delete.
- `namespace` (string, required): Plural namespace, e.g. 'people'.

### `consolidated_timeline` (~197 tokens)

Merge several people or families into one chronological timeline.

The way to see a household move together through censuses, or to check
whether a family's events are mutually consistent. Carries the same
citation count and confidence per event as get_timeline, with an
uncited_count across the whole set.

Input parameters:

- `anchor` (string): Handle or gramps_id of the central person, so ages are reported relative to them.
- `event_types` (string): Comma-delimited event type names to include, e.g. 'Birth,Death,Census'. Omit for all.
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `limit` (integer): Maximum events.
- `object_type` (string): Either 'person' or 'family'.
- `targets` (array, required): Handles or gramps_ids to merge into one timeline.

### `list_tasks` (~54 tokens)

List recent background jobs for this tree, newest first.

Use when you have lost a task_id, or to see whether anything is still
running before starting a write session.

Input parameters:

- `limit` (integer): Maximum tasks to return.

### `get_transaction` (~51 tokens)

Read one transaction in full, including the objects it changed.

list_transactions summarises; this shows what actually moved. Read it
before undoing anything.

Input parameters:

- `transaction_id` (integer, required): Id from list_transactions.

### `get_place` (~84 tokens)

Read one place: name, title, type, enclosure, coordinates and URLs.

The `enclosed_by` handles are the jurisdictional chain. A place with none
is orphaned in the hierarchy, which is usually a place that got minted
from an event's place string rather than created deliberately.

Input parameters:

- `place` (string, required): Handle or gramps_id of the place.

### `get_citation` (~72 tokens)

Read one citation: page, confidence, date, and its source.

\`cited_by_count` is the useful part. Zero means nothing references this
citation — it is orphan debris, and `uncite` should have deleted it.

Input parameters:

- `citation` (string, required): Handle or gramps_id of the citation.

### `get_note` (~76 tokens)

Read one note in full, with its type and what it is attached to.

Notes hold the researcher's own reasoning — why a conflict was resolved
one way, what a hard-to-read page actually said — so the text comes back
whole rather than truncated.

Input parameters:

- `note` (string, required): Handle or gramps_id of the note.

### `get_media` (~84 tokens)

Read one media object: path, mime type, checksum, description, date.

\`referenced_by_count` above one is usually correct — one image cited from
every fact it proves. Several media objects sharing a checksum is the
duplicate that `find_duplicates(kind='media_checksum')` hunts.

Input parameters:

- `media` (string, required): Handle or gramps_id of the media object.

### `add_place` (~227 tokens)

Create a place deliberately, with a type and a parent.

Use this instead of letting a place appear as a side effect of naming one
in an event. That route produces an untyped, unparented place whose title
is the bare string you typed, which is how duplicate hierarchies start.

Input parameters:

- `code` (string): Postal or FIPS code.
- `latitude` (string): Latitude, decimal degrees.
- `longitude` (string): Longitude, decimal degrees.
- `name` (string, required): The place's own name, e.g. 'Cedar Flat'.
- `parent` (string): Handle or gramps_id of an existing enclosing place. Must already exist — it is never created for you.
- `place_type` (string): Gramps place type: Town, City, County, State, Country, Parish, Cemetery, and so on.
- `title` (string): Full display title, e.g. 'Cedar Flat, Brannock, Ohio, USA'. Defaults to the name. This is what event place matching compares against, so set it properly.

### `get_facts` (~213 tokens)

Read the tree's record-holders: oldest at death, youngest parent, most children.

Superlatives across a set of people, not statistics about one person. An
implausible holder — a father at eight, a death at 130 — is usually a data
error, which makes this a quick plausibility check. Living and private
people are excluded unless include_private is set. Slow: the server
computes it all per call.

Input parameters:

- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `person` (string): Handle or gramps_id a built-in person_filter is anchored on.
- `person_filter` (string): Narrow the set: 'Ancestors', 'Descendants', 'DescendantFamilies' or 'CommonAncestor' of person, or a saved custom person filter's name. Omit for the whole tree.
- `rank` (integer): Record-holders to return per statistic.

### `get_researcher` (~50 tokens)

Read the researcher details recorded for this tree.

These are embedded in every export, so they travel with any GEDCOM or
Gramps XML you hand to someone else. Worth checking before sharing one.

### `query_records` (~487 tokens)

Query any collection server-side, with columns, filters and sorting.

More capable than `query_objects` and the tool to reach for on an audit.
It reads indexed columns, reaches arbitrary paths inside the stored object,
and follows relationships — so "families where the mother died before the
father" or "events whose place is in Ohio" are single queries.

\**It is the only way to filter events by type.** GrampsQL cannot: the word
is shadowed, so `type = "Birth"` silently matches nothing. Pass `event_type`
here instead.

Returns rows plus a total count and a `next_after` cursor. Private records,
living people and families with a living parent come back as redacted stubs.

Input parameters:

- `after` (string): Cursor from a previous response's next_after, for paging past the first page.
- `event_type` (string): Events only. Filter by type name such as 'Birth' or 'Census'. Translated to the integer the tree stores, which is the only way event type is filterable at all.
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `limit` (integer): Maximum rows (1-500).
- `object_type` (string, required): Collection to query: person, family, event, place, source, citation, repository, media, note, or tag.
- `order_by`: Sort keys, each {"column": ..., "direction": "asc" or "desc"}. json_path is not usable here.
- `select`: Columns to return. A plain column name, or {"json_path": [...], "as": "label"} to reach into the stored object. A path may cross a relationship: person->birth/death, family->father/mother, event->pla…
- `where`: Conditions combined with AND. Each is {"column": <name or json_path>, "op": <op>, "value": ...}. Operators: eq, ne, lt, lte, gt, gte, like, regex, contains, in. Use "value_column" instead of "value"…
- `where_expr`: An expression instead of `where`, e.g. "surname == 'Smith'".

### `list_event_types` (~63 tokens)

List the event type names this tree uses, with their stored integers.

Useful before a `query_records` filter, and as a check on itself: an
unexpected type name in the list is usually a typo that Gramps silently
accepted as a new custom type.

### `add_dna_match` (~240 tokens)

Record a DNA match as evidence, cited to the test that found it.

Stored as Gramps Web stores a match, so its interface and get_dna_matches
read it back. Nothing is written unless the segments parse: unreadable data
would otherwise record a match sharing no DNA.

A match proves the two share DNA, not how they are related. Record any
relationship separately, with its own evidence.

Input parameters:

- `citation` (required): The test the match came from: source or source_title naming the company and kit, page for where the match is shown, confidence in the match itself. A new citation is always minted.
- `match` (string, required): Handle or gramps_id of the matching person. Add them first if they are not in the tree.
- `person` (string, required): Handle or gramps_id of the tested person, whose results list the match.
- `segments` (string, required): The shared segments as the testing company exports them: rows of chromosome, start, stop, centiMorgans, SNPs, comma- or tab-separated, with an optional side of M, P or U. A header row is tolerated.

### `get_dna_matches` (~159 tokens)

List the DNA matches recorded against a person.

Each match reports total shared centiMorgans and the largest single
segment — the two figures a relationship estimate actually rests on —
plus any common ancestor already identified.

\**DNA evidence works differently from documentary evidence.** A match
proves a biological relationship exists; it does not say which one. Shared
cM constrains the possibilities and rarely resolves them, and it says
nothing about the paper trail. `unattributed_count` is the useful number:
matches with no common ancestor identified are the open research.

Input parameters:

- `include_raw` (boolean): Include the unparsed note text the segments came from.
- `person` (string, required): Handle or gramps_id of the tested person.

### `get_ydna` (~145 tokens)

Report a person's Y-DNA haplogroup, from broadest clade to terminal.

Y-DNA follows the direct paternal line only, so it speaks to one thread
of a tree and is silent on every other. A shared terminal clade indicates
a common paternal ancestor, usually far further back than any record
reaches — it corroborates a surname line rather than proving a named
link.

\`has_data` is false when the person has no Y-DNA recorded, which is the
normal case.

Input parameters:

- `include_raw` (boolean): Include the raw SNP data string.
- `person` (string, required): Handle or gramps_id of the tested person.

### `parse_dna_segments` (~170 tokens)

Parse pasted shared-segment data into structured segments and totals.

Use this to check what a match file actually contains before recording
it. Returns each segment plus the total and largest-segment centiMorgans.

If nothing parses, `parsed` is false and the reason is given. That
distinction matters: the server answers unreadable input with zero
segments and a success status, which would otherwise read as "this person
shares no DNA" rather than "I could not read that".

Input parameters:

- `data` (string, required): Raw shared-segment data, as a testing company exports it: rows of chromosome, start, stop, centiMorgans, SNPs, separated by commas or tabs, with an optional side of M, P or U. A header row is tolerat…

### `get_relationship` (~144 tokens)

Work out how two people in the tree are related.

Returns the relationship in words plus the generation distance from each
person to their common ancestor. `related` is false when no common
ancestor was found within the search depth — which is a finding in itself
if you expected one.

Input parameters:

- `all_paths` (boolean): Report every relationship path, not just the closest. Use this when two people may be related more than one way.
- `depth`: Generations to search. Server default if omitted.
- `person1` (string, required): Handle or gramps_id of the first person.
- `person2` (string, required): Handle or gramps_id of the second person.

### `assess_living` (~171 tokens)

Ask the server whether a person is probably still alive, and why.

The server walks relatives to decide, so it handles people with no dates
of their own — someone undated whose children died a century ago. Use it
before publishing or sharing anything, and use `explain` when you want to
see the reasoning rather than just the verdict.

Note this is advisory. Bulk output is filtered by this server's own rule
regardless of what this returns.

Input parameters:

- `average_generation_gap`: Years per generation used when estimating.
- `explain` (boolean): Also return the estimated birth and death dates and which relative they were derived from.
- `max_age_probably_alive`: Age beyond which a person is presumed dead.
- `person` (string, required): Handle or gramps_id of the person.

### `get_timeline` (~176 tokens)

Build a chronological timeline of someone's life events.

Each entry carries their age at the time, how many citations support the
event, and the strongest confidence among them — so a timeline doubles as
a readable audit of where the evidence thins out. `uncited_count` says how
many events on it rest on nothing.

Input parameters:

- `ancestors`: Generations of ancestors whose events to fold in.
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `limit` (integer): Maximum events to return.
- `object_type` (string): Either 'person' or 'family'.
- `offspring`: Generations of descendants whose events to fold in.
- `target` (string, required): Handle or gramps_id of the person or family.

### `event_span` (~127 tokens)

Measure the elapsed time between two events.

The arithmetic behind most plausibility checks: age at marriage, years
between a census and a death, how long a widow waited. Doing this by hand
from two formatted date strings is where transcription errors hide.

Input parameters:

- `as_age` (boolean): Phrase the result as an age rather than an interval.
- `event1` (string, required): Handle or gramps_id of the first event.
- `event2` (string, required): Handle or gramps_id of the second event.
- `precision`: How many units to include (years, months, days).

### `reindex_search` (~99 tokens)

Rebuild the full-text search index.

\`search_text` reads a stored index, and nothing refreshes it after writes.
Run this after a bulk import or a large editing session, or searches will
quietly miss everything added since the last build. Returns a task_id to
poll with get_task.

Input parameters:

- `full` (boolean): Rebuild from scratch rather than updating incrementally. Slower, and the right choice after a large import.

### `get_task` (~109 tokens)

Check whether a background job has finished, and whether it worked.

Undo, verification, import and reindex are dispatched to a worker and
answer before the work is done. Poll this until `finished` is true, then
read `succeeded`. Submitting one of those operations and never checking
leaves you assuming an outcome you have not seen.

Input parameters:

- `task_id` (string, required): Task id returned by whatever dispatched the work, e.g. the task_id from undo_transaction or verify_tree.

### `verify_tree` (~503 tokens)

Run Gramps' own genealogical plausibility checks over the whole tree.

This is a different audit from the citation ones. `list_unsourced_facts`
asks whether a claim has evidence; this asks whether a claim is possible —
a mother bearing a child at nine, a marriage lasting 120 years, a date that
will not parse. A wrong date can be impeccably sourced, so these catch what
a citation sweep cannot.

Leave the thresholds alone on a first run; the server's defaults are the
conventional ones. Tighten a specific bound when chasing a specific class
of error.

May run in the background, in which case a task_id comes back — poll it
with get_task.

Input parameters:

- `estimate_age` (boolean): Estimate missing or inexact dates when checking ages. Finds more, at the cost of guessing.
- `flag_invalid_dates` (boolean): Report dates the parser cannot read.
- `max_age_at_death`: Flag a death later than this age. Server default 90.
- `max_age_to_marry`: Flag a marriage older than this. Server default 50.
- `max_child_birth_span`: Flag a longer span of one couple's births. Default 25.
- `max_children_father`: Flag a man with more children than this. Default 15.
- `max_children_mother`: Flag a woman with more children than this. Default 12.
- `max_father_age`: Flag a father older than this. Server default 65.
- `max_husband_wife_age_gap`: Flag a wider spousal age gap. Server default 30.
- `max_mother_age`: Flag a mother older than this. Server default 48.
- `max_spouses`: Flag more spouses than this. Server default 3.
- `max_widowhood_years`: Flag a longer widowhood before remarriage. Default 30.
- `max_years_between_children`: Flag a longer gap between siblings. Default 8.
- `min_age_to_marry`: Flag a marriage younger than this. Server default 17.
- `min_father_age`: Flag a father younger than this. Server default 18.
- `min_mother_age`: Flag a mother younger than this. Server default 17.
- `tree_id` (string): Tree to check. Leave empty to use the tree these credentials are bound to, which is the usual case.

### `consult_reference` (~222 tokens)

Consult the legacy GEDCOM reference layer for HINTS (never authoritative).

Searches the configured Ancestry/FamilySearch exports and returns, per file,
matching individuals and their claimed facts. Crucially, each fact is flagged
whether the legacy tree attached a source, with the source text if present --
so you can distinguish 'they cite an actual death certificate' from 'unsourced
guess'. These are UNTRUSTED hints: use them to decide what real record to hunt
for, then create the fact in the tree citing that record -- do not copy a hint
in as a sourced fact. Probably-living people are withheld and counted.

Input parameters:

- `approx_birth_year`: Approximate birth year to disambiguate (± a few years).
- `include_private` (boolean): Show living people and private records in full. Only when the user asks for them; they are withheld by default.
- `name` (string, required): Name (or name substring) to look up.
- `year_tolerance` (integer): Allowed birth-year difference when matching.

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/ianderso-gramps-evidence-mcp/gramps-evidence-mcp#diagnostics

## Score history

- 2026-10-01: 66
- 2026-09-30: 66

## Common questions

### What is the Gramps Evidence MCP server?

Gramps Evidence is an MCP server listed in the public MCP registry as io.github.ianderso/gramps-evidence-mcp. Read/write a self-hosted Gramps Web family tree where every fact carries a citation. This page covers its PyPI package (gramps-evidence-mcp).

### Is the Gramps Evidence MCP server safe to use?

Gramps Evidence scores 66 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 1 October 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the Gramps Evidence MCP server expose?

Gramps Evidence exposes 89 tools: add_person, add_event_to_person, add_family, add_source, add_citation, and 84 more. Their descriptions and schemas cost roughly 14,020 tokens of context every time the server is loaded.

### Is the Gramps Evidence MCP server still maintained?

Gramps Evidence is still listed as active in the MCP registry. We last reached this channel on 1 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the Gramps Evidence MCP server under?

Gramps Evidence declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/gramps-evidence-mcp/
- Socket report: https://socket.dev/pypi/package/gramps-evidence-mcp
- Repository: https://github.com/ianderso/gramps-evidence-mcp
- Changelog RSS feed: https://verifymcp.io/servers/ianderso-gramps-evidence-mcp/gramps-evidence-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/ianderso-gramps-evidence-mcp/gramps-evidence-mcp.json
- HTML version of this page: https://verifymcp.io/servers/ianderso-gramps-evidence-mcp/gramps-evidence-mcp
