MCP tools
All 13 tools the Personify MCP server exposes — signatures, parameters, examples.
The Personify MCP server exposes 13 read-only tools. They cluster into four groups:
- Search —
search,semantic_search - Browse —
timeline,get_item,recent_items,recent_runs - Catalog —
list_sources,list_accounts,stats - Graph —
graph_search_entities,get_entity,entity_neighborhood,entity_context
All tools return JSON. All tools are safe to call repeatedly — there are no side effects.
search
Postgres full-text search across item_text.body. Returns the most relevant items as {id, source, kind, ts, title, snippet, score}. Best for keyword and phrase queries.
Signature
search(query: str, limit: int = 25, source: str | None = None) -> list[hit]Parameters
| Name | Type | Default | Description |
|---|---|---|---|
query | string | required | Search expression. |
limit | int | 25 | Max hits returned. |
source | string | null | Restrict to a source slug. |
Example
$ search(query="rust borrow checker", limit=3)[{"id": 4127, "source": "github", "kind": "code","ts": "2025-11-04T12:14:00Z", "title": "src/borrow.rs","snippet": "fn check_borrow(...)", "score": 0.41}, ...]
semantic_search
pgvector cosine similarity over embedded chunks. Best for "find items semantically similar to this idea" rather than exact matches. Requires the optional embeddings extra and a vault embed pass.
Signature
semantic_search(query: str, limit: int = 25, source: str | None = None) -> list[hit]Parameters
| Name | Type | Default | Description |
|---|---|---|---|
query | string | required | Natural-language query — embedded with the same model used for items. |
limit | int | 25 | Max hits returned. |
source | string | null | Restrict to a source slug. |
Example
$ semantic_search(query="library metaphor for ownership")[{"id": 7710, "source": "chatgpt", "kind": "message","ts": "2025-09-12T22:01:00Z","title": "Rust ownership analogies", "score": 0.81}, ...]
timeline
Items with non-null timestamps in a date range, most recent first.
Signature
timeline(start: str | None = None,
end: str | None = None,
source: str | None = None,
limit: int = 200) -> list[item]Parameters
| Name | Type | Default | Description |
|---|---|---|---|
start | ISO 8601 | null | Inclusive lower bound. |
end | ISO 8601 | null | Exclusive upper bound. |
source | string | null | Restrict to a source slug. |
limit | int | 200 | Max items returned. |
Example
$ timeline(start="2026-01-01", end="2026-02-01", source="gmail", limit=2)[{"id": 91201, "source": "gmail", "ts": "2026-01-29T16:42:00Z","title": "Re: Q1 plan"}, ...]
get_item
Retrieve a single item by id. The body is truncated to 4096 chars by default — pass include_body=True for the full text.
Signature
get_item(item_id: int, include_body: bool = False) -> itemParameters
| Name | Type | Default | Description |
|---|---|---|---|
item_id | int | required | Item id. |
include_body | bool | false | If true, return full untruncated body. |
Example
$ get_item(item_id=4127){"id": 4127, "source": "github", "ts": "2025-11-04T12:14:00Z","title": "src/borrow.rs", "body": "fn check_borrow(...) { ...[body truncated at 4096 chars]"}
recent_items
Paginated browse over items with stable ordering: ts DESC NULLS LAST, id DESC.
Signature
recent_items(source: str | None = None,
account: str | None = None,
kind: str | None = None,
limit: int = 50,
offset: int = 0) -> pageParameters
| Name | Type | Default | Description |
|---|---|---|---|
source | string | null | Filter by source slug. |
account | string | null | Filter by account handle. |
kind | string | null | Filter by item kind. |
limit | int | 50 | Page size. |
offset | int | 0 | Skip this many. |
Example
$ recent_items(source="discord", limit=2){"items": [{"id": 12, "kind": "message", ...}],"limit": 2, "offset": 0, "has_more": true}
recent_runs
Most recent ingestion runs with status, parser, and item counts.
Signature
recent_runs(limit: int = 10) -> list[run_summary]Parameters
| Name | Type | Default | Description |
|---|---|---|---|
limit | int | 10 | Max runs returned. |
Example
$ recent_runs(limit=2)[{"id": 14, "source": "github", "status": "completed","items_added": 8201, "started_at": "2026-05-03T09:11:00Z"}, ...]
list_sources
Active source registry — {slug, label, created_at} for every source with at least one ingested item.
Signature
list_sources() -> list[source]Example
$ list_sources()[{"slug": "gmail", "label": "Gmail", "created_at": "..."},{"slug": "github", "label": "GitHub", "created_at": "..."}, ...]
list_accounts
All account handles that have data ingested.
Signature
list_accounts() -> list[account]Example
$ list_accounts()[{"handle": "myname@example.com", "source": "gmail"},{"handle": "my-org", "source": "github"}, ...]
stats
Vault summary — item / export / run totals plus per-source and per-account breakdowns. Same data as the /stats HTTP endpoint and the vault://stats resource.
Signature
stats() -> vault_summaryExample
$ stats(){"items": 128402, "exports": 12, "runs": 14,"items_per_source": {"gmail": 82140},"items_per_account": {...}}
graph_search_entities
Find entities by name or alias substring. type is validated against the live entity-type registry — invalid types return an error rather than an empty list.
Signature
graph_search_entities(query: str,
type: str | None = None,
limit: int = 20) -> list[entity_summary]Parameters
| Name | Type | Default | Description |
|---|---|---|---|
query | string | required | Substring matched against canonical name and aliases. |
type | string | null | One of the 22 entity types (e.g. Project, Person). |
limit | int | 20 | Max entities returned. |
Example
$ graph_search_entities(query="personify", type="Project")[{"id": 81, "type": "Project", "name": "Personify","canonical_name": "personify", "origin": "extractor"}]
get_entity
Entity with aliases and item-backed evidence. Every entity in the graph is grounded in items — evidence lists the items the extractor saw.
Signature
get_entity(entity_id: int) -> entity_fullExample
$ get_entity(entity_id=81){"entity": {"id": 81, "type": "Project", "name": "Personify"},"aliases": [{"alias": "the vault"}], "evidence": [{"source_id": 4127, ...}]}
entity_neighborhood
Walk the graph outward from an entity. Depth is capped at 2 — depth-3 graphs explode quickly and aren't useful as LLM context.
Signature
entity_neighborhood(entity_id: int, depth: int = 1) -> graph_subgraphParameters
| Name | Type | Default | Description |
|---|---|---|---|
entity_id | int | required | Center of the walk. |
depth | int | 1 | 1 or 2. |
Example
$ entity_neighborhood(entity_id=81, depth=1){"nodes": [{"id": 81, ...}, {"id": 14, ...}],"edges": [{"source_id": 81, "target_id": 14, "type": "USES"}]}
entity_context
LLM-friendly grounding payload combining entity, neighborhood, evidence snippets, and suggested follow-up queries. Designed to be dropped straight into a prompt.
Signature
entity_context(entity_id: int) -> context_payloadExample
$ entity_context(entity_id=81){"entity": {...}, "neighborhood": {"nodes": [...], "edges": [...]},"evidence": [{"item_id": 4127, "snippet": "..."}],"suggested_queries": ["how does Personify ingest GitHub repos?"]}