Skip to content

Latest commit

 

History

History
670 lines (573 loc) · 14.9 KB

File metadata and controls

670 lines (573 loc) · 14.9 KB

Gramps Web MCP Server – Product Requirements Document (PRD)

1. Overview

The Gramps Web MCP Server exposes the Gramps Web HTTP API as a set of MCP tools so AI assistants can inspect and edit a Gramps family tree over HTTP.[web:8][web:10] It targets a self-hosted Gramps Web API instance (usually via Docker) and focuses on core genealogy objects: people, families, events, and places.[web:10][web:12]

The server is stateless, configured via environment variables for base URL and auth token, and acts purely as an HTTP–JSON proxy with light validation and ergonomic argument shapes.

The gramps server should also produce a CLI tool that is easily compatible with OpenClaw as a skill.


2. Goals and Non‑Goals

2.1 Goals

  • Provide a safe well-typed MCP interface over the Gramps Web API (read/write).[web:10]
  • Cover the 80% workflows: searching, retrieving, and creating/updating people, families, events, and places.[web:10][web:19]
  • Make person-centric workflows easy (e.g., get a person with families, ancestors, and descendants in one call via composition tools).[web:10][web:17]
  • Keep configuration minimal (base URL, API token, tree ID).

2.2 Non‑Goals

  • No direct DB access; all operations go through the Gramps Web HTTP API.[web:10]
  • No schema migration or Gramps core plugin features.[web:17]
  • No UI; this is MCP only, for consumption by AI clients.

3. System Context

3.1 External Dependency: Gramps Web API

  • Backend: Python + Flask REST API for Gramps.[web:8][web:12]
  • Typical base URL: https://example.com/api or http://localhost:5000/api.[web:10][web:20]
  • Standard REST endpoints include (names vary slightly by version):[web:10][web:19]
    • /meta – API metadata and version.
    • /people, /people/{handle}
    • /families, /families/{handle}
    • /events, /events/{handle}
    • /places, /places/{handle}
  • Authentication: typically bearer token or session cookie, configured on the API.[web:10][web:20]

3.2 MCP Server Role

  • Acts as a thin adapter:
    • Translates MCP tool calls → HTTP requests to Gramps Web API.
    • Validates and normalizes arguments (e.g., person handle vs Gramps ID).
    • Returns structured JSON responses suitable for LLM consumption.

4. Configuration

The server is configured via environment variables and optional JSON config.

4.1 Environment Variables

  • GRAMPS_WEB_BASE_URL (required)
    • Base URL of Gramps Web API, e.g., https://my-gramps/api.
  • GRAMPS_WEB_API_TOKEN (optional but recommended)
    • Bearer token or API key, sent as Authorization: Bearer <token>.
  • GRAMPS_WEB_TREE_ID (optional)
    • Default tree ID or name if the API instance supports multiple trees.
  • GRAMPS_WEB_REQUEST_TIMEOUT_MS (optional, default 15000)
    • HTTP timeout in milliseconds.
  • GRAMPS_WEB_VERIFY_TLS (optional, default true)
    • When false, disables TLS verification for self-signed dev setups.

4.2 Error Handling

All tools must:

  • Map HTTP 4xx/5xx into structured MCP errors with:
    • error_code (NOT_FOUND, VALIDATION, AUTH, SERVER).
    • http_status.
    • details (string with concise human message).
  • Surface Gramps API validation errors as part of details.[web:10]

5. Data Models (MCP-Level JSON)

These are logical JSON models exposed to MCP clients; internally they map 1:1 or very closely to Gramps Web API payloads.[web:10][web:17]

5.1 Person

{
  "handle": "string",
  "gramps_id": "string",
  "primary_name": {
    "first_name": "string",
    "surname": "string",
    "suffix": "string | null"
  },
  "gender": "UNKNOWN | MALE | FEMALE | OTHER",
  "birth": {
    "event_handle": "string | null",
    "date": "string | null",
    "place_title": "string | null"
  },
  "death": {
    "event_handle": "string | null",
    "date": "string | null",
    "place_title": "string | null"
  },
  "family_handles": {
    "as_child": ["string"],
    "as_spouse": ["string"]
  },
  "tags": ["string"],
  "private": "boolean"
}

5.2 Family

{
  "handle": "string",
  "gramps_id": "string",
  "father_handle": "string | null",
  "mother_handle": "string | null",
  "parent_handles": ["string"],
  "child_handles": ["string"],
  "marriage_event_handle": "string | null",
  "tags": ["string"],
  "private": "boolean"
}

5.3 Event

{
  "handle": "string",
  "gramps_id": "string",
  "type": "string",
  "date": "string | null",
  "place_handle": "string | null",
  "description": "string | null",
  "citation_handles": ["string"],
  "note_handles": ["string"],
  "tags": ["string"],
  "private": "boolean"
}

5.4 Place

{
  "handle": "string",
  "gramps_id": "string",
  "title": "string",
  "latitude": "number | null",
  "longitude": "number | null",
  "code": "string | null",
  "place_type": "string | null",
  "tags": ["string"],
  "private": "boolean"
}

