# MCP tools

> The complete tool surface available in Orbit 0.4.

## Endpoint and transport

Orbit exposes `POST /mcp/orbit` through the official Laravel MCP package. Use an MCP client to negotiate the protocol and send tool calls. All calls require an active bearer token. Protocol `tools/list` is cursor-paginated (15 tools per page by default); follow `nextCursor` until absent. There are 43 contributor tools and 17 reader tools. This is separate from record-search page-number pagination.

| Tool | Reader | Contributor | Effect |
| --- | --- | --- | --- |
| `workspace_context` | Yes | Yes | Read workspace, capabilities, and supported statuses. |
| `contacts_search` | Yes | Yes | Find or filter contacts. |
| `contacts_get` | Yes | Yes | Retrieve one contact. |
| `contacts_create` | No | Yes | Create a contact. |
| `contacts_update` | No | Yes | Patch a contact with a revision check. |
| `contacts_archive` | No | Yes | Archive a contact while retaining history. |
| `contacts_restore` | No | Yes | Restore an archived contact. |
| `contacts_brief` | Yes | Yes | Read bounded contact context and sources. |
| `organisations_search` | Yes | Yes | Find or filter organisations. |
| `organisations_get` | Yes | Yes | Retrieve one organisation. |
| `organisations_create` | No | Yes | Create an organisation. |
| `organisations_update` | No | Yes | Patch an organisation with a revision check. |
| `organisations_archive` | No | Yes | Archive an organisation while retaining history. |
| `organisations_restore` | No | Yes | Restore an archived organisation. |
| `projects_search` | Yes | Yes | Find or filter projects. |
| `projects_get` | Yes | Yes | Retrieve one project. |
| `projects_create` | No | Yes | Create a project. |
| `projects_update` | No | Yes | Patch a project with a revision check. |
| `projects_archive` | No | Yes | Archive a project while retaining history. |
| `projects_restore` | No | Yes | Restore an archived project. |
| `projects_brief` | Yes | Yes | Read bounded project context and sources. |
| `tasks_search` | Yes | Yes | Find or filter tasks. |
| `tasks_get` | Yes | Yes | Retrieve one task. |
| `tasks_create` | No | Yes | Create a task. |
| `tasks_update` | No | Yes | Patch a task with a revision check. |
| `tasks_archive` | No | Yes | Archive a task while retaining history. |
| `tasks_restore` | No | Yes | Restore an archived task. |
| `tasks_claim` | No | Yes | Atomically claim open or expired work. |
| `tasks_claim_renew` | No | Yes | Renew your unexpired claim. |
| `tasks_claim_release` | No | Yes | Release your claim with a status and reason. |
| `tasks_complete` | No | Yes | Complete claimed work with a linked outcome. |
| `tasks_attempts` | Yes | Yes | Read paginated claim attempt history. |
| `affiliations_list` | Yes | Yes | List contact–organisation affiliation records. |
| `affiliations_set` | No | Yes | Create, edit, or restore a contact–organisation affiliation. |
| `affiliations_remove` | No | Yes | Archive a contact–organisation affiliation. |
| `participants_list` | Yes | Yes | List project participant records. |
| `participants_set` | No | Yes | Create, edit, or restore a project participant. |
| `participants_remove` | No | Yes | Archive a project participant. |
| `activity_append` | No | Yes | Append one sourced activity with record links. |
| `activity_list` | Yes | Yes | Read activity attached to a record. |
| `activity_link` | No | Yes | Attach an existing activity to more records. |
| `tags_list` | Yes | Yes | Discover reusable workspace labels. |
| `fields_list` | Yes | Yes | Discover field keys, types, and entity scope. |

## workspace_context

**Arguments:** none.

Returns the authenticated workspace, agent identity and role, implemented capabilities, limits, and usage conventions. It never returns credential hashes or secrets.

```json
{}
```

## contacts_search

All arguments are optional. With no query, the tool lists accessible contacts.

```json
{
  "query": "maya@example.com",
  "tag": "collaborator",
  "include_archived": false,
  "page": 1,
  "per_page": 20
}
```

