Docs

Contacts

What it does

Contacts keep the people you work with on the company they belong to, so a name in a meeting can become a real record only after you accept it.

Open Contacts (/contacts). The list and the drawer are a thin client over the session API. A signed-in person can create a contact. An agent proposes one with approval_create and waits. A single first name with no email and no account is not a confirmed person. Allowed fields are in Entity fields. Send full_name, not name.

contact_intake is the direct write for an intake payload that already has an email and a company. It is not a shortcut around a fuzzy name.

MCP tools

ToolScopeRole
approval_createapprovals:writePropose a person. table contacts, type graph_entity_create
contact_intakecontacts:write, accounts:writeCreate a contact and account from an intake payload that includes email
entity_field_writegraph:writeWrite one field through provenance
entity_getnone (token still required)Full card by search-entity id
entity_state_getnone (token still required)Read agent_state
entity_state_setcontacts:writeReplace agent_state
entity_state_patchcontacts:writeShallow-merge agent_state
entity_note_addnotes:writeAppend a note
entity_notes_listnotes:readRecent notes
scorecard_getcontacts:readLatest scorecard when record_table is contacts
mention_addmentions:write, activities:writeLink an activity to this person

Do not call MCP entity_create. It returns deprecated and writes nothing.

HTTP endpoints

MethodPathRole
GET/cockpit/api/contactsList
POST/cockpit/api/entities/contactsCreate from a signed-in session. Provenance source is human
GET, PATCH, DELETE/cockpit/api/entities/contacts/:idDrawer read, update, delete
POST/cockpit/api/entities/contacts/:id/mergeMerge into the keeper

A duplicate email on create returns a conflict and names the contact that already holds it. The second row is not inserted.

Permissions

Token scopes come from one permission-set layer. Reads need contacts:read. Intake needs both contacts:write and accounts:write. Proposals need approvals:write.

Row access is RLS by creator. Admins see all rows. Members see their own.

Agent example

Call approval_create for a person you are not ready to treat as confirmed.

{
  "tool": "approval_create",
  "arguments": {
    "item_type": "graph_entity_create",
    "title": "Create contact: Jane Example",
    "table": "contacts",
    "fields": {
      "full_name": "Jane Example",
      "title": "VP Operations",
      "lifecycle_stage": "lead"
    }
  }
}

Expected result: a pending card. No contact row until a person approves it. lifecycle_stage prospect is stored as lead.

{
  "status": "pending",
  "item_type": "graph_entity_create",
  "title": "Create contact: Jane Example"
}