6. MCP Tools (Endpoints)

This section defines the MCP tools, not the raw HTTP paths, but each tool includes the underlying HTTP method and URL pattern for implementation.

6.1 Health & Metadata

6.1.1 gramps_health

  • Purpose: Check connectivity, authentication, and basic metadata.
  • HTTP: GET /meta[web:10]
  • Input:
    {}
  • Output:
    {
      "status": "ok | degraded | error",
      "api_version": "string | null",
      "backend_version": "string | null",
      "tree_id": "string | null",
      "message": "string"
    }
  • Behavior:
    • If HTTP 200: status = "ok".
    • If 401/403: status = "error", message explains auth issue.
    • If timeout or network error: status = "error".

6.2 People

6.2.1 gramps_list_people

  • Purpose: List people with simple filters and pagination.
  • HTTP: GET /people[web:10][web:19]
  • Input:
    {
      "query": "string | null",
      "limit": "number | null",
      "offset": "number | null",
      "order_by": "name | gramps_id | change | null",
      "ascending": "boolean | null"
    }
  • HTTP mapping:
    • /people?filter=<query>&limit=<limit>&offset=<offset>&order_by=<order_by>&ascending=<true|false> (parameter names adjusted to match API once confirmed).[web:10]
  • Output:
    {
      "total": "number",
      "items": ["Person"]
    }
  • Notes:
    • query is passed as a server-side filter/search parameter if supported; otherwise ignored.[web:19]

6.2.2 gramps_get_person

  • Purpose: Fetch a person by handle or Gramps ID.
  • HTTP: GET /people/{handle} or GET /people?gramps_id=... depending on API.[web:10]
  • Input:
    {
      "handle": "string | null",
      "gramps_id": "string | null"
    }
  • Rules:
    • Exactly one of handle or gramps_id must be non-null.
  • Output:
    {
      "person": "Person"
    }

6.2.3 gramps_search_people

  • Purpose: Full-text search across people fields (name, ID, notes where supported).
  • HTTP: GET /people with search or similar query param (adjusted to actual API).[web:10][web:19]
  • Input:
    {
      "text": "string",
      "limit": "number | null"
    }
  • Output:
    {
      "items": ["Person"]
    }

6.2.4 gramps_create_person

  • Purpose: Create a new person record.
  • HTTP: POST /people[web:10]
  • Input:
    {
      "primary_name": {
        "first_name": "string",
        "surname": "string"
      },
      "gender": "UNKNOWN | MALE | FEMALE | OTHER | null",
      "birth": {
        "date": "string | null",
        "place_handle": "string | null"
      },
      "death": {
        "date": "string | null",
        "place_handle": "string | null"
      },
      "tags": ["string"]
    }
  • HTTP body mapping:
    • Convert to Gramps Web Person JSON structure (fields like name, gender, event_ref_list, etc., following the OpenAPI/spec).[web:10]
  • Output:
    {
      "person": "Person"
    }

6.2.5 gramps_update_person

  • Purpose: Update existing person fields.
  • HTTP: PATCH /people/{handle} or PUT depending on API.[web:10]
  • Input:
    {
      "handle": "string",
      "primary_name": {
        "first_name": "string | null",
        "surname": "string | null"
      },
      "gender": "UNKNOWN | MALE | FEMALE | OTHER | null",
      "birth": {
        "date": "string | null",
        "place_handle": "string | null"
      },
      "death": {
        "date": "string | null",
        "place_handle": "string | null"
      },
      "tags": ["string"]
    }
  • Behavior:
    • Only non-null fields will be updated where the API supports partial updates; otherwise, fetch-and-merge then PUT.
  • Output:
    {
      "person": "Person"
    }

6.2.6 gramps_delete_person

  • Purpose: Delete a person by handle.
  • HTTP: DELETE /people/{handle}[web:10]
  • Input:
    {
      "handle": "string"
    }
  • Output:
    {
      "success": "boolean",
      "message": "string"
    }

6.3 Families

6.3.1 gramps_list_families

  • Purpose: List family units with pagination.
  • HTTP: GET /families[web:10][web:19]
  • Input:
    {
      "limit": "number | null",
      "offset": "number | null"
    }
  • Output:
    {
      "total": "number",
      "items": ["Family"]
    }

6.3.2 gramps_get_family

  • Purpose: Fetch family by handle or Gramps ID.
  • HTTP: GET /families/{handle} or GET /families?gramps_id=...[web:10]
  • Input:
    {
      "handle": "string | null",
      "gramps_id": "string | null"
    }
  • Output:
    {
      "family": "Family"
    }

6.3.3 gramps_create_family

  • Purpose: Create a new family unit linking spouses and children.
  • HTTP: POST /families[web:10]
  • Input:
    {
      "parent_handles": ["string"],
      "child_handles": ["string"],
      "marriage_event": {
        "date": "string | null",
        "place_handle": "string | null"
      }
    }
  • Output:
    {
      "family": "Family"
    }

