Table of Contents

Tools

This page documents Orleans.Lattice.Api.Mcp 9.9.0, in the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at tools.md, and llms.txt lists every page.

The MCP server exposes its capabilities as tools, grouped into opt-in modules plus a lattice_capabilities and a lattice_list_regions meta-tool. Every tool is a thin adapter over the matching Orleans.Lattice.Api.* facade and is named lattice_<group>_<verb>. The server ships with no tools; each module is added explicitly.

Opting in

var services = new ServiceCollection();

services.AddLatticeMcp();
services.AddStateTools();
services.AddDataTools(enableWrites: true);
services.AddBackupTools(enableControl: true);
services.AddAuthTools(enableAdministration: true);
services.AddReplicationTools(enableControl: true);
services.AddTreeAdminTools(enableSchemaControl: true, enableLifecycle: true);

Each module registration is idempotent except AddDataTools, which is meant to be called once (a second call registers a second data tool group rather than replacing the first), and within a module the destructive verbs stay hidden unless the host opts them in:

Module Extension Read/inspect verbs Destructive verbs (opt-in flag)
State AddStateTools() always none (read-only facade)
Data AddDataTools(enableWrites) always writes, gated by enableWrites
Backup AddBackupTools(enableControl) always capture / incremental capture / restore / revert / delete, gated by enableControl
Auth AddAuthTools(enableAdministration) always group / membership / rule mutation, gated by enableAdministration
Replication AddReplicationTools(enableControl) always enable / disable replication, gated by enableControl
TreeAdmin AddTreeAdminTools(enableSchemaControl, enableLifecycle) always schema policy / version / remediation mutation, gated by enableSchemaControl; tree lifecycle, restore, bulk-load, WAL-move, orphaned-leaf repair, view, tag-index, compaction, and retention control, gated by enableLifecycle
Tenant self-awareness AddTenantSelfAwarenessTools() always (self-gates on tenancy) none (read-only facade)
Tenant-admin AddTenantAdminTools(enableControl) none (its one inspect tool, lattice_tenant_region_status, is contributed only with enableControl) tenant create / suspend / resume / delete / set-quotas and region authorize / set-residency, gated by enableControl

Read tools carry readOnlyHint = true; destructive tools carry destructiveHint = true and readOnlyHint = false, so a well-behaved MCP client can surface the distinction to the operator. Enabling a destructive verb only advertises it - it stays subject to the same fail-closed access gate the facade enforces (see Security).

Discovery

The lattice_capabilities meta-tool reports, for the authenticated caller, its resolved subject id, the connected cluster's cluster and service ids, and one entry per facade group saying whether the group is available - its tool module is registered on this server and the caller's effective permissions grant an operation the group covers - plus, on a remote head, the endpoint the group is served from. It reports groups, not individual tools; the session's tool list is the per-tool view. Discovery is permission-scoped: a group's tools are listed only to a caller holding an Allow grant for an operation the group covers (and only the tools the registered authorizer permits by name), so a caller never sees a group it holds no grant for. The scopeless Telemetry and AppInstall capabilities count only from a whole-tree grant written at cluster-wide scope (LatticeScope.ClusterWide()), so neither a tree-scoped rule carrying the Telemetry bit nor a key- or prefix-scoped rule on the cluster-wide tree id lists the telemetry group. The data group narrows the listing per tool: its mutating tools are listed only to a caller whose grants include a mutating data-plane operation (see the data tools below). Otherwise the filter is deliberately coarse - one grant lists the whole group - and the facade's access gate still authorizes every call per tree and per verb, so a listed tool can be refused for a tree, a verb, or a Deny rule the caller's grants do not cover. lattice_capabilities is offered to every authenticated caller and is the one tool the coarse authorizer does not gate; an unauthenticated session is offered no tools at all.

Installable app tools

A host that registers Orleans.Lattice.Api.Mcp.Apps (AddAppMcpTools()) also advertises every enabled installable app's tools on this endpoint. They are not named lattice_<group>_<verb>: each is namespaced by its app slug as {slug}_{tool}, for example crm_find_contact. They are added to an authenticated caller's session after the group tools, through the same per-session tool collection and the same coarse authorizer, and each is listed only to a caller that holds the tool's declared app role. A role is held by binding - the caller is a member of a group the install binds to that role - and the shared access gate can then only take it away, never confer it: the tool is withheld when, on each of the role's scopes, the gate refuses at least one of the role's operations, so an explicit deny on a bound member wins and the caller's other rights never list an app tool (see the app tool surface for the exact rule). An app tool whose name collides with a tool already in the session is skipped, so an app can never shadow a built-in or group tool, and an app whose slug is lattice or repocontext (the leading segments of the built-in tool namespaces) contributes no tools at all. App tools never appear in the lattice_capabilities report, which describes facade groups only, and with the package unregistered the tool list is unchanged.

Region targeting

A single MCP server can front more than one region (the current cluster plus configured, reachable peers - see Remote host). Two additive surfaces expose this:

  • lattice_list_regions - a read-only meta-tool that lists the regions the server can route a call to, current region first, each with its region id, cluster id, and per-group endpoint availability. Because it discloses peer topology, it is gated like a group tool rather than riding along with lattice_capabilities: it is advertised only to a caller holding at least one facade-group grant, and only when the registered authorizer permits it by name. A region that does not serve a group is reported unavailable for it and rejected fail-closed when a call targets it for that group; only the regions configured on this server are listed, and with VerifyRegionIdentity on, a peer whose endpoint is unreachable or answers as a different cluster than the one it advertises is omitted (fail-closed discovery), while a peer the probe cannot check - for example one with no advertised ClusterId or no State endpoint - stays listed (see Remote hosting). The tool is projected from the shared Orleans.Lattice.Api.Region.ILatticeRegionCatalog contract, so a client reads the same region model the facade layer exposes.
  • An optional region argument on every facade-group tool (the two meta-tools take none) - pass a listed region id to route that single call to the named region; omit it to target the current region. Omitting it is byte-for-byte identical to a region-unaware call. The result is annotated with the region it was served from (in the result's _meta.region) whenever a region was supplied.

Region targeting is fail-closed at both ends. Targeting an unknown region, or a region that does not serve the tool's group, returns a clean typed fault that points the caller at lattice_list_regions - never a leaked exception. A cross-region call forwards the same caller credential to the target region, so the target authorizes it independently: a caller lacking rights in the target region is denied there. A region is never an authorization bypass.

A tool call targeting a named region passes the region id as the optional region argument:

// lattice_data_get, explicitly targeting the "us-east" region.
{
  "treeId": "orders",
  "key": "order-42",
  "region": "us-east"
}

The result carries the served region in its _meta.region field. Omit region to target the current region; the call and its result are then identical to a region-unaware binding. Call lattice_list_regions (no arguments) first to discover the routable region ids.

Tenant-scoped region discovery

On a cluster running the tenancy add-on, what lattice_list_regions returns depends on whether the call asserts an active tenant (the lattice-active-tenant header - see Security):

  • No tenant asserted (an operator, or any caller on a non-tenancy cluster) - the full routing topology, unannotated and byte-for-byte as before. The reserved default tenant is treated the same way, and so is any call to a head that cannot resolve tenant standing: a non-tenancy cluster, or a remote head without the TenantAdmin endpoint (see Remote hosting).
  • A non-default tenant assertion the caller may not act as - refused by the head's ITenantContextResolver (the seam the tenancy add-on registers to validate an assertion against the caller's own membership), resolved to a different tenant, or made to a head with no validating resolver - the current region alone, with no tenantScope annotation, so the asserted id is never echoed back. The tenant's standing is never looked up.
  • A validated non-default tenant - the current region plus only those peers in the tenant's actionable set: the regions its operator has authorized it into, plus the regions it is resident in. Each entry gains an additive tenantScope object reporting tenantId, isAllowed, status, and isResident. The current region is always listed (the caller is already talking to it) and is annotated truthfully, which may say the tenant is neither allowed into nor resident in it.
  • A validated tenant whose standing the head's tenancy resolver cannot establish - the current region alone, fail-closed. It never falls back to the full topology.

