Local single-user directory MCP: people, projects and artifacts and their cross-platform references (Slack / Jira / GitLab / GitHub / Outlook / … — open vocab).
Strong semantic design with clear, action-oriented tool names and comprehensive descriptions. All 13 tools have explicit descriptions (avg ~180 chars) and input schemas with typed parameters. Output schemas are documented via code examples. However, several tools lack enum constraints for open-vocab fields (system, ref_type, kind), and error handling guidance is minimal. Parameter descriptions are generally good but some lack format/constraint details. No tool annotations (readOnlyHint/destructiveHint) despite clear risk stratification (8 WRITE, 5 READ_ONLY).
Search the directory by name. Optionally narrow by kind (person/project/…).
Attach an external coordinate (anchor) to an entity — a Slack id, Jira key, repo, URL.
Record a fact about an entity. Set key for a semi-structured attribute (e.g. key='status').
Capture a reference: an artifact (email/ticket/doc/thread) and the people involved in it. Idempotent — safe to call every time you read something. Attach the artifact via `artifact_links` and list the people via `people` (name or email). The artifact becomes a node in the graph; each person is linked to it via a `mentions` edge.
Link two entities, e.g. relate("me", "reports_to", "Grace") or ("Ada", "works_on", "Checkout").
Record an external organization (client/vendor) as an entity for grouping its people. Find-or-create by name (e.g. "Globex", "Initech", "Hooli").
Open-vocab fields (system, ref_type, kind, relation type) lack enum constraints. LLMs will hallucinate invalid values instead of consulting vocab tool. Should declare enums or provide strict validation with recovery guidance.
No tool annotations (readOnlyHint/destructiveHint/idempotentHint) despite clear risk stratification: 8 WRITE tools (remember_*, relate, link, note, set_self, record_reference) vs 5 READ_ONLY. Agents cannot distinguish safe from destructive calls without reading descriptions.
Error handling lacks recovery guidance. No tool documents what to do if a lookup fails, a duplicate is detected, or a constraint is violated. E.g., remember_person says 'reuses existing' but doesn't explain what happens if email matches multiple records or if the user should call whois first.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | 2026-07-28+ | v2 |
Record a person. Reuses an existing one that shares the email rather than duplicating. `email` is the identity key (re-recording the same address updates, never duplicates). Attach every other coordinate via `links` as `{"system","ref_type","value"}` — e.g. `{"system":"slack","ref_type":"user","value":"U123"}`, github, jira, notion, anything.
Record a project with however many coordinates it spans. Attach each coordinate via `links` as `{"system","ref_type","value"}` — e.g. a Jira project key `{"system":"jira","ref_type":"project_key","value":"VX"}`, a Slack channel, a repo, a Notion page, anything. No system is privileged.
Record an internal team/department as an entity, so people can be `member_of` it. Find-or-create by name (e.g. "Platform", "QA", "IT", "Support").
Mark an entity as 'me' — the user running this MCP. Only one entity can be self at a time.
Canonical vocabulary and what is already in use: `kind` / `system` / `ref_type` / relation `type`. Before inventing a new value, call this to see the suggestions and what is already in the directory.
The external coordinates for someone, grouped by system — what to feed the other MCPs.
Resolve a person/project by name, email, or a self-relative phrase like "my boss". Returns who they are, their contacts grouped by system (Slack/Jira/email/…), their relationships and recorded facts. This is how you learn where to look for someone. When the query is ambiguous (e.g. two similarly-named projects you both work on), `ambiguous` is true and `alternatives` lists the other plausible matches — the top result is only a best-guess ordering, so YOU should decide between them (ask the user or use other context) rather than trusting the first one.
LinkInput TypedDict uses NotRequired for optional fields but schema generation may not expose this clearly to LLMs. Parameter descriptions for 'links' array items lack detail on required vs optional sub-fields (label is optional, others required).
Output schema for who_to_query is truncated in source (ends mid-line). Cannot verify full response structure. Assume incomplete documentation.