Use `query` for a name/ID substring, exact email, or formatting-normalised phone. Explicit `name`, `email`, `phone`, `tag`, `organisation_id`, `project_id`, and scalar `custom_fields` equality filters combine with AND. See [Contacts](/docs/contacts) for country-prefix handling and ambiguity.

`page` ranges from 1 to 10,000; `per_page` ranges from 1 to 50. Defaults are 1 and 20. The result contains `contacts`, `page`, `per_page`, `has_more`, and `next_page`. Page boundaries may shift if records change between calls.

## contacts_get

Supply a contact UUID and optionally request archived records.

```json
{
  "id": "01900000-0000-7000-8000-000000000001",
  "include_archived": false
}
```

Returns a `contact` object with its ID, revision, stored fields, actor IDs, and UTC timestamps. Unknown and inaccessible IDs return the same `not_found` error.

## contacts_create

Requires a contributor, `display_name`, and `idempotency_key`. See [Contacts](/docs/contacts) for optional fields and duplicate handling.

```json
{
  "display_name": "Maya Chen",
  "idempotency_key": "contact-maya-001"
}
```

Returns `contact` and `replayed`. A successful first creation has revision `1` and `replayed: false`. An identical retry has `replayed: true` and the original contact snapshot.

## contacts_update

Requires `id`, `expected_revision`, `idempotency_key`, and a nonempty `changes` object or `remove_custom_fields` list. Returns `contact` and `replayed`. Updates reject stale revisions, unsupported fields, and edits to archived records. Arrays replace; omitted fields persist; optional text accepts null. Custom-field keys are patched.

```json
{
  "id": "01900000-0000-7000-8000-000000000001",
  "expected_revision": 1,
  "idempotency_key": "contact-update-001",
  "changes": {"tags": ["collaborator"], "description": null}
}
```

## contacts_archive and contacts_restore

Both take the same argument shape and return `contact` and `replayed`:

```json
{
  "id": "01900000-0000-7000-8000-000000000001",
  "expected_revision": 2,
  "idempotency_key": "contact-archive-001"
}
```

Use the latest revision and a new operation key when restoring. Retrying the identical request replays the original snapshot, even after another mutation. A new request that leaves the state unchanged does not increment the revision or create an audit event.

## tags_list and fields_list

Both accept optional `query`, `page` (1–10,000), and `per_page` (1–50; default 20). `query` is a case-insensitive literal substring of the tag name or field key.

`tags_list` returns `tags`, `page`, `per_page`, `has_more`, and `next_page`. Tags are created when applied to contacts, organisations, or projects; removing an assignment does not delete its registry entry.

`fields_list` returns `field_definitions` with key, type, description, and applicable entity, plus the same pagination fields. Definitions are workspace-scoped and CLI-managed. `fields_list` additionally accepts `entity`: `contact`, `organisation`, `project`, or `task`. See [Tags](/docs/tags) and [Custom fields](/docs/custom-fields).

## Organisation, project, and task records

Each record family exposes `*_search`, `*_get`, `*_create`, `*_update`, `*_archive`, and `*_restore`. Responses use `organisation`, `project`, or `task` for one record, and the plural for search results. Mutations add `replayed`; searches add `page`, `per_page`, `has_more`, and `next_page`.

- Create requires `name` (organisation/project) or `title` (task), plus `idempotency_key`.
- Get requires `id`; `include_archived` is optional.
- Update requires `id`, `expected_revision`, `idempotency_key`, and `changes` or `remove_custom_fields`.
- Archive/restore require `id`, `expected_revision`, and `idempotency_key`.
- Search accepts optional `query`, scalar `custom_fields`, `include_archived`, `page`, and `per_page`. Other filters are entity-specific.

Names/titles are limited to 255 characters, descriptions to 10,000, and arrays use the same limits as contacts. Arrays replace; omitted values persist; optional values accept null; custom fields patch by key. Actual changes increment revisions; no-ops do not. Creates for organisations and projects warn on possible duplicates and accept an explicit `allow_duplicate` after review. Tasks are distinguished by ID and operation key rather than title uniqueness.