In the shipped registrations the two validated-tenant cases are not reached. The discovery tool runs without the caller's credential, so on a co-hosted head the validating resolver sees an anonymous caller and refuses every non-default assertion, and a remote head registers no validating resolver at all. A non-default tenant assertion is therefore currently answered with the current region alone and no tenantScope annotation - or, by a remote head without the TenantAdmin endpoint, with the full unscoped topology.

A region reported with isResident: false is a legitimate lattice_tenant_set_residency destination but not yet a routing destination: targeting it with a region argument is refused by the residency gate until its status reaches Online, and no shipped component advances a region to Online (see Tenant region residency). See the region sets.

State tools (lattice_state_*)

Read-only introspection over ILatticeStateQuery. Registered by AddStateTools().

Tool Purpose
lattice_state_get_cluster_info The connected cluster's identity (Orleans cluster and service ids).
lattice_state_list_trees Paged catalog of registered trees.
lattice_state_list_views Paged catalog of materialised views.
lattice_state_list_tag_indexes Tag indexes defined on the cluster.
lattice_state_list_tag_values Distinct tag values one tag index carries over one subject tree.
lattice_state_list_covered_trees Trees covered by a tag index.
lattice_state_list_index_tags Distinct tag values one tag index carries across every tree it covers.
lattice_state_scan_tag_members Members matching a tag value.
lattice_state_get_tree_summary Summary of one tree.
lattice_state_get_shard_summaries Per-shard summaries for a tree.
lattice_state_get_physical_shard_count Physical shard count for a tree.
lattice_state_get_tree_structure Depth-bounded shard-root node graph.
lattice_state_scan_entries Key-ordered entry page; the optional mode selects the cursor (Snapshot, the default, or the cheaper Live / LivePointInTime).
lattice_state_get_entry One key's full record.
lattice_state_get_entry_history Version history for a key.
lattice_state_cancel_scan Cancel an in-flight scan.

Data tools (lattice_data_*)

Read/write access over ILatticeDataApi. Registered by AddDataTools(enableWrites). The read tools - the two point / range reads plus the thirteen typed-CRDT reads - are always exposed; the write tools (the six point / batch writes plus the thirteen typed-CRDT writes) require enableWrites: true. Discovery then applies a per-tool minimum inside the group: the read tools are listed to any caller the data group admits, while each write tool is listed only to a caller whose Allow grants include at least one of Write, Delete, RangeDelete, CrdtApply, AtomicWrite, or BulkLoad, so a caller holding only Read / RangeRead is offered the reads alone and cannot invoke a write it was not offered.

Tool Kind Purpose
lattice_data_get read Fetch a single key.
lattice_data_read_range read Read a key range. Only treeId is required; the range bounds, page size, and continuation token are optional (omit them for a full, unbounded first page).
lattice_data_set write Set a single key.
lattice_data_delete write Delete a single key.
lattice_data_delete_range write Delete every key in a half-open [startInclusive, endExclusive) range, returning deletedCount. Both bounds are required. The drain reopens transparently across a transient enumerator loss so a large range completes; authorization is all-or-nothing across the span.
lattice_data_set_many write Non-atomic single-tree batch: apply each key independently (best-effort, per-key authorized).
lattice_data_set_many_atomic write Atomic single-tree batch.
lattice_data_set_many_atomic_cross_tree write Atomic cross-tree batch.

Typed CRDT tools

These surface the replicated CRDT primitives directly, so a caller reads and writes a value's convergent type without hand-encoding CRDT state. Element and value bytes are base64-encoded. Every write except the G-Set add and the Max- / Min-Register sets names its writer with a replicaId. The writes that offer more than one operation (PN-Counter, OR-Set, OR-Flag, RW-Flag, RW-Set, Sequence, and OR-Map) take an operation discriminator with the values shown in parentheses below; the remaining writes perform one fixed operation and take no discriminator. Each type also has a paired read. See CRDT primitives for the merge rules summarised below.

Type Write tool Read tool Merge rule
PN-Counter lattice_data_pncounter (increment / decrement) lattice_data_pncounter_get Per-replica signed sum.
G-Counter lattice_data_gcounter (increment only) lattice_data_gcounter_get Per-replica grow-only sum.
OR-Set lattice_data_orset (add / remove) lattice_data_orset_get Add-wins, observed-remove.
OR-Flag lattice_data_orflag (enable / disable) lattice_data_orflag_get Enable-wins.
RW-Flag lattice_data_rwflag (enable / disable) lattice_data_rwflag_get Disable-wins.
RW-Set lattice_data_rwset (add / remove) lattice_data_rwset_get Remove-wins observed set.
Version Vector lattice_data_version_vector_tick lattice_data_version_vector_get Per-replica max clock.
MV-Register lattice_data_mvregister_set lattice_data_mvregister_get Keep concurrent values.
Max-Register lattice_data_maxregister_set lattice_data_maxregister_get Keep the greatest observed value.
Min-Register lattice_data_minregister_set lattice_data_minregister_get Keep the least observed value.
Sequence lattice_data_sequence (insertAt / removeAt) lattice_data_sequence_get Ordered insert / tombstone.
OR-Map lattice_data_ormap (set / remove) lattice_data_ormap_get Recursive per-key merge.
G-Set lattice_data_gset (add only) lattice_data_gset_get Grow-only set.

The OR-Map tools operate on an OrMap<string, MvRegister> (string field keys; each field value a multi-value register of base64 bytes). The host must register that shape for the target tree name at silo startup (AddOrMapShape<string, MvRegister>(treeName)); no MCP tool registers one. On a tree without it, lattice_data_ormap is rejected with a caller error naming the missing registration, while lattice_data_ormap_get still returns an empty map - so an empty read does not mean the map is writable.