6.3.4 gramps_update_family

  • Purpose: Add/remove children or change parents for an existing family.
  • HTTP: PATCH /families/{handle}[web:10]
  • Input:
    {
      "handle": "string",
      "parent_handles": ["string | null"],
      "child_handles": ["string | null"],
      "marriage_event_handle": "string | null"
    }
  • Output:
    {
      "family": "Family"
    }

6.4 Events

6.4.1 gramps_list_events

  • Purpose: Paginated list of events.
  • HTTP: GET /events[web:10][web:19]
  • Input:
    {
      "type": "string | null",
      "limit": "number | null",
      "offset": "number | null"
    }
  • Output:
    {
      "total": "number",
      "items": ["Event"]
    }

6.4.2 gramps_get_event

  • Purpose: Fetch event by handle or Gramps ID.
  • HTTP: GET /events/{handle} or GET /events?gramps_id=...[web:10]
  • Input:
    {
      "handle": "string | null",
      "gramps_id": "string | null"
    }
  • Output:
    {
      "event": "Event"
    }

6.4.3 gramps_create_event

  • Purpose: Create a new event (birth, death, marriage, etc.).
  • HTTP: POST /events[web:10]
  • Input:
    {
      "type": "string",
      "date": "string | null",
      "place_handle": "string | null",
      "description": "string | null",
      "tags": ["string"]
    }
  • Output:
    {
      "event": "Event"
    }

6.5 Places

6.5.1 gramps_list_places

  • Purpose: Paginated list of places.
  • HTTP: GET /places[web:10]
  • Input:
    {
      "query": "string | null",
      "limit": "number | null",
      "offset": "number | null"
    }
  • Output:
    {
      "total": "number",
      "items": ["Place"]
    }

6.5.2 gramps_get_place

  • Purpose: Fetch place by handle or Gramps ID.
  • HTTP: GET /places/{handle} or GET /places?gramps_id=...[web:10]
  • Input:
    {
      "handle": "string | null",
      "gramps_id": "string | null"
    }
  • Output:
    {
      "place": "Place"
    }

6.5.3 gramps_create_place

  • Purpose: Create a new place record.
  • HTTP: POST /places[web:10]
  • Input:
    {
      "title": "string",
      "latitude": "number | null",
      "longitude": "number | null",
      "code": "string | null",
      "place_type": "string | null",
      "tags": ["string"]
    }
  • Output:
    {
      "place": "Place"
    }

6.6 Tree Navigation Helpers

These tools are composed operations that the MCP server performs by calling multiple underlying HTTP endpoints.

6.6.1 gramps_get_person_with_family

  • Purpose: Given a person handle, fetch the person and all their immediate family records.
  • HTTP:
    • GET /people/{handle}
    • GET /families/{handle} for each family.[web:10]
  • Input:
    {
      "handle": "string"
    }
  • Output:
    {
      "person": "Person",
      "families_as_child": ["Family"],
      "families_as_spouse": ["Family"]
    }

6.6.2 gramps_get_ancestors

  • Purpose: Fetch ancestors up to max_generations depth.
  • HTTP:
    • Repeated GET /people/{handle} and GET /families/{handle} to walk parents.[web:10][web:17]
  • Input:
    {
      "handle": "string",
      "max_generations": "number"
    }
  • Output:
    {
      "root_handle": "string",
      "generations": [
        {
          "generation_index": "number",
          "person_handles": ["string"]
        }
      ],
      "people": {
        "<handle>": "Person"
      },
      "families": {
        "<handle>": "Family"
      }
    }

6.6.3 gramps_get_descendants

  • Purpose: Fetch descendants up to max_generations.
  • HTTP:
    • Similar to ancestors, but walking children via family links.[web:10][web:17]
  • Input:
    {
      "handle": "string",
      "max_generations": "number"
    }
  • Output:
    {
      "root_handle": "string",
      "generations": [
        {
          "generation_index": "number",
          "person_handles": ["string"]
        }
      ],
      "people": {
        "<handle>": "Person"
      },
      "families": {
        "<handle>": "Family"
      }
    }

7. Security and Permissions

  • All outgoing HTTP requests must attach Authorization header if GRAMPS_WEB_API_TOKEN is set.
  • The MCP server must never log full tokens or API responses in plaintext logs.
  • Optionally support a read_only mode:
    • When GRAMPS_WEB_READ_ONLY env is true, disable all mutation tools:
      • gramps_create_*, gramps_update_*, gramps_delete_person, etc.

8. Implementation Notes

  • Language: TypeScript or Python recommended.
  • HTTP client: must support:
    • Configurable timeout.
    • TLS verification toggles.
    • JSON encoding/decoding with robust error paths.
  • The MCP manifest will describe:
    • Each tool name and JSON schema for arguments/results.
    • A clear description string matching the purpose described above.

This spec should be sufficient to implement a first version of the Gramps Web MCP server and keep the mapping to the GitHub-hosted Gramps Web HTTP API explicit and maintainable.[web:8][web:10][web:12]