See [Organisations](/docs/organisations), [Projects](/docs/projects), and [Tasks](/docs/tasks) for fields, filters, statuses, and examples.

## Task lifecycle tools

`tasks_claim`, `tasks_claim_renew`, `tasks_claim_release`, and `tasks_complete` require `id`, `expected_revision`, and `idempotency_key`. All except claim also require `claim_id`.

- Claim/renew accept `lease_seconds` (60–3,600; default 900).
- Release requires `status` (`open`, `blocked`, `cancelled`) and `reason` (1–2,000 characters).
- Complete requires `outcome_id`, identifying a non-redacted, linked `task_outcome` activity.

Each mutation returns `task`, `replayed`, and freshly checked `current_claim_valid`. The task snapshot may be historical on replay. `tasks_attempts` takes `id`, optional `include_archived`, `page`, and `per_page` and returns attempt history with pagination. See [Tasks](/docs/tasks) for examples, expiry, interrupted work, and safe handoffs.

## Sorting search results

Primary-record searches accept `sort` and `direction` (`asc` or `desc`, default `asc`). Allowed fields are:

| Search | Sort fields (first is default) |
| --- | --- |
| Contacts | `display_name`, `created_at`, `updated_at` |
| Organisations | `name`, `created_at`, `updated_at` |
| Projects | `name`, `target_date`, `created_at`, `updated_at` |
| Tasks | `title`, `due_at`, `created_at`, `updated_at` |

ID ascending breaks ties; nullable dates sort last in both directions. Other list tools retain their documented fixed ordering. Arbitrary field names and SQL expressions are rejected.

## Relationship tools

`affiliations_set` and `participants_set` create, edit, or restore relationships. Creation supplies endpoint IDs and a role; editing/restoring supplies the relationship `id` and `expected_revision`, without endpoint IDs. Every write requires `idempotency_key`.

`affiliations_remove` and `participants_remove` archive a relationship using `id`, `expected_revision`, and `idempotency_key`. Results contain `affiliation` or `participant`, plus `replayed`.

`affiliations_list` requires `contact_id`; `participants_list` requires `project_id`. Both accept archive and pagination options. Results contain `affiliations` or `participants` plus pagination. See [Relationships](/docs/relationships) for the exact creation and patch fields.

## Activity tools

`activity_append` requires `type`, `body`, `occurred_at`, `links`, and `idempotency_key`. Optional fields are `title`, `external_references`, and `corrects_id`.

`activity_link` requires an existing activity `id`, additional `links`, and `idempotency_key`. It only adds links. Both writes return `activity` and `replayed`.

`activity_list` requires `record_type` and `record_id`, with optional `query`, `type`, archive, and pagination filters. It returns `activities` with source references and links, plus pagination. See [Activity](/docs/activity) for limits and append-only correction semantics.

## Structured briefs

`contacts_brief` and `projects_brief` require `id`. Optional arguments are `per_section` (1–20; default 5), `activity_page`, `task_page`, `relationship_page` (1–10,000; default 1), and `include_archived`.

Results contain the named record, `activity`, `tasks`, `relationships`, and `conventions`. Each section contains its own results and pagination metadata. Tasks are directly linked outstanding tasks; relationships are affiliations for contacts and participants for projects. Entries retain source references. No prose generation or transitive graph traversal occurs.

## Limits and errors

Requests are limited to **64 KiB**, and each agent can make **120 requests per minute**. A separate 240-per-minute IP limit also applies. Search returns at most 50 records per page.

Transport failures use HTTP statuses such as 401, 403, 413, and 429. Tool validation errors use MCP’s error result and an actionable message. Unsupported fields are rejected. Capture `X-Request-ID` when investigating a failed request.

There is no permanent-delete tool or agent-driven field-definition editing. Claim lifecycle mutations enforce owner and expiry checks. `claim_unavailable` means an active reservation exists; `claim_invalid` means the caller does not hold the supplied unexpired claim; `claim_required` means an in-progress task must be released before ordinary editing; `invalid_outcome` requires a non-redacted, linked task outcome. A `revision_conflict` requires reviewing current data, not blindly resubmitting a larger revision number.