Backup tools (lattice_backup_*)

Backup control over ILatticeBackupControl and ILatticeBackupOperations. Registered by AddBackupTools(enableControl). The seven read-only tools are always exposed; the ten control tools require enableControl: true (the count includes the three deprecated aliases).

Tool Kind Purpose
lattice_backup_list inspect Paged, read-filtered catalog page.
lattice_backup_describe inspect A manifest and its restore chain.
lattice_backup_inventory inspect Catalog-wide inventory summary.
lattice_backup_scope_status inspect A scope's schedule and last-run status.
lattice_backup_export_artifact inspect Export one bounded, base64-encoded page of a backup artifact's bytes, resumed from chunkOffset until endOfStream.
lattice_backup_operation_status inspect Read a tracked backup or restore operation by operation id; returns found plus the operation view when visible.
lattice_backup_operation_list inspect Page the caller's tracked backup and restore operations newest-first.
lattice_backup_start control Start a tracked full backup and return { operationId, kind, treeIds, created, statusTool }.
lattice_backup_start_incremental control Start a tracked incremental backup layered on a base backup and return an operation handle.
lattice_backup_start_set control Start a tracked backup set over treeIds and return an operation handle.
lattice_backup_start_restore control Start a tracked restore and return an operation handle; a succeeded status includes restoreResult for lattice_backup_revert_restore.
lattice_backup_start_health_check control Start a tracked health check of one backup against the sink and return an operation handle; progress counts artifacts, the verdict is the healthStatus result key, and the fresh report is persisted as the backup's latest health state.
lattice_backup_start_catalog_rebuild control Start a tracked rebuild of the backup catalog from the sink and return an operation handle; needs the restore grant over the backup catalog.
lattice_backup_start_catalog_scrub control Start a tracked scrub of the backup catalog against the sink, pruning orphans when pruneOrphans is true, and return an operation handle; needs the restore grant over the backup catalog.
lattice_backup_operation_cancel control Request cancellation of a tracked backup or restore operation.
lattice_backup_revert_restore control Undo a shadow-cutover restore from a prior restore result.
lattice_backup_delete control Delete a backup and its unshared artifacts.
lattice_backup_create control Deprecated alias for lattice_backup_start; will be removed in the next major version and now returns an operation handle instead of blocking.
lattice_backup_create_incremental control Deprecated alias for lattice_backup_start_incremental; will be removed in the next major version and now returns an operation handle instead of blocking.
lattice_backup_restore control Deprecated alias for lattice_backup_start_restore; will be removed in the next major version and keeps its operationId argument as the restore engine idempotency key.

The operation view returned by lattice_backup_operation_status, lattice_backup_operation_list, and lattice_backup_operation_cancel includes operationId, kind, treeIds, state, phase, phaseIndex, phaseCount, completedUnits, totalUnits, unitName, start and finish timestamps, failureReason, resultReference, the result map, restoreResult for a succeeded restore, and cancelRequested. Without control enabled the backup group exposes 7 tools; with control enabled it exposes 20.

Auth tools (lattice_auth_*)

Authorization administration over ILatticeAuthAdmin. Registered by AddAuthTools(enableAdministration). The introspection tools are always exposed; the mutating administration verbs require enableAdministration: true, and remain administrator-gated by the facade regardless.

Tool Kind Purpose
lattice_auth_explain inspect Explain an authorization decision.
lattice_auth_effective_permissions inspect A subject's effective permissions.
lattice_auth_get_group inspect Get a group.
lattice_auth_list_groups inspect List groups.
lattice_auth_list_group_members inspect List a group's members.
lattice_auth_list_subject_groups inspect List the groups a subject belongs to.
lattice_auth_get_rule inspect Get an authorization rule.
lattice_auth_list_rules inspect List all rules.
lattice_auth_list_rules_for_tree inspect List rules for a tree.
lattice_auth_upsert_group admin Create or replace a group.
lattice_auth_remove_group admin Remove a group.
lattice_auth_add_member admin Add a group member.
lattice_auth_remove_member admin Remove a group member.
lattice_auth_put_rule admin Create or replace a rule.
lattice_auth_remove_rule admin Remove a rule.

lattice_auth_explain and lattice_auth_effective_permissions take an optional subjectKind argument (User by default). Set it to Group when subjectId names a group, so the tool resolves the group's rule closure instead of treating the id as a user; otherwise a group subject matches no rules and the decision falls through to the tree's default effect.

Both lattice_auth_explain and lattice_auth_effective_permissions also report the cluster's authorization posture (whether the all-trees grant tier and access-administration delegation are enabled). This is the discovery path for the posture - lattice_capabilities does not carry it - so an agent can tell whether a cluster-wide Tree:* grant is actually enforced and whether a policy-tree delegation rule is authorable. Consistent with that posture, lattice_auth_put_rule rejects a Tree:* data-plane rule while the all-trees grant tier is off, and a whole-tree Admin rule on the reserved policy tree while access-administration delegation is off.

Replication tools (lattice_replication_*)

Runtime per-tree cross-cluster replication control over ILatticeReplicationControl. Registered by AddReplicationTools(enableControl). The inspect tool is always exposed; the mutating control tools require enableControl: true, and remain subject to the facade's fail-closed replication access gate regardless. The module is served under both topologies: in-silo, and out-of-silo via AddLatticeMcpRemote(o => { o.Replication = ...; o.EnableReplicationControl = ...; }) over the replication-API gRPC client (see Remote hosting).

Tool Kind Purpose
lattice_replication_get_config inspect Report each authorized tree's enrolled state, the merge mode in force, its ambiguity status, and which enrollment source (Runtime, Static, or RuntimeAndStatic) put it in force.
lattice_replication_enable control Enable replication for a tree under a fixed merge mode.
lattice_replication_disable control Disable replication for a tree without purging already-replicated peer data; a shipper already active for the tree is not stopped.

The control tools carry destructiveHint = true; the inspect tool carries readOnlyHint = true. Discovery is permission-scoped by the LatticeOperation.Replication grant, so a caller without that grant is not shown the group.

lattice_replication_get_config reconciles both enrollment sources a replication-enabled host resolves against: trees enabled at runtime through lattice_replication_enable, and trees declared in the static deployment-time replicated-tree map. Each entry's source says which one is in force, so an estate configured purely at deployment time reports its trees rather than an empty set. That static map always holds the sys-replication-config tree itself, which enableRuntimeConfig: true enrols under OrMap, so the report lists that tree as Static to any caller authorized to manage it. A tree reported Static keeps shipping even after lattice_replication_disable - the static map is a floor - and is turned off by editing the deployment configuration instead. See Runtime replication configuration.

TreeAdmin schema tools (lattice_treeadmin_schema_*)

Schema-management control over ILatticeSchemaControl and ILatticeSchemaOperations, surfaced under the tree-administration group. Registered by AddTreeAdminTools(enableSchemaControl). The read-only schema-inspection tools are always exposed; the mutating schema-management tools require enableSchemaControl: true, and every tool remains subject to the facade's own fail-closed schema access gate regardless (a read authorizes on ordinary read authority; a mutation authorizes on schema-management authority). The group is discovered by a caller granted any one of LatticeOperation.Admin, TreeLifecycle, BulkLoad, or Restore; each tool is still authorized by the facade at call time.

The MCP group holds the ILatticeSchemaControl and ILatticeSchemaOperations facades and delegates to them verbatim - it adds no method to the tree-administration facade and no authorization path of its own. The schema facade and its packages are unchanged.

Tool Kind Purpose
lattice_treeadmin_schema_get_policy inspect Read a tree's enforcement policy, or none when unset.
lattice_treeadmin_schema_list_dead_letters inspect Stream a tree's strict-mode dead-letter entries.
lattice_treeadmin_schema_count_dead_letters inspect Count a tree's strict-mode dead-letter entries.
lattice_treeadmin_schema_get_version_config inspect Read a tree's envelope-version config, or none when unversioned.
lattice_treeadmin_schema_get_remediation_status inspect Read a tree's current or last-known remediation status.
lattice_treeadmin_schema_scan_compliance inspect Scan every current value against the compiled policy and report compliance, in one blocking call; prefer lattice_treeadmin_schema_compliance_scan_start.
lattice_treeadmin_schema_probe_capabilities inspect Probe which schema operations the caller may perform, side-effect free.
lattice_treeadmin_schema_set_policy manage Set or replace a tree's enforcement policy.
lattice_treeadmin_schema_clear_policy manage Clear a tree's enforcement policy.
lattice_treeadmin_schema_set_version_config manage Opt a tree in to envelope versioning (or replace its config).
lattice_treeadmin_schema_clear_version_config manage Opt a tree back out of envelope versioning.
lattice_treeadmin_schema_advance_target_version manage Advance a tree's target schema version.
lattice_treeadmin_schema_remediation_start manage Start a tracked remediation: every value rewritten by a transform and checked against a target policy, then the tree cut over. Returns an operation handle at once.
lattice_treeadmin_schema_migration_start manage Start a tracked eager migration of every value to the tree's current target version. Returns an operation handle at once.
lattice_treeadmin_schema_advance_and_migrate_start manage Start a tracked advance of the target version, then an eager migration to it. Returns an operation handle at once.
lattice_treeadmin_schema_operation_status inspect Read a schema operation's state, phase, values processed of total, and its result map.
lattice_treeadmin_schema_operation_list inspect List the caller's schema operations, newest-first.
lattice_treeadmin_schema_operation_cancel manage Request cancellation of a schema operation; it takes effect only before cutover.
lattice_treeadmin_schema_remediate manage Deprecated alias for lattice_treeadmin_schema_remediation_start; will be removed in the next major version and now returns an operation handle instead of blocking.
lattice_treeadmin_schema_migrate_to_target manage Deprecated alias for lattice_treeadmin_schema_migration_start; will be removed in the next major version and now returns an operation handle instead of blocking.
lattice_treeadmin_schema_advance_and_migrate manage Deprecated alias for lattice_treeadmin_schema_advance_and_migrate_start; will be removed in the next major version and now returns an operation handle instead of blocking.

The manage tools carry destructiveHint = true and readOnlyHint = false, except lattice_treeadmin_schema_operation_cancel, which only stops a run before cutover and so carries destructiveHint = false; the inspect tools carry readOnlyHint = true. The status and list tools are always exposed; the start, cancel and alias tools require enableSchemaControl: true. lattice_treeadmin_schema_set_version_config takes the version config as scalar schemaId / targetVersion / strictIngest arguments; lattice_treeadmin_schema_set_policy and lattice_treeadmin_schema_remediation_start take the schema policy and value-transform model objects directly.

Every start tool takes an optional operationId: starting again with an id in use returns the existing operation with created = false, so a retried start is safe. Poll lattice_treeadmin_schema_operation_status with the handle's operationId until the state is terminal. The operation kinds, phases and result keys are described in Schema operations.

This module is served under both topologies. In-silo it delegates to the co-hosted ILatticeSchemaControl and ILatticeSchemaOperations facades directly; over the remote (out-of-silo) topology the AddLatticeMcpRemote composition wires one schema-API gRPC adapter, GrpcLatticeSchemaControl, serving both facades, off the same endpoint as the tree-administration group (LatticeApiMcpRemoteOptions.TreeAdmin, since the schema-API and tree-administration gRPC services are co-hosted on the same silo address). The remote host honours the same read-always / write-gated split: the read-only schema-inspection tools are served whenever the tree-administration endpoint is configured, and the mutating schema-management tools additionally require LatticeApiMcpRemoteOptions.EnableSchemaControl = true (which maps onto enableSchemaControl). Caller credentials are forwarded on every gRPC call by the shared credential-forwarding interceptor, so the remote cluster re-runs the facade's own fail-closed access gate.

TreeAdmin diagnostics tools (lattice_treeadmin_*)

Read-only administrative diagnostics and storage accounting over ILatticeTreeAdmin, surfaced under the tree-administration group. Registered by AddTreeAdminTools and always exposed (no opt-in flag). Each tool wraps the existing public grain surface (ILattice, ILatticeAdmin) rather than re-implementing shard fan-out, and every tool remains subject to the facade's own fail-closed access gate: the per-tree verbs authorize on whole-tree LatticeOperation.Read authority, and lattice_treeadmin_storage_usage authorizes on the distinct cluster-wide LatticeOperation.Telemetry capability. The group is discovered by a caller granted any one of LatticeOperation.Admin, TreeLifecycle, BulkLoad, or Restore; each tool is still authorized by the facade at call time.

Tool Kind Purpose
lattice_treeadmin_shard_hotness inspect Read a tree's per-shard read/write hotness with tree-level totals.
lattice_treeadmin_shard_diagnostics inspect Read a whole-tree diagnostic report. Both modes walk every shard's leaf chain: the default counts live keys only (its tombstone counts read zero), and the deep flag also counts tombstoned and expired entries.
lattice_treeadmin_shard_map_inspect inspect Inspect a tree's shard-map topology (physical tree id, virtual/physical shard counts, map version).
lattice_treeadmin_projection_digest inspect Read a single shard's leaf-projection content digest for cheap divergence detection.
lattice_treeadmin_tree_stats inspect Read a tree's rolled-up topology, live-key counts, and storage byte breakdown in one call.
lattice_treeadmin_storage_usage inspect Read cluster-wide storage accounting. By default each tree's figures come from its short-lived storage-usage cache (LatticeOptions.StorageUsageCacheTtl), refilled from each shard root's maintained byte totals and each WAL partition without walking the leaf chain; the deep flag forces a fresh leaf-walk that re-measures every shard, in one call - prefer lattice_treeadmin_storage_usage_refresh_start, which re-measures in the background with progress.

Every tool carries readOnlyHint = true and destructiveHint = false. lattice_treeadmin_shard_diagnostics and lattice_treeadmin_storage_usage take an optional deep flag (default false, the cheap path); lattice_treeadmin_projection_digest takes a treeId and a non-negative shardIndex; the remaining per-tree tools take a treeId. lattice_treeadmin_storage_usage is cluster-wide and takes no tree id.

This module is served under both topologies. In-silo it delegates to the co-hosted ILatticeTreeAdmin facade directly; over the remote (out-of-silo) topology the AddLatticeMcpRemote composition wires a tree-administration-API gRPC adapter off the LatticeApiMcpRemoteOptions.TreeAdmin endpoint. Caller credentials are forwarded on every gRPC call by the shared credential-forwarding interceptor, so the remote cluster re-runs the facade's own fail-closed access gate.

TreeAdmin operation tools (lattice_treeadmin_*)

Accept-then-poll compliance scans and fresh storage-usage refreshes, on the shared long-running operation contract, surfaced under the tree-administration group and always exposed (no opt-in flag). A start tool returns a handle naming the operation id and the status tool to poll; the status, list and cancel tools are scoped by the facade to the tool's own kind, the caller's tenant and what the caller may read, and report found = false for an operation the caller may not see.

Tool Kind Purpose
lattice_treeadmin_schema_compliance_scan_start operate Start a tracked compliance scan of a tree (ILatticeSchemaComplianceOperations); needs read over the tree.
lattice_treeadmin_schema_compliance_scan_status inspect Read a compliance scan's state, phase, entries scanned of total, and on success the report in the result map.
lattice_treeadmin_schema_compliance_scan_list inspect List the caller's compliance scans, newest-first.
lattice_treeadmin_schema_compliance_scan_cancel operate Request cancellation of a compliance scan.
lattice_treeadmin_storage_usage_refresh_start operate Start a tracked deep re-measure of every tree's storage usage (ILatticeStorageUsageOperations); needs cluster telemetry.
lattice_treeadmin_storage_usage_refresh_status inspect Read a refresh's state, trees measured of total, and on success the cluster totals in the result map.
lattice_treeadmin_storage_usage_refresh_list inspect List the caller's refreshes, newest-first.
lattice_treeadmin_storage_usage_refresh_cancel operate Request cancellation of a refresh.

The inspect tools carry readOnlyHint = true; the operate tools record or stop an operation, so they carry readOnlyHint = false, but never mutate data, so every tool carries destructiveHint = false. Each start takes an optional operationId that makes it idempotent. Over the remote topology AddLatticeMcpRemote wires gRPC adapters for both surfaces off the LatticeApiMcpRemoteOptions.TreeAdmin endpoint. See Schema compliance operations and Storage usage operations for the phases, units and result keys.

TreeAdmin lifecycle and control tools (lattice_treeadmin_*)

Explicit tree lifecycle, per-tree registry configuration, bulk-load, restore, WAL placement, view, tag-index, compaction, and retention operations over ILatticeTreeAdmin, surfaced under the tree-administration group. Registered by AddTreeAdminTools(enableLifecycle: true). The read-only lifecycle/control tools are always exposed; the mutating lifecycle/control tools require enableLifecycle: true. Each tool delegates to the tree-administration facade instead of re-implementing registry or shard fan-out behaviour, and every tool remains subject to the facade's own fail-closed access gate. The group is advertised to callers whose effective permissions include one of the tree-administration group capabilities (Admin, TreeLifecycle, BulkLoad, or Restore); individual verbs are still authorized by the facade at call time. Registration is idempotent under matching parameters, and reserved system tree ids in the _lattice_ namespace are rejected for mutating verbs.

Tree lifecycle and registry

Tool Kind Purpose
lattice_treeadmin_tree_exists read Report whether a tree is registered.
lattice_treeadmin_tree_resolve_alias read Resolve the physical tree a logical tree maps to.
lattice_treeadmin_tree_get_config read Read a tree's registry-backed configuration (sizing, alias, per-tree overrides).
lattice_treeadmin_tree_get_shard_map read Read a tree's registry-persisted shard map (custom-map flag, version, virtual/physical shard counts).
lattice_treeadmin_tree_deletion_status read Read a tree's soft-deletion state, recovery window, and purge status - including, while a purge runs, purgeInProgress with purgedShardCount of purgeShardCount shards done. Answers without waiting for a shard's purge.
lattice_treeadmin_tree_reshard_status read Read the current online-reshard state and shard-map fan-out, with the running reshard's target and starting shard counts to measure its progress against.
lattice_treeadmin_tree_resize_status read Read the current online-resize state - running, an accepted undo still unwinding (undoRequested), or none - and effective B+ node capacities, with the phase and the completed and total work units of a running resize.
lattice_treeadmin_tree_snapshot_status read Read whether a point-in-time snapshot capture is in flight for a tree and, while one runs, its phase and how many of its shards are copied.
lattice_treeadmin_tree_create manage Explicitly create or register a tree with optional initial sizing.
lattice_treeadmin_tree_set_alias manage Point a logical tree at a physical tree.
lattice_treeadmin_tree_set_config manage Apply per-tree configuration overrides - publish-events, projection-digest maintenance, durable-history retention, and the advisory WAL retained-byte ceiling - each written only when its apply* flag is set (a null value on an applied dimension clears that override).
lattice_treeadmin_tree_delete manage Soft-delete a tree.
lattice_treeadmin_tree_recover manage Recover a soft-deleted tree within its recovery window.
lattice_treeadmin_tree_purge manage Hard-purge a soft-deleted tree, irreversibly and bypassing the soft-delete window. Requires confirm = true; a false or omitted confirm is rejected. Accept-then-poll: the shard walk runs in the background, and the call returns within a bounded wait - with purgeInProgress still true for a tree too large to purge in that time, which is not a failure; poll lattice_treeadmin_tree_deletion_status. A call while the purge runs or after it completed returns the status without error.
lattice_treeadmin_tree_reshard manage Start an online reshard that grows or shrinks a tree to a target physical shard count: at least 2, and at most the tree's virtual slot count, never more than 4096.
lattice_treeadmin_tree_resize manage Start an online B+ node-capacity resize.
lattice_treeadmin_tree_resize_undo manage Undo a tree's most recent resize - an in-flight one at any phase, or a completed one while the pre-resize tree is still within its soft-delete window. Accept-then-poll: admitted even while a resize phase runs, it returns within a bounded wait with undoRequested set if the unwind is still in progress.
lattice_treeadmin_tree_snapshot manage Capture a point-in-time tree snapshot into a fresh destination tree, in Offline or Online mode; any other mode value is rejected before a tree is resolved.

Bulk load, restore, and WAL placement

Tool Kind Purpose
lattice_treeadmin_bulk_load_begin manage Begin a streamed bulk-load session.
lattice_treeadmin_bulk_load_append manage Append a batch to an active bulk-load session.
lattice_treeadmin_bulk_load_commit manage Commit an active bulk-load session.
lattice_treeadmin_tree_restore manage Restore one tree from a backup.
lattice_treeadmin_tree_restore_set manage Restore a set of trees from a backup set.
lattice_treeadmin_tree_restore_revert manage Revert a shadow-cutover restore.
lattice_treeadmin_wal_placement_inspect read Inspect a tree's durable WAL placement.
lattice_treeadmin_wal_placement_audit read Audit WAL placement against the reporting silo's storage-provider catalog.
lattice_treeadmin_wal_reclamation read Read which durable pin holds a tree's WAL floor (consumer id, leaf, partition, pin offset), the leaf's persisted checkpoint and durable state, and isWedged: true exactly when the holder has a usable offset above a checkpoint of -1, a pin that never moves. Keyed on the holder, not on WAL growth; pinStoreReadable = false means nothing was established. Served by ILatticeWalReclamation; a host without it fails the call.
lattice_treeadmin_wal_move_plan read Preview moving a WAL partition to a target storage provider.
lattice_treeadmin_wal_move_execute manage Execute a planned WAL partition move, waiting for it (deprecated blocking verb; prefer lattice_treeadmin_wal_move_start).
lattice_treeadmin_wal_move_reclaim manage Reclaim source WAL storage after a move.
lattice_treeadmin_orphaned_leaves_audit read Audit descent-unreachable leaves and repair eligibility. Optional survey=true counts every key outcome per leaf (100,000-key bound, read-only, off by default); VerifiedKeyCount remains a prefix, not a census. Nullable survey counts distinguish unknown from zero; findings identify shard, leaf, range and first failure. Batch totals include orphan/repairable/refused leaves and surveyed missing keys. Keep survey enabled on resumed batches; pass each batch's resumeFrom back until the report's isComplete is true, then check verdictComplete and unknown counts.
lattice_treeadmin_orphaned_leaves_repair manage Unsplice every orphaned leaf whose keys were all verified readable elsewhere, releasing the WAL trim floor. One bounded batch per call; pass each batch's resumeFrom back until isComplete is true, then re-audit. On a timeout the return value is not authoritative.

Views, tag indexes, compaction, and retention

Tool Kind Purpose
lattice_treeadmin_view_create manage Create or update a provider-backed runtime materialised view from a provider key and a base64 payload (64 KiB decoded maximum).
lattice_treeadmin_view_list read List runtime-registered materialised views with provider key and projection version; payloads are never returned.
lattice_treeadmin_view_status read Read one materialised view's source, lag, active generation, provider key, and projection version; payloads are never returned.
lattice_treeadmin_view_rebuild manage Rebuild a materialised view, waiting for it (deprecated blocking verb; prefer lattice_treeadmin_view_rebuild_start).
lattice_treeadmin_view_reconcile manage Reconcile a materialised view, waiting for it (deprecated blocking verb; prefer lattice_treeadmin_view_reconcile_start).
lattice_treeadmin_view_drop manage Drop a runtime materialised view.
lattice_treeadmin_tag_index_list read List tag indexes and their backing membership trees.
lattice_treeadmin_tag_index_status read Read one tag index's backing tree, covered trees, and reconcile state.
lattice_treeadmin_tag_index_reconcile manage Reconcile a tag index, waiting for it (deprecated blocking verb; prefer lattice_treeadmin_tag_index_reconcile_start).
lattice_treeadmin_compaction_trigger manage Trigger an out-of-cycle tombstone-compaction pass on one physical shard of a tree (shardIndex), bypassing the shard's cooldown; reaps only tombstones and TTL-expired entries.
lattice_treeadmin_retention_get read Read a tree's durable-history retention policy.
lattice_treeadmin_retention_set manage Set or clear a tree's durable-history retention policy: a null mode or windowSeconds clears that part, a non-positive window is rejected, and a mode other than MetadataOnly, FullValue or Hybrid is rejected before a tree is resolved.

The read tools carry readOnlyHint = true and destructiveHint = false; the manage tools carry destructiveHint = true and readOnlyHint = false, except lattice_treeadmin_compaction_trigger and lattice_treeadmin_retention_set, which are mutating but non-destructive to readable state and so carry readOnlyHint = false and destructiveHint = false. The registry-persisted shard-map read is distinct from the diagnostics lattice_treeadmin_shard_map_inspect tool, which inspects live routing rather than the durable registry map.

Accept-then-poll operations

Tool Kind Purpose
lattice_treeadmin_view_rebuild_start manage Start a tracked view rebuild; returns the operation handle at once.
lattice_treeadmin_view_reconcile_start manage Start a tracked view reconcile.
lattice_treeadmin_tag_index_reconcile_start manage Start a tracked tag-index reconcile sweep.
lattice_treeadmin_wal_move_start manage Start a tracked WAL partition move (same tunables as wal_move_execute).
lattice_treeadmin_orphaned_leaves_repair_start manage Start a tracked whole-tree orphaned-leaf repair.
lattice_treeadmin_orphaned_leaves_audit_start manage Start a tracked whole-tree orphaned-leaf audit; mutates nothing but the operation record.
lattice_treeadmin_operation_cancel manage Request cancellation of a tracked tree-administration operation; needs the grant that starting it needed.
lattice_treeadmin_operation_status read Read a tracked tree-administration operation by id; returns found plus the operation view when visible.
lattice_treeadmin_operation_list read List one newest-first page of the caller's tracked tree-administration operations.

Every start tool takes an optional operationId for idempotency and returns operationId, kind, treeIds, created and the statusTool to poll. The operation view includes state, phase, phaseIndex, phaseCount, completedUnits, totalUnits, unitName, failureReason, resultReference, result and cancelRequested; the kinds, phases, units and result keys are in Tree-administration operations. lattice_treeadmin_operation_status and lattice_treeadmin_operation_list are always contributed; the start tools and lattice_treeadmin_operation_cancel need the lifecycle opt-in. lattice_treeadmin_orphaned_leaves_audit_start and lattice_treeadmin_operation_cancel are non-destructive (destructiveHint = false); the other start tools are destructive.

This module is served under both topologies. In-silo it delegates to the co-hosted ILatticeTreeAdmin facade directly; over the remote (out-of-silo) topology the AddLatticeMcpRemote composition wires the same tree-administration-API gRPC adapter off the LatticeApiMcpRemoteOptions.TreeAdmin endpoint, with the mutating lifecycle/control tools additionally requiring LatticeApiMcpRemoteOptions.EnableLifecycleControl = true (which maps onto enableLifecycle). lattice_treeadmin_wal_reclamation resolves the separate ILatticeWalReclamation facade instead: in-silo the one AddLatticeTreeAdminApi registers, and over the remote topology a GrpcLatticeWalReclamation adapter off the same endpoint that calls the GetWalReclamation RPC. Caller credentials are forwarded on every gRPC call by the shared credential-forwarding interceptor, so the remote cluster re-runs the facade's own fail-closed access gate.

Tenant self-awareness tools (lattice_tenant_current, lattice_tenant_list, lattice_tenant_get)

Read-only tenant discovery over the tenant self-service facade, registered by AddTenantSelfAwarenessTools(). The module self-gates on whether tenancy is enabled: it takes no opt-in flag of its own and contributes its tools only when the tenancy-gated self-service facade is present, so a non-tenancy deployment - even one that calls the extension - is byte-for-byte unchanged. The tools advertise under the existing read-only State group rather than a new discovery group.

Tool Kind Purpose
lattice_tenant_current inspect Report the tenant the calling credential is operating as, with its lifecycle status and whether it is the reserved default tenant.
lattice_tenant_list inspect List the tenants the caller is authorized to access, in ascending tenant-id order, scoped fail-closed to the caller.
lattice_tenant_get inspect Read one authorized tenant's lifecycle status, per-region residency, and authored resource quotas; fails closed with a not-found when the tenant does not exist or the caller may not see it.

Every tool carries readOnlyHint = true and destructiveHint = false. The module adds no authorization path of its own: each tool stamps the caller credential onto the ambient context and defers to the facade's leak-free, fail-closed per-tenant scoping, so an unauthorized caller sees only its own default context, an empty accessible list, and a fail-closed not-found on inspect.

This module is served under both topologies. In-silo it delegates to the co-hosted self-service facade directly; over the remote (out-of-silo) topology the AddLatticeMcpRemote composition wires a tenant self-service gRPC adapter off the LatticeApiMcpRemoteOptions.TenantAdmin endpoint (the self-service reads share the tenant-administration gRPC service address). Caller credentials are forwarded on every gRPC call by the shared credential-forwarding interceptor, so the remote cluster re-runs the facade's own fail-closed per-tenant scoping.

Tenant-admin tools (lattice_tenant_create, lattice_tenant_suspend, lattice_tenant_resume, lattice_tenant_delete, lattice_tenant_set_quotas)

Tenant lifecycle control over the tenant-administration facade, registered by AddTenantAdminTools(enableControl). The lifecycle verbs are all mutating, so the module contributes tools only when enableControl: true; called without it, the tenantadmin capability is advertised to an Admin caller but no tools are contributed, and a cluster that never calls AddTenantAdminTools exposes no tenant-admin capability at all. The same registration also contributes the three region-residency tools. The group is discovered only by a caller granted LatticeOperation.Admin.

Tool Kind Purpose
lattice_tenant_create manage Register a new tenant in the active status, seeding the admin subjects that may see it. Omit adminSubjects (or pass an empty list) and the calling subject is seeded so the creator can see what it created; supply a non-empty list and that set is used instead (the caller is not added on top): a null, empty or whitespace entry is rejected, duplicates collapse, and where an identity directory is registered with validation required, an id it cannot resolve is refused. Fails closed if a tenant with the same id already exists (it is not an idempotent upsert).
lattice_tenant_suspend manage Move a tenant to the suspended status. Idempotent; the reserved default tenant cannot be suspended.
lattice_tenant_resume manage Return a suspended tenant to the active status. Idempotent; fails closed if the tenant does not exist.
lattice_tenant_delete manage Delete a tenant, cascading a soft-delete to every tree the tenant owns before removing its registry record. The reserved default tenant cannot be deleted.
lattice_tenant_set_quotas manage Author a tenant's resource quotas and burst allowance, replacing whatever quotas it currently carries. Each ceiling (maxBytes, maxKeys, maxMemoryBytes, maxTreeCount, maxOpsPerSecond) is null for unbounded on that dimension, and a bounded ceiling must be non-negative; pass every dimension null to lift the caps again. burstPercent must be non-negative. The reserved default tenant cannot be given quotas, and it fails closed if the tenant does not exist.

Every tool carries destructiveHint = true and readOnlyHint = false. The module adds no authorization path of its own: each tool stamps the caller credential onto the ambient context and defers to the facade's own fail-closed tenant-admin access gate, so an unauthorized caller is default-denied on every mutation.

This module is served under both topologies. In-silo it delegates to the co-hosted tenant-administration facade directly; over the remote (out-of-silo) topology the AddLatticeMcpRemote composition wires a tenant-administration gRPC adapter off the LatticeApiMcpRemoteOptions.TenantAdmin endpoint, with the mutating tools additionally requiring LatticeApiMcpRemoteOptions.EnableTenantControl = true (which maps onto enableControl). Caller credentials are forwarded on every gRPC call by the shared credential-forwarding interceptor, so the remote cluster re-runs the facade's own fail-closed access gate.

Tenant region residency (lattice_tenant_authorize_regions, lattice_tenant_set_residency, lattice_tenant_region_status)

Per-tenant region-residency control over the region-residency facade, contributed by the same AddTenantAdminTools(enableControl) registration and gated behind the same enableControl opt-in. Of the region sets, they author the operator-owned allowed set and the tenant-owned resident set.

Tool Kind Arguments Purpose
lattice_tenant_authorize_regions manage tenantId, allowedRegions (both required) Author the complete set of regions a tenant is allowed to place residency in. Operator action.
lattice_tenant_set_residency manage tenantId, residencyRegions (both required) Author the complete set of regions a tenant is resident in, within its allowed set. Tenant-admin action.
lattice_tenant_region_status inspect tenantId (required) Read the tenant's per-region residency lifecycle, ordered by region id. Tenant-admin action.

Both region-set arguments are a replacement, not a delta: a currently-allowed region absent from allowedRegions is revoked, and a currently-resident region absent from residencyRegions begins draining. Because an omitted list would be indistinguishable from "revoke everything", both are mandatory in the tool schema - an agent must state the set it wants rather than wiping a tenant's standing by forgetting an argument.

The two mutating tools carry destructiveHint = true and readOnlyHint = false; lattice_tenant_region_status carries readOnlyHint = true and destructiveHint = false, so this group is no longer uniformly mutating.

Authorization is two-tier and inherited from the facade, which the tools do not widen:

  • lattice_tenant_authorize_regions is operator-only - the server authorizes it as cluster-wide admin on the reserved auth policy tree and denies every non-operator caller, including a tenant admin. The allowed set is the operator's containment boundary.
  • lattice_tenant_set_residency and lattice_tenant_region_status are operator-or-tenant-admin - the caller is authorized as the platform operator or as a live admin subject on the tenant record.

Both tiers are independent of the data-plane DefaultEffect, so an unmatched request resolves to deny even under DefaultEffect = Allow.

Ordering matters and the tools fail closed when it is violated: lattice_tenant_set_residency refuses a region outside the allowed set, refuses to remove the last resident region, and lattice_tenant_authorize_regions refuses to revoke a region the tenant is still resident in. A newly added region reports Provisioning, not Online, and no shipped component advances it further: nothing backfills the tenant's existing data into an added region, so promoting it through Backfilling to Online is an operator step the host takes on a silo, one lifecycle step at a time with TenantRecord.TryPromoteRegionStatus. A dropped region's drain completes on its own, Draining -> Offline -> Removed, on each silo of that region that registers the tenant-admin control API (see Lifecycle states). Once a tenant's residency is set it is served only in a region whose status is exactly Online, so until an operator has advanced one it is served in none.

The typical workflow is:

  1. An operator calls lattice_tenant_authorize_regions to widen the allowed set.
  2. A tenant admin calls lattice_tenant_region_status and sees the new region as isAllowed: true with status None.
  3. The tenant admin calls lattice_tenant_set_residency to move into it; it reports Provisioning.
  4. The region stays Provisioning until an operator of the host advances it, one lifecycle step at a time, to Online; no shipped component does. Only then does a region-targeted call routed there succeed.

This module is served under both topologies. In-silo it delegates to the co-hosted region-residency facade directly; over the remote topology AddLatticeMcpRemote wires a region-residency gRPC adapter off the same LatticeApiMcpRemoteOptions.TenantAdmin endpoint.

Error handling

Every facade-backed tool call is routed through a single translation seam, so a fault is surfaced to the client as an actionable error result rather than the SDK's opaque generic mask. The translated message names the failure class:

Fault What the client sees
A remote gRPC RpcException of any status The binding's sanitised detail, prefixed with the status code - except a FailedPrecondition guidance message, which is surfaced verbatim on its own. A PermissionDenied/Unauthenticated denial stays a denial, and a server-side fault code points at the cluster logs.
A local MCP-host fault (assembly load failure, argument or mapping error) The exception type name and message, so an operator can diagnose a host-side problem directly.
A fail-closed authorization denial Surfaced as a denial with its safe message; it is never downgraded or swallowed.

The seam never forwards a raw server exception or stack trace across the gRPC boundary: the deliberately generic Internal wire message stays generic, and the translation only ever adds the gRPC status code and the detail the binding already chose to expose (see Security).

Every group tool (everything except the two meta-tools) binds its arguments strictly: an argument the tool does not declare - typically a misspelled parameter name - is rejected before any facade call, with a message naming the offending argument and listing the accepted ones, rather than being silently ignored. The echoed names are sanitised: at most five are named (the rest are counted), each is cut to 64 characters, and any character other than an ASCII letter or digit, _, - or . is replaced with ?. Caller mistakes on the data and state tools surface as client-error statuses, never as a generic Internal fault that points at the cluster logs. On lattice_data_set_many_atomic and lattice_data_set_many_atomic_cross_tree, reusing an operationId with a different key set (or, cross-tree, a different tree or key set) than its first submission is a FailedPrecondition with a self-contained message; a duplicate key or an empty / '/'-bearing operationId is an InvalidArgument. Those two statuses are what a remote head reports from the data gRPC binding; a co-hosted server surfaces the same fault as the facade's own exception type and message. On lattice_data_set, a value that is not valid base64 is rejected up front, before any facade call, with a tool error that names the parameter ("The 'value' parameter must be base64-encoded; the supplied text is not valid base64.") rather than leaking a JSON decode error. Unknown-target reads (lattice_state_get_tree_summary, lattice_state_get_shard_summaries, lattice_state_get_entry, lattice_state_get_tree_structure, lattice_state_scan_entries, lattice_state_get_entry_history) are typed statuses on a normal result - TreeNotFound, KeyNotFound, or IndexNotFound - not gRPC faults, and lattice_state_get_physical_shard_count answers an unknown tree with a null count and treeExists set to false.

Client errors are answered, not logged as faults

The ModelContextProtocol SDK logs every exception a tool throws at Error level with its stack, as "threw an unhandled exception", before it turns the exception into an error result. A caller that omits a required argument would therefore read, in the server log, exactly like a server fault. So a call rejected as the caller's mistake is answered with the same error result (isError: true, text An error occurred invoking '<tool>': <message>) without being thrown: the MCP host logs it at Debug with no stack under event McpToolClientError, and counts it on orleans.lattice.api.mcp.tool.client_errors - a counter on the MCP host's own meter, orleans.lattice.api.mcp (exposed as LatticeApiMcpMetrics.MeterName on the public LatticeApiMcpMetrics class), so an OpenTelemetry pipeline must subscribe to that meter to export it - tagged by tool, reason, and a tenant tag fixed to the platform sentinel _platform_:

reason Raised for
unknown_argument An argument the tool does not declare (the strict-binding rejection above).
invalid_argument A missing, empty, or unrecognised argument, including one the SDK's argument binder cannot bind.
rejected_content An argument whose content is refused, for example a repository-context memory body carrying leaked tool-call framing or a credential-bearing URL.
not_found A record or resource the call names that does not exist, for example repocontext_update against a key with no record.

The message of a classified client error is sanitised once, before it is returned or logged: every control character and Unicode line or paragraph separator is replaced with ?, and a message longer than 2,048 characters is cut there and ends in ..., so a caller-chosen key, path or argument name cannot forge a record in a line-oriented log.

The built-in lattice_* tools raise only the two argument-binding reasons - unknown_argument, and invalid_argument for an argument the SDK's binder cannot bind; rejected_content, not_found, and the other invalid_argument cases come from the repository-context tools. A caller mistake that a tool does not classify is still thrown, so it still logs at Error and is not counted. In the built-in groups that includes a value that is not valid base64 on lattice_data_set, an argument the facade rejects, and an InvalidArgument status from a remote head. Several repository-context refusals are unclassified too, for example a fencing conflict or a claim on a non-memory key; the repository-context page lists them.

The Debug line is the MCP host's own record, and a tool group can log a failure itself before the host sees it. The repository-context tools do: they log every call that reaches one of their tools and fails at Warning with its exception, a classified client error included. So a caller mistake on a repocontext_* tool still leaves a Warning line with a stack beside the host's Debug line. An undeclared argument, a refused region, and a refusal by the registered ILatticeApiMcpAuthorizer are turned away before the tool runs, so they leave no such line. An access-gate denial that fails the call from inside a repocontext_* tool - the LatticeAuthorizationDeniedException the tree access gate throws when it refuses the caller's credential on one of the tool's tree operations - does reach that logger, so it leaves the Warning line with its stack. The host then turns it into an unclassified error, so it also logs at Error and is not counted as a client error.

What the client sees is unchanged. A server fault, any fault a tool raises without classifying it as one of the reasons above, an authorization denial, and a region refusal are still thrown, so they still log at Error: a denial is never downgraded to a client error.

Next

  • Security - how tools are gated and how the caller credential flows.
  • Remote hosting - the same tool modules over gRPC clients.