familysearch-org-mcp
This server provides an MCP interface to FamilySearch.org for reading/searching the shared Family Tree and historical records, and for making public, attributed edits to people, relationships, sources, notes, and memories.
People: get, search, ancestry/descendancy, changes, and matches; create/update persons and add/edit/delete conclusions (facts, names, gender) with change messages/reasons.
Relationships: get, create, and delete couple and child-parent relationships, including lineage types.
Sources: list a person's sources or your Source Box, create source descriptions, attach/detach them with tags, and delete descriptions.
Notes: list, add, and delete notes on persons.
Memories: list person/mine, get metadata, download to file or inline, upload local files, attach to persons, and delete.
Historical records: search indexed records with filters/facets, get full records by persona/ark, download record images (optionally scaled/cropped), and list collections; README also describes full-text OCR search, catalog/browse, and film image listing.
Places: search and get standardized place descriptions with jurisdictions/coordinates.
Session and raw access: check login status/open login, and make arbitrary FamilySearch platform or website
/service/requests via raw_request.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@familysearch-org-mcp search historical records for my ancestor John Smith"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
familysearch-org-mcp
An MCP server for FamilySearch.org: the shared Family Tree (read, search, add people, facts, relationships,
sources, notes, memories), historical record search and record reading, and standardized places.
Companion to ancestry-com-mcp; both can be attached at once.
Tools are prefixed familysearch_ and ancestry_ so they never collide.
Unofficial. Not affiliated with or endorsed by FamilySearch. It authenticates with your own website session rather than a developer key, which FamilySearch may not sanction; the Family Tree is shared and public, so every write is visible to everyone. Use it with care, at your own risk.
How it works
FamilySearch has a documented platform API (GEDCOM X). Production developer keys are only issued to registered
businesses, but the website's own session cookie (fssessionid) is accepted as an OAuth bearer token by
api.familysearch.org, and plain Node requests are not bot-blocked there. So this server runs without a
browser: all API calls go straight from Node with Authorization: Bearer <cookie>. Historical record search
lives on www.familysearch.org/service/… behind Imperva bot protection and goes through a Chrome-impersonating
client (impit) instead. Cookies are kept in .session.json (mode 600,
git-ignored). The token expires after 24 h or 60 min idle, but the server mints a new one silently by replaying
the website's OAuth login redirect with the saved identity cookies, so a real Chrome is needed only for the
initial sign-in (pnpm login or the familysearch_session tool's login action: opens a dedicated Chrome
profile, waits for you to log in, saves the cookies, closes the window) and again if the identity session
itself expires.
Requirements: Node 26+, pnpm, Google Chrome.
Related MCP server: Gramps MCP
Setup
git clone https://github.com/ball2jh/familysearch-org-mcp
cd familysearch-org-mcp
pnpm install
pnpm login # one-time: opens Chrome to sign in, saves .session.json, closes Chrome
pnpm mcp-test # read-only checkClaude Code / Claude Desktop config (stdio):
{ "mcpServers": { "familysearch": { "command": "node", "args": ["/absolute/path/to/familysearch-org-mcp/src/server.ts"] } } }Tools
Tools are grouped by resource and split into a read tool and an edit tool, so an MCP client can
auto-approve reads and ask before writes based on the tool annotations (readOnlyHint, destructiveHint,
idempotentHint, openWorldHint, all set honestly on every tool). Every tool takes an action parameter;
every parameter is described in the schema, and a missing parameter for an action comes back as an error naming
it. The whole definition set is about 10K tokens.
Tool | Actions | Writes? |
| status, login | opens Chrome, saves cookies |
| get, search, ancestry, descendancy, changes, matches, notes | no |
| create, update, delete_conclusion, delete | yes, public |
| get_couple, get_child_parents | no |
| create_couple, create_child_parents, delete_couple, delete_child_parents | yes, public |
| list_person, source_box, get | no |
| create, attach, detach, delete_description | yes, public |
| add, delete | yes, public |
| list_person, list_mine, get | no |
| upload, attach, delete | yes |
| search, fulltext (OCR text of unindexed images), get, collections, collection, catalog / catalog_item (the FamilySearch Catalog: books, microfilm, digital folders and their film numbers), browse (a collection's county/volume/image hierarchy), film (every image of a digital film) | no |
| record_image (by persona, record or image ark, or a film image's storage id; optional region to zoom), memory | writes a local file, or returns the image inline |
| search, get | no |
| any platform request (or a | can |
Files: familysearch_download writes record images and memory files to a local outPath; without outPath,
images come back inline (record images scaled to maxWidth, default 1600 px, and always fitted to what the
model can see: at most 2000 px on the long edge and 4784 visual tokens) so the assistant can look at them. To
read small handwriting, region cuts part of the page from the full-resolution scan (with the sharp image
library), so a quarter page reaches the model near full resolution. familysearch_memory_edit upload reads from a local filePath.
The Family Tree is a single shared public tree. Every write is visible to everyone and attributed to the
user, so the edit tools take a changeMessage/reason and the server instructions tell the model to search
before creating, be conservative, cite sources, and confirm deletions.
Results: JSON, trimmed to what a caller acts on. A result over 36K characters (about 9K tokens, under the 10K-token warning and 25K-token cap Claude Code applies to tool results; override with
MCP_MAX_RESULT_CHARS) is cut at an item boundary so it stays valid JSON, and carries a _truncated field with
the count shown, the total, and how to get the rest. Errors, including validation errors and upstream HTTP
failures, come back as tool results with isError: true and a message that says what to do next. A 429 from
FamilySearch is retried once after its Retry-After; if it persists the error says how long to wait.
Tests
pnpm test— unit tests, no network: result helpers, error andWarningparsing, fact-type normalization, restricted-image access rules (test/restricted.test.ts), the search, relationship, ancestry, descendancy, collection, catalog (holdings, film paging and filter), full-text (the boolean query compiler, paging through split searches, facets) and waypoint projections on recorded response shapes (test/fixtures/), andtest/writes.test.ts, which runs the real client against a fake person intest/fake-transport.tsthat applies each write the way FamilySearch does, to check the body every edit sends and the result it reads back (a date-only fact edit keeps its place, a second Birth is refused, a new name is not preferred, a warning is an error).test/conventions.test.tsandtest/tools.test.tsare static checks: no write swallows a failed read, every write's result comes from a returned id or a read-back and never an optional id or a bareok: true, every person POST goes through theWarningcheck, failed requests keep their HTTP status, every tool action has a handler and every parameter a description.pnpm mcp-test— read-only end-to-end run over stdio against your account: checks that every tool has a title, full annotations and described parameters, calls every read action, downloads one image inline and one to disk, and checks that error paths come back asisErrorresults. Prints definition size and per-call latency.pnpm mcp-write-test— creates three living (therefore private) "Mcptest" people and touches nothing else: adds and removes a note, facts, names, a source and a memory on one of them, checks each refusal (a second Birth, a new preferred name, an unknown place id or source description, a delete without a reason), links them as a couple and a child, and reads every write back to check what was stored and that the unmentioned fields survived. Cleanup runs in afinally, so a failing step does not leave test people behind.
Repository layout
src/transport.ts— bearer-token HTTP, silent token renewal, Imperva client, pacing, rate-limit handling, error unwrappingsrc/session.ts— cookie jar persisted in.session.jsonsrc/browser.ts— Chrome bootstrap used only byloginsrc/client.ts— typed client over the GEDCOM X platform API, with response compactionsrc/result.ts— tool-result helpers: JSON-safe truncation, inline images, errors, action dispatchsrc/tools.ts— MCP tool definitionssrc/server.ts— stdio entry point and server instructionsscripts/—login.ts, the Chrome launcher, the traffic recorder, and the two end-to-end teststest/— unit testsdocs/endpoints.md— verified endpoint table, including which documented paths do not work
Caveats
The session token expires (24 h / 60 min idle); the server renews it silently from the saved identity cookies. When that renewal fails too, tools report not logged in and
familysearch_session logingets you back in.FamilySearch throttles (HTTP 429); requests are spaced 120 ms apart and a 429 is retried once after
Retry-After.Unindexed material:
fulltextsearches the OCR'd text of wills, deeds, probate, court and land books and newspapers, which the indexedsearchnever sees; every hit carries the entire page text upstream, so the tool returns a snippet around the match unlessincludeTextis asked for. FamilySearch's own query language is not boolean (+wordrequired,-wordexcluded, every other word optional; AND/OR are ignored words and parentheses group nothing), so the tool compiles its booleantextinto that: words are required, and an OR inside an AND runs as up to 8 searches that do not overlap, whose totals add up (see "Full-text query syntax" indocs/endpoints.md). Its place, collection, year and record-type filters are the site's facets: the upstreamq.placeparameter is silently ignored, soplaceis matched against the index's place tree (region > country or state > county > town) and a part it cannot match is refused with the choices rather than searched wider.browsewalks a collection's waypoints (county → volume → images) andfilmlists a digital film's images in order (the storage service ignores paging offsets, so the tool pages client-side). Both hand back image arks or storage ids thatfamilysearch_download record_imageaccepts.Restricted images (viewable only at a FamilySearch center or affiliate library, only by Church members, or not at all) cannot be downloaded:
record_imagefails naming the rule,geton the image ark returnsrestrictedwith its collection, waypoint and citation, andfilmsaysrestricted(ormixed: …) up front. The index of such an image is often still readable withsearchandget. See "Restricted images" indocs/endpoints.md.Replace-style writes refill what the caller left out. A conclusion sent with an id replaces the stored one wholesale, so
familysearch_person_edit updatereads the person first and keeps the unmentioned date, place, value, name type, preferred flag and name parts;scripts/mcp-write-test.tsedits a fact with only a date and checks the place survived. Any new write that replaces a record must follow the same rule.Some writes that look like additions are replacements upstream and are refused instead: a second Birth, Christening, Death, Burial or other single-instance fact without an id (FamilySearch overwrites the stored one), and a new name sent as preferred (it replaces the preferred name). New names are added as alternates.
FamilySearch answers HTTP 200 to writes it only partly applied or ignored (an unknown place id, an unknown source description, a repeated source attachment). A person POST with a
Warningheader is reported as an error, place ids and source descriptions are checked before writing, and every write's result is read back from the person.Tool schemas are strict: a parameter the tool does not have is rejected by name rather than dropped. Per-page counts are clamped to what fits the result budget (record search 40, full text 20, film and browse 250, collections 80, catalog 50, catalog_item films 200); recorded sessions asked for 50 to 1000 and got truncated results they then worked from.
Tree search accepts a year range ("1745-1780") and sends it as from/to; the platform rejects the single value.
The research project that uses these servers should run them from a separate stable clone (see
CLAUDE.md), not from a checkout that is being edited.Not covered: LDS ordinance data, user (private) trees, discussions, and the Source Box folder management.
.session.json,.profile/andcaptures/hold live session cookies and are gitignored. Never commit them.The server logs only to stderr, so it is safe on stdio.
Available Tools
9 toolsfs_sessionARead-only
FamilySearch login session. "status" reports whether the dedicated Chrome is signed in and who the user is; "open_login" opens the sign-in page for the user.
Inputs: action (required).
memoryADestructive
Memories (photos, documents). Actions: list_person · list_mine · get (metadata + file url) · download (file to outPath, or base64) · upload (local file → my memories; then attach) · attach (memoryId → personId) · delete (memoryId).
Inputs: action (required), count, start, title, +6 more.
noteADestructive
Notes on a Family Tree person. Actions: list · add (subject + text) · delete (noteId).
Inputs: action (required), text, noteId, subject, +2 more.
personADestructive
People in the FamilySearch Family Tree (one shared, collaborative tree — edits are public and attributed; always give a changeMessage/reason). Actions: get (names, facts with ids, relatives, couple and child-parent relationships; sources=true adds source descriptions) · search (tree persons by name/dates/places/relatives; q* fields; matching is fuzzy by default — name wildcards "?" = one character, "" = any length, up to 4 per name, at least 3 literal letters, may lead or trail: bou, Tlts*) · ancestry / descendancy (generations) · changes (change history) · matches (record hints; records=true) · create (unconnected new person; connect with relationship.create) · update (add or edit facts/name/gender; a fact with id edits, without id adds) · delete_conclusion (remove a fact/name/gender by id) · delete (remove a person you created; needs reason). Dates and places on facts should carry formalDate and placeId (see the fact fields) or the tree flags them as non-standardized. Living people you create are private to your account (invisible to other users) until marked deceased.
Inputs: action (required), sex, name, count, +26 more.
placeBRead-only
Standardized places. Actions: search (name → place ids, jurisdictions, coordinates) · get (place description by id).
Inputs: action (required), count, query, placeId.
raw_requestADestructive
Escape hatch: any FamilySearch platform request with the session bearer token (path like "/platform/tree/persons/XXXX-XXX"; default Accept application/x-fs-v1+json). Set viaSite=true for www.familysearch.org /service/ endpoints that reject non-browser clients.
Inputs: path (required), accept, method, viaSite, +2 more.
recordARead-only
FamilySearch historical records. Actions: search (indexed records by name/dates/places/relatives/census role; collectionType narrows to a category; every field is fuzzy unless listed in exactFields; facets=true returns the site filter groups (collection, birth/marriage/death/residence place region and year range, sex) whose params can be passed back via extraParams; use offset/count to page; wildcards are rarely needed — "?" = one character, "" = any length, up to 4 per name, at least 3 literal letters, may lead or trail: Sm?th, bou, Tlts*) · get (full record by persona id or ark, with all persons on the record, their events, and the image ark) · download_image (the record's scanned image as JPEG to outPath or base64; maxWidth to scale) · collections (record collections). To cite a record on a tree person: source.create with about=the record ark, then source.attach.
Inputs: action (required), sex, race, count, +39 more.
relationshipADestructive
Family Tree relationships. Actions: create_couple (person1 + person2, optional marriage facts) · create_child_parents (child + parent1/parent2, lineage types BiologicalParent/AdoptiveParent/StepParent/FosterParent/GuardianParent) · get_couple / get_child_parents (by relationship id, from person.get) · delete_couple / delete_child_parents (needs reason).
Inputs: action (required), child, facts, reason, +8 more.
sourceADestructive
Sources on FamilySearch. A source description lives in the user's Source Box; attaching it to a person creates a source reference (with optional tags = the fact types it supports). Actions: list_person (a person's attached sources) · source_box (my source descriptions) · create (title, citation, optional about URL/ark) · get · delete_description · attach (personId + descriptionId + tags) · detach (personId + sourceReferenceId).
Inputs: action (required), note, tags, about, +8 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 9 tools
Each tool maps to a clear, distinct resource type—person, relationship, source, record, memory, note, place, session, and raw request. Descriptions clearly separate overlapping concepts like person.search vs record.search or memory.attach vs source.attach. No two tools appear to do the same thing.
All tool names are singular nouns representing domain entities, with compound names using underscores (fs_session, raw_request). This is a consistent, predictable pattern. No mixing of verb styles, casing, or conventions.
9 tools is well within the ideal 3-15 range and appropriately scoped for FamilySearch. Each tool covers a distinct functional area without redundancy or bloat. The set feels balanced for the platform's core genealogy workflows.
Core lifecycles are well covered: person CRUD, relationship create/get/delete, source attach/detach, memory upload/attach, note add/delete, record search/get, and place lookup. Minor gaps like updating a note, source description, or relationship are workaroundable via delete/recreate, so slightly short of full CRUD completeness.
Related MCP Connectors
Household health records with source attribution. Read and add records with OAuth approval.
Search, read and cite documents. Add, replace and delete files with write access. OAuth required.
Read wearables and lab health data — sleep, activity, workouts, timeseries, lab tests and orders.
Read, write, and combine connected apps and databases with shared code and per-person permissions.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to create, edit, and query genealogical data from GEDCOM files. Supports complex genealogy searches, automatic data enrichment from web sources, relationship analysis, and biography generation for individuals and families.17MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to interact with Gramps genealogy databases for intelligent family tree research and management. Provides comprehensive tools for searching family data, creating records, analyzing relationships, and tracking genealogy research through natural language.51AGPL 3.0
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to query genealogy data from GEDCOM files with 24 tools for search, navigation, relationship analysis, and timeline events.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to search FamilySearch's Family Tree, view person details, explore ancestors and descendants, and search historical records using browser session authentication.7 npm6MIT