Skip to main content
The Tools Reference is generated from the live server and lists every tool’s parameters. This page is the hand-written companion: the conventions the reference doesn’t repeat 103 times.

Result shape

Every tool returns the standard MCP content envelope with a single text part containing pretty-printed JSON:
A few tools return a bare string rather than JSON — ping is one. The memory tools (morphic_recall, morphic_attachment_recall, morphic_remember) return JSON on success; older integrations that parsed their bare-string output need updating.

Error envelope

Every tool converges on one machine-readable error shape. Branch on error_code; if your agent simply relays user_message verbatim, the wording is already correct and product-voiced.
Failures return isError: true and a JSON body:

Error codes

Backend prose never reaches the model: HTTP {status}: {detail} strings, component names, tenant ids and stack traces are sanitised at a single boundary. Full diagnostics still go to the server’s stderr for operators.
Wiki tools previously returned failures without isError, which made a failed write look like a success. They now use the envelope above. If you special-cased wiki responses, remove that code.

Choosing a workspace per call

Every tool takes an optional workspace argument: a workspace slug, on any call. It only matters when a connection was approved for more than one workspace. Then the server cannot guess which one a request means, and answers workspace_selection_required until one is named. Set workspace and the call proceeds:
Call list_workspaces for the slugs this connection may use. Omit the argument to use whatever the connection already resolves to — a sole approved workspace, or the ?workspace= on the connect URL.
The argument is a request, not a decision. The server re-checks it against what you approved on the consent screen and your live membership on every call, so a workspace outside the grant is refused no matter what a client sends.

Object-type slugs are plural

Morphic’s default object types are people, companies, deals — not person/company/deal. Anywhere a tool takes object_type_slug or entity_type, use the plural form. Workspaces can define custom object types, so never hard-code the list. Call list_entity_types for the real slugs, then get_entity_type_schema for a type’s field slugs before writing to it.

Task statuses are workspace-configured

create_activity.status and update_activity.status take a workspace task-status slug, not a fixed enum. Call list_task_statuses to get this workspace’s exact slugs.
There is no pending status. Older documentation listed it; it was never valid. Common real slugs are not_started, in_progress, completed, cancelled — but confirm with list_task_statuses.
activity_type and priority are fixed enums, and are enforced at the schema level:
  • activity_type: task · email · call · meeting · note · stage_change
  • priority: low · medium · high

create_activity vs create_note

Both attach text to a record; they land in different places.
  • create_activity(activity_type="note", …) → a timeline note, ordered chronologically alongside calls, emails and meetings.
  • create_note(…) → a standalone, editable, pinnable note in the record’s notes panel.
Note bodies are stored exactly as sent. Pass real newlines — the server no longer rewrites literal \n sequences into line breaks, so an escaped string arrives escaped.

Bulk tools

Every bulk_* tool takes an array of up to 200 ids and applies the same change to all of them. For per-record different values, loop the single-record tool instead. Bulk calls return per-id success/failure, so one bad id does not abort the batch. Always inspect the per-id results rather than assuming a 200 means everything applied. Bulk tools available: bulk_update_entities, bulk_archive_entities, bulk_delete_entities, bulk_link_entities, bulk_unlink_entities, bulk_create_activities, bulk_update_activities, bulk_archive_activities, bulk_delete_activities, bulk_create_notes, bulk_delete_notes.

Linking and unlinking records

link_entities and unlink_entities take the same three arguments — the relation is addressed by attribute slug, not by a relation id:
Older documentation said unlink_entities takes entity_id + relation_id. It does not, and never has in the shipped server — that call fails schema validation. There is no need to save a relation_id from link_entities.
The attribute slug is resolved to its internal UUID for you. Resolution costs two extra backend calls and the cache is per-request, so a tight loop of links is noticeably slower than bulk_link_entities.

Answering a question: start with Context

For any question about this workspace — a named record of any object type, or what people have said or done (Slack, email, meetings, chat, “did anyone mention X”) — call ask_context before any search tool. Pass the user’s question verbatim; do not pre-extract names or look up an id first. You do have conversation history; it reaches you through this tool, not through Slack’s or Gmail’s own APIs. Never tell the user you cannot search past messages. If contexts is empty, semantic is still a complete answer — Slack-only workspaces do not auto-create CRM records. Empty semantic too means nothing is indexed yet. ask_context returns these keys: It never errors on a question it cannot resolve — an unmatched question still returns semantic and next_steps. Only then reach for the deeper layers, and only for the reason next_steps gives:
  • get_entity / get_entity_with_relations — you need a record’s raw field values.
  • list_activities — you need the chronological timeline itself.
  • search_entities / list_entitiesresolved was empty or wrong, or you want a ranked list rather than one record’s story.
  • morphic_recall — the question is about durable cross-session memory, not a record.
If you already hold a record id, get_context is the entity-scoped form of the same call. The same layers are available over REST: POST /api/gold/context/ask (body: question, optional max_entities, include_graph) and GET /api/gold/{entity_id}/context.

Finding records

search_entities is semantic (vector) search. When nothing matches it returns an explicitly empty result rather than an error:
list_entities is the deterministic counterpart and does far more than paginate. Beyond object_type_slug, search, is_archived, page and page_size it accepts:
  • entity_ids — hydrate a specific set of records in one call.
  • sort_by — a sort expression, e.g. created_at:desc or deal_value:asc.
  • filters — field-level conditions keyed by attribute slug, e.g.
    The 19 operators are is, equals, is_not, not_equals, contains, not_contains, starts_with, ends_with, greater_than, less_than, greater_than_or_equal, less_than_or_equal, after, before, between, is_empty, empty, not_empty, is_not_empty. Omit value for the emptiness operators; pass value2 with between.
Call get_entity_type_schema first so your slugs and operators match the attribute types.

Knowledge base list results are lossy

list_kb_documents deliberately shrinks its payload: each item’s content_markdown is truncated to a ~160-character excerpt and the BlockNote content field is removed entirely. Use it to discover what exists; call get_kb_document for a real body. fetch_all=true flattens every folder level. page / page_size are still sent alongside it and their interaction with fetch_all is backend-defined — prefer one or the other, not both.

Automations

author_workflow is the only way to build automation logic. No tool exposes raw React Flow graph JSON: authoring is delegated to the same LLM-backed builder the Morphic UI uses, from a natural-language description. Two current engine limits to plan around:
  • Linear only. Condition and branch nodes are not evaluated by the execution engine yet.
  • No retries. A failed step aborts the entire run.
Typical sequence: create_workflow (draft metadata) → author_workflow (trigger + steps) → publish_workflow (go live) → enqueue_workflow_manual_run (run it now, for real) → list_workflow_runs / get_workflow_run (inspect).

Optional request headers

Where to go next