
# Server Mode

With [`MCP_ENABLED=true`](/en/docs/mcp-integration), Sovrium generates an MCP tool set from your configuration. Nothing is exposed by default: an entity appears only when its schema declares `aiAccess`, and only in the shape the connecting role is allowed to see.

## Exposed Surfaces

Four kinds of thing become tools.

| Surface            | Tool name                         | What it does                                                |
| ------------------ | --------------------------------- | ----------------------------------------------------------- |
| User tables        | `{app}_{table}_{op}`              | Read, list, create, update, delete records.                 |
| Manual automations | `{app}_automation_{name}`         | Invoke an automation with a manual trigger.                 |
| Action templates   | `{app}_action_{name}`             | Execute one action template.                                |
| Admin internals    | `{app}_auth_*` / `{app}_system_*` | Read-only views of auth and system tables, admin role only. |

`tools/list` is filtered per connection, so a `viewer` credential is never even told that a delete tool exists. Only manual-trigger automations qualify — a cron or record-change automation has no caller to expose.

## Declaring Eligibility

`aiAccess` is the schema author's declaration of intent. It is deliberately separate from `MCP_ENABLED`: writing it does not expose anything, and the operator's switch does not expose anything you did not write.

```yaml
tables:
  - name: contacts
    aiAccess: true
```

That boolean is the common case — expose the table with defaults. The object form takes over when defaults are not right, and **supplying any object is itself the enable signal**; there is no `enabled` field to set.

```yaml
tables:
  - name: contacts
    aiAccess:
      description: Customer contacts. Use this when the user asks about people.
      operations: [read, list, create, update]
      fieldExposure: permissioned
      annotations:
        readOnly: false
        destructive: false
```

| Property              | Meaning                                                                             |
| --------------------- | ----------------------------------------------------------------------------------- |
| `description`         | The tool description the model reads. Up to 2000 characters.                        |
| `operations`          | Subset of `read`, `list`, `create`, `update`, `delete`. Tables default to all five. |
| `fieldExposure`       | `permissioned` (default), `all`, or `whitelist`.                                    |
| `whitelistFields`     | Which fields, when `fieldExposure: whitelist`. Required and non-empty in that mode. |
| `annotations`         | Risk hints — see below.                                                             |
| `requireConfirmation` | Force the destructive hint regardless of operation type.                            |

Automations and action templates accept the same block but ignore `operations`: each exposes a single invocation tool.

:::callout
**`description` is the highest-leverage field on this page.** The model chooses tools by reading them. "Customer contacts. Use this when the user asks about people" produces materially better behaviour than an auto-generated "Read from contacts", because it says _when_ to reach for the tool rather than only what it touches. Spend your effort here before tuning anything else.
:::

### Field Exposure

| Mode           | Fields in the tool schema                                     |
| -------------- | ------------------------------------------------------------- |
| `permissioned` | Only what the connecting role may read or write. The default. |
| `all`          | Every field, still subject to field-level RBAC at call time.  |
| `whitelist`    | Only the names in `whitelistFields`.                          |

`permissioned` is right almost always: it means a `viewer` and an `admin` connecting to the same table see different tool schemas, without you maintaining two declarations. Reach for `whitelist` when a table holds columns that are readable by the role but simply not the AI's business.

## Tool Risk Annotations

Annotations compile into the MCP tool definition so a client can decide whether to run a call silently or ask its user first. They map one-to-one onto the protocol's hints:

| Annotation    | MCP hint          | Says                                                  |
| ------------- | ----------------- | ----------------------------------------------------- |
| `readOnly`    | `readOnlyHint`    | Reads only — safe to auto-approve.                    |
| `destructive` | `destructiveHint` | Destroys or sends something — ask first.              |
| `idempotent`  | `idempotentHint`  | Calling twice is safe; no duplicate side effects.     |
| `openWorld`   | `openWorldHint`   | Reaches outside the app — external API, network call. |

Left unset, sensible values are derived from the operation type, and `MCP_CONFIRM_DESTRUCTIVE` (on by default) additionally marks delete tools and non-idempotent automations as destructive.

The case worth setting by hand is the automation that is technically idempotent but practically irreversible — sending an email, charging a card. `requireConfirmation: true` forces the destructive hint on those regardless of what the operation type would imply.

## Related Pages

- [MCP Overview](/en/docs/mcp-integration) — enabling the server.
- [Connecting a Client](/en/docs/mcp-clients) — pointing an assistant at it.
- [Auth, RBAC & Rate Limiting](/en/docs/mcp-security) — the enforcement behind the filtering.
- [Tables Overview](/en/docs/tables-overview) — where `aiAccess` sits on a table.
- [Actions](/en/docs/automation-actions-overview) — action templates as tools.
