ReferenceAvo MCPTools reference

Avo MCP tools reference

Every tool except list_workspaces and describe_tool operates on a workspace. Pass workspaceId as a parameter; stdio clients can also set the WORKSPACE_ID environment variable.

🔒

Each tool lists the OAuth scope it requires. Write tools (workflow, save_items) require the write scope, which is requested as a separate consent step on first use.

The MCP exposes a small set of tools mapped to agent intents:

IntentToolScope
Entry point — find your workspace IDslist_workspacesread
Learn the shape — fetch the exact contract for the call you are about to makedescribe_toolnone
Discover — find items by meaning or by structural filtersearchread
Understand — full details for an event, property, branch, source, etc.getread
Change — create, update, archive, or unarchive items on a branchsave_itemswrite
Progress — create a branch, update its description, pull main, set a source language, importworkflowwrite

Two more tools round out the surface: list_branches (transitional, stays available while branch enumeration is folded into search) and give_feedback (send product feedback about the MCP to the Avo team — call it when the MCP could not do what you set out to do).

How discovery works

The advertised tool list is deliberately small: the save_items input schema is an index, not the full contract. Many MCP clients silently drop tools whose schema is too large, so the per-type field contracts are served on demand by describe_tool instead of being advertised up front. The flow an agent should follow:

  1. Connect. The server’s instructions (what your client receives on initialize) are the capability map — every tool, its item types and actions, and what to call next.
  2. describe_tool() — the same capability map plus a short “Designing tracking” guide.
  3. describe_tool(tool:"save_items", type:"<type>", op:"<op>") — the exact fields for the item type and operation you are about to write.
  4. Write with save_items.

If a save_items item carries an unknown field or an out-of-domain value, the error echoes that type’s contract, so an agent can self-correct without a second describe_tool call.

Item type vocabulary

save_items, search, and get share one snake_case entity vocabulary:

Canonical typeUsed by
event, property, metric, categorysearch, get, save_items
event_variant, property_bundlesearch, get, save_items
source, destination, group_type, gatewaysearch, get, save_items
journeysearch, get (read-only)
workspace_configget (takes no id)
branchget
⚠️

Deprecated aliases. The camelCase spellings eventVariant, propertyBundle, groupType, and workspaceConfig are still accepted for one release as aliases of the snake_case types above. They will be removed — use the snake_case spellings in anything you write today.


list_workspaces

Scope: read

List the Avo workspaces the authenticated user has access to. Call this first to discover workspace IDs before invoking any workspace-scoped tool.

Parameters

None.

Returns

One row per workspace: name, workspace ID, and the user’s role.

Examples

Discover the workspaces you can access

Prompt: “What Avo workspaces do I have access to?”

Claude calls list_workspaces with no parameters and uses the returned workspaceId to scope every other tool call in the session.


describe_tool

Scope: none — read-only, rendered locally by the MCP server. No workspace data, no branch, no authentication, no side effects.

The on-demand schema and contract index. Call it to get the exact shape of the call you are about to make: the capability map, the save_items item envelope, the per-type field contract for a given operation, the workflow action parameters, and the search / get vocabularies.

Parameters

All parameters are optional strings. There are no nested objects or unions.

ParameterValuesDescription
toollist_workspaces, describe_tool, search, get, save_items, workflow, give_feedback, list_branchesWhich tool to describe. Omit for the capability map.
typeAn item type (see vocabulary)For save_items: render that type’s field contract.
actioncreate_branch, update_branch_description, pull_main, set_source_language, importFor workflow: render that action’s parameters.
opcreate, update, archive, unarchiveFor save_items: narrow the fields table to one operation.
formatfull (default), conciseconcise returns the fields table only (no placement note, example, or limits line).

Returns

Plain text, shaped by what you asked for:

  • describe_tool() — the capability map (the same text as the server instructions) followed by a “Designing tracking” guide and the link to the avo-mcp plugin. The guide only lives in this response, not in the advertised instructions.
  • describe_tool(tool:"save_items") — the item envelope explanation and a pointer to call again with a type.
  • describe_tool(tool:"save_items", type:"property") — the fields table for that type: one line per field with its name, JSON type, whether it is required, which ops accept it, and a one-line doc. Fields with a closed value set list the accepted values (One of: …); the set object lists its accepted nested keys. Add op:"update" to narrow to one operation.
  • describe_tool(tool:"workflow") — the list of actions. Add action:"<action>" for that action’s parameters and an example call.
  • describe_tool(tool:"search") / describe_tool(tool:"get") — each read tool’s item-type vocabulary, and for get(type:"branch") the accepted include values.
  • Unknown type or action — an error that lists the valid values, so an agent can self-correct from the message alone.

Examples

Learn what a property update accepts before writing one

Prompt: “Rename the product_id property and add two allowed values.”

Before its first property write of the session, Claude fetches the update contract for properties and reads that renames go in set.name while allowed-value changes go in the top-level addAllowedValues.

{
  "tool": "save_items",
  "type": "property",
  "op": "update"
}

The response (abridged):

Fields for property (op: update):
- propertyId (string, required; update/archive/unarchive) — The property's id. Required for update/archive/unarchive.
- addAllowedValues (array; create/update) — Create/update (string property): allowed values to add.
- removeAllowedValues (array; update) — Update only: allowed values to remove …
- isList (boolean; update) — Update: toggle whether the property holds a list of values.
- addCategories (array; update) — Update: category names to attach …
- set (object; update) — Update only: scalar field changes … Nested keys (set.<key>): nameSuffix, description, propertyType, sendAs, name, platform, programmingLanguage, libraryName, libraryDestination, analyticsTool, triggers.

Placement: scalar renames go in set.*; collection deltas at the item top level.
Limits: up to 50 items per call; $tmp: refs resolve within one call.

Get the capability map

Prompt: “What can the Avo MCP do?”

Claude calls describe_tool with no parameters and summarizes the capability map for the user.


Scope: read

Find tracking plan items in one of two modes — the mode is selected automatically by which parameters you pass. Combining query with structural filters returns 400. An empty call (no query, no filter, no branch scope) is rejected. For ID-based lookups use get.

  • Semantic search — pass query to find items by meaning across events, properties, metrics, categories, property bundles, and event variants. Avo embeds each item with OpenAI embeddings and runs a vector-similarity search at query time, so "user signed up" matches Account Created or Registration Completed even when no keyword overlaps.
  • Structured listing — omit query and pass filters to enumerate exact matches with keyset pagination. Pass itemType alone (no query, no filter) to enumerate sources, destinations, group types, gateways, or journeys.
🔒

Semantic search requires Avo Intelligence Smart Search to be enabled in your workspace. Workspace admins can enable it in Workspace Settings. If you don’t have admin access, ask a workspace admin to enable it. Filter-mode listing does not require Smart Search.

Parameters

Shared across modes

ParameterRequiredDescription
itemTypeNoFilter by type: event (default), property, metric, event_variant, category, property_bundle, source, destination, group_type, gateway, or journey. camelCase aliases are accepted but deprecated.
maxResultsNoSemantic mode: 1–20, default 10. Filter mode: 1–500, default 10.
workspaceIdNoWorkspace ID. Repeat it on every page when paginating.

Semantic mode (pass query)

ParameterRequiredDescription
queryYesNatural language search query.

Semantic search is performed against the main branch only. The semantic index may lag slightly for very recently created or updated items.

Filter mode (omit query, pass any of the filter fields)

ParameterRequiredDescription
tagsNoFilter by tag.
categoriesNoFilter by category name.
sourcesNoFilter by source name. Does not apply to metrics.
eventNamesNoFilter by event name. With itemType: "property", returns properties on those events.
variantNamesNoFilter by event variant name.
propertiesNoWith itemType: "event", returns events referencing any of these properties.
includeVariantsNoWith itemType: "event", interleaves each event’s variants in the result set.
stakeholdersNoFilter by stakeholder.
ownersNoFilter by owner.
destinationsNoFilter by destination name.
typeNoWith itemType: "event", filter by event type.
customFieldNoFilter by custom-field name. Resolve valid names from get with type: "workspace_config".
piiNoFilter by PII type. Resolve valid types from get with type: "workspace_config".
nameMappingNoFilter by destination-name-mapping. Tagged object: { kind: "any" } (items with any mapping) or { kind: "matchesAny", names: [...], includeNoMapping?: bool } (items whose mapped name is in names; with includeNoMapping: true items without a mapping rule also pass). Omitting nameMapping means no filter on mapping.
checkpointNoEvent and property listings only. Narrow to items whose data reaches one pipeline location. Tagged object by kind: { kind: "source", sourceId }, { kind: "gatewayInput", gatewayId, inputId }, { kind: "gateway", gatewayId }, { kind: "gatewayOutput", gatewayId, outputId }, or { kind: "destination", destinationId }. An unwired or dangling checkpoint returns no items plus a warning, never an error.
branchIdNoBranch to enumerate on. Defaults to main.
branchNameNoAlternative to branchId.
pageTokenNoPagination token from a previous response.

Multiple values inside one array are OR’d; values across different filter keys are AND’d.

Pagination

Filter-mode responses include a nextPageToken when more results are available, and end with a “Next page” note. To fetch the next page, call search again with the same parameters — workspaceId, itemType, every filter, the branch, maxResults, and checkpoint when you used it — plus pageToken. The token alone is not sufficient: omitting maxResults reverts the page size to the default, and omitting workspaceId can resolve the next page against a different workspace.

Returns

Ranked results with rank, name, type, item ID, relevance percentage, and a truncated description (80 characters). Filter-mode responses include a nextPageToken when more results are available.

{
  "results": [
    {
      "rank": 1,
      "name": "Account Created",
      "itemType": "event",
      "itemId": "evt-9f2b…",
      "relevance": 0.91,
      "description": "Sent when a new account is successfully created."
    },
    {
      "rank": 2,
      "name": "Signup Started",
      "itemType": "event",
      "itemId": "evt-3c11…",
      "relevance": 0.87,
      "description": "Sent when the user opens the signup screen."
    }
  ]
}

Examples

Find events by meaning (semantic)

Prompt: “What events do we have for signup?”

Claude passes the user’s phrasing directly to query. Semantic mode returns events whose meaning matches the query, even when the exact words differ — "user signed up" will match Account Created or Registration Completed.

{
  "query": "user signed up",
  "itemType": "event",
  "maxResults": 5
}

List events using a specific property (filter)

Prompt: “Which events on iOS use the product_id property?”

Filter mode is selected by omitting query. Multiple filter keys are AND’d, so this returns only events that reference product_id and are tracked from the iOS source.

{
  "itemType": "event",
  "properties": ["product_id"],
  "sources": ["iOS"],
  "maxResults": 50
}

Enumerate the workspace’s sources

Prompt: “Which sources do we have?”

{
  "itemType": "source"
}

Common errors

  • query and structural filters combined — returns 400. Choose one mode.
  • Empty call (no query, no filter, no branch scope) — rejected.
  • Smart Search not enabled in the workspace — semantic mode fails; fall back to filter mode or get.
  • Workspace access denied.

get

Scope: read

Get item details for any of four type families:

  • Tracking-plan items — event, property, metric, category, property_bundle, event_variant. Look up by id or exact name. For events, includePropertyDetails: true returns each property’s type, constraints, and allowed values inline. event_variant takes the base event’s id plus variantId.
  • Workspace metadata — source, destination, group_type, gateway. Pass id or name for one item; to enumerate the list, use search with that itemType and no query.
  • Workspace config and journeys — workspace_config (takes no id) returns naming/casing rules, custom-field definitions, and the PII type list; custom-field and PII-type names plug straight into search’s customField and pii filters. journey requires an id (enumerate with search(itemType:"journey")).
  • Branches — branch. Identify with branchId or branchName. Use include to pick content. include defaults to ["overview"].

Defaults to the main branch when no branch is specified.

Parameters

ParameterRequiredDescription
typeYesItem type. One of: event, property, metric, category, property_bundle, source, destination, group_type, gateway, event_variant, workspace_config, journey, branch. camelCase aliases are accepted but deprecated.
idVaries by typeThe item’s unique ID. Required for tracking-plan items unless name is provided; required for journey. Not used by workspace_config.
nameVaries by typeExact name match. Alternative to id for most types. May return multiple matches for ambiguous names (especially properties) — use search for fuzzy lookup.
variantIdFor event_variantThe variant ID. Combined with id (the base event ID).
includeFor branchArray of branch facets to return: overview, all_changes, event_changes, property_changes, code_snippets, implementation_guide. Defaults to ["overview"]. Values are unioned.
sourceIdWhen include contains code_snippetsSource ID to scope the code snippets to.
checkpointNoEvents and properties only. Annotates whether the item’s data reaches one pipeline location — same tagged-object shape as the search checkpoint filter. Never filters the item out, never errors.
branchIdNoBranch to look up on. Defaults to main. branchId takes precedence over branchName.
branchNameNoAlternative to branchId.
includePropertyDetailsNoEvents only. When true, includes full property definitions (type, constraints, allowed values). Defaults to false, which returns only property ID + name references.
includeArchivedNoWhen true (default), includes archived items in results. When false, only active items.
workspaceIdNoWorkspace ID

Returns

Full details for the item, shaped per item type.

  • type: "event" \| "property" \| "metric" \| "category" \| "property_bundle" \| "event_variant" — the item’s full definition. Events, properties, and event variants include owner and stakeholders.
  • type: "source" \| "destination" \| "group_type" \| "gateway" — a single entity.
  • type: "branch" — the facets requested via include. overview returns resolved emails for the creator, reviewers, and collaborators, branch status, impacted source IDs, and description. all_changes (or the narrower event_changes / property_changes) returns the structured diff (new, modified, and deleted items with their properties and descriptions). implementation_guide returns the diff organized for an implementer. code_snippets returns per-event code diffs for the source named in sourceId — exact unified diffs for Avo Codegen sources and illustrative pseudocode for manually-instrumented sources.
  • type: "workspace_config" — the workspace’s event/property naming conventions and casing rules, plus custom field definitions and the list of recognized PII types. Use this before proposing new events or properties so names match the workspace’s audit rules.
  • type: "journey" — the journey’s definition.

Examples

Look up an event by exact name

Prompt: “How is the Account Created event defined?”

Claude calls get with the exact name and includePropertyDetails: true so the response includes each attached property’s type, constraints, and allowed values. Useful when the agent already knows the canonical name and wants the full schema in one call.

{
  "type": "event",
  "name": "Account Created",
  "includePropertyDetails": true
}

Read what changed on a branch

Prompt: “What’s on the checkout-v2 branch — and can you show me the iOS code diff?”

Claude calls get with type: "branch" and combines all_changes and code_snippets in include. sourceId scopes the diff to a single source.

{
  "type": "branch",
  "branchName": "checkout-v2",
  "include": ["all_changes", "code_snippets"],
  "sourceId": "src-ios"
}

Common errors

  • Item not found.
  • Ambiguous name (returns multiple matches — narrow by ID).
  • sourceId missing when include contains code_snippets.
  • Workspace access denied.

save_items

Scope: write · Destructive: archive ops

🚧

Write access is in general beta — enabled for every workspace, no need to request access. Email support@avo.app if you hit anything unexpected.

⚠️

Destructive operations. op: "archive" archives the target item on the branch. Property archives cascade — references on every event that uses the property are also removed. Archives are reversible (op: "unarchive", or from the Avo web app), but the cascade means a single call can touch many events.

Batch create, update, archive, and unarchive tracking-plan items on a branch: events, properties, event variants, property bundles, metrics, categories, sources, destinations, group types, and gateways. A single call can mix item types and operations, and can cross-reference new items via temporary IDs.

💡

Before your first write of a type in a session, call describe_tool with tool:"save_items", the type, and the op. The advertised save_items schema only describes the item envelope; the per-type fields live in the describe_tool response, and the tables below are a snapshot of it.

Parameters

Top-level

ParameterRequiredDescription
branchIdYesThe branch to write to. Get it from workflow (action: "create_branch"). Writes on main are rejected.
itemsYesArray of item envelopes to apply (see below).
onReviewedBranchNoAcknowledgement for writing to a branch that is already in review. Omitted → the write is rejected so approvals aren’t silently invalidated. { kind: "revertToDraft" } reverts the branch to Draft and applies the edits; { kind: "reject" } is the default.
workspaceIdNoWorkspace ID

The request is capped at 50 items per call.

Item envelope

Every item has the same six-key shape. The type-specific content goes inside fields:

{ "op": "create", "type": "event", "id": "…", "name": "…", "tempId": "…", "fields": { } }
KeyTypeNotes
op"create" | "update" | "archive" | "unarchive"Defaults to "create". Every op applies to every type.
typestringRequired. One of event, property, event_variant, property_bundle, metric, destination, source, group_type, category, gateway. camelCase aliases are accepted but deprecated.
idstringThe identity ID for update / archive / unarchive on single-ID types — see the table below. You may pass it here or as the type’s ID field inside fields; passing both with different values is rejected. event_variant has a compound identity and passes baseEventId + variantId inside fields instead.
namestringRequired on every create. Cosmetic on other ops.
tempIdstringCreate only. A temporary handle (letters, digits, _, -; max 64 characters) for cross-referencing inside the same call. Reference it elsewhere as "$tmp:<tempId>".
fieldsobjectThe type-specific fields for this (type, op) — exactly what describe_tool renders. Omit or pass null when the op needs nothing beyond the identity.

Identity ID per type (for update / archive / unarchive):

TypeID field
eventeventId
propertypropertyId
metricmetricId
categorycategoryId
property_bundlepropertyBundleId
sourcesourceId
destinationdestinationId
group_typegroupTypeId
gatewaygatewayId
event_variantbaseEventId + variantId (both in fields, on every op)

Inside fields, three placement rules apply to every type:

  • Scalar edits go in set (update only). set is a nested object with a closed key set: name, description, nameSuffix, propertyType, sendAs, platform, programmingLanguage, libraryName, libraryDestination, analyticsTool, triggers. Not every key applies to every type; unknown keys are rejected. set.sendAs is accepted only on create — a property’s sendAs is immutable after creation.
  • Collection changes stay at the top level of fields — addProperties / removeProperties, addCategories / removeCategories, addAllowedValues / removeAllowedValues, and every other add* / remove* / clear* field.
  • description is create-only, and only for types whose create reads it: event, property, event_variant, property_bundle, metric, category. A create for a source, destination, group_type, or gateway that carries description is rejected. On update, use set.description.

Validation is strict. An unknown key in fields, a field the current op doesn’t accept (set on a create, description or tempId on an update, removeAllowedValues on a create), or a value outside a field’s domain is rejected up front. The error names the (type, op) and echoes the type’s field contract.

Field contracts by type

The tables below are the describe_tool(tool:"save_items", type:"<type>") output at the time of writing. The live response is authoritative. Fields marked create/update are accepted on both ops; the identity ID field is required on update / archive / unarchive. tempId (create only) and set (update only) apply to every type and are omitted from the tables.

event

FieldOpsNotes
eventIdupdate, archive, unarchiveThe event’s ID (or $tmp: of a same-batch create).
descriptioncreateEvent description.
sourcescreateSource IDs to include the event in. ID or $tmp: only.
propertiescreateProperty IDs to attach. ID or $tmp: only.
propertyBundlescreateProperty bundle IDs to attach. ID or $tmp: only.
actionscreateInitial action types (identify, page, revenue, …). Omit for logEvent only.
nameComponentscreateAdvanced-naming workspaces: per-building-block name values.
tagscreateTag names to attach (literal strings).
addProperties / removePropertiesupdateProperty IDs (or $tmp:) to add / remove.
addSources / removeSourcesupdateSource IDs to include / exclude.
setSourceCodegenupdateSet the per-source include-in-codegen flag.
addSourceDestinations / removeSourceDestinationsupdateLink / unlink (source, destination) pairs on the event.
setActionsupdateReplace the event’s action types.
customFieldValuesupdateSet or clear per-custom-field values.
addCategories / removeCategoriesupdateCategory names (or $tmp: to a same-batch category). The event must already exist — attaching a category to an event created in the same batch is rejected; do it in a follow-up call.
addTags / removeTagsupdateTag names to attach / detach.
addGroupTypes / removeGroupTypesupdateGroup type names (name or $tmp:, not raw IDs).
addPropertyBundles / removePropertyBundlesupdateProperty bundle IDs to attach / detach.
nameMappingscreate/updatePer-destination name mapping entries — see Name mappings.
owner, stakeholderscreate/updateSee Owner and stakeholder fields.
set.name, set.descriptionupdateRename (renaming to a name already held by another live event is rejected) / new description.

property

FieldOpsNotes
propertyIdupdate, archive, unarchiveThe property’s ID.
descriptioncreateProperty description.
propertyTypecreatestring, int, long, float, bool, object, any (aliases like integer, boolean, double accepted). Change later with set.propertyType.
sendAscreateevent, user, or system. Immutable after create.
nestedPropertiescreateObject property: child-property slots { propertyId, … }.
tagscreateTag names to attach.
addAllowedValuescreate/updateString property: allowed values to add.
removeAllowedValuesupdateAllowed values to remove. Rejected on a create.
eventConfigscreate/updatePer-event property settings — see Per-event property settings. Max 50 entries.
customFieldValuescreate/updateSet or clear per-custom-field values.
piicreate/updateThe property’s PII state: { kind: "declared" | "notPii" | "unset" }.
nameMappingscreate/updateSee Name mappings.
isListupdateBoolean — toggle between scalar (false) and list (true).
addNestedProperties / removeNestedPropertiesupdateObject property: child-property slots to add / child-property IDs to detach (live IDs only, no $tmp:).
addPropertyRegex / removePropertyRegexupdateSet the global regex rule { regex, testValue } / pass true to remove it.
addEventRegexOverride / removeEventRegexOverrideupdateSet an event-specific regex override { eventId, regex, testValue } / the event ID whose override to remove.
addCategories / removeCategoriesupdateCategory names (or $tmp:). The property must already exist.
addTags / removeTagsupdateTag names to attach / detach.
owner, stakeholderscreate/updateSee Owner and stakeholder fields.
set.name, set.description, set.propertyTypeupdateRename / new description / new type.

event_variant

FieldOpsNotes
baseEventIdallThe parent event’s ID (or $tmp:). Required on every op.
variantIdallThe variant’s ID — you supply it on create (must not contain .). Required on every op.
descriptioncreateVariant description.
nameSuffixcreateSuffix appended to the parent event name (e.g. buy_now produces click / buy_now). Change later with set.nameSuffix.
attachPropertiescreate/updateProperty IDs (or $tmp:) to attach to this variant.
overridescreateComponent-level overrides { propertyId, pinned } or { propertyId, allowed }.
bundleOverridescreateBundle IDs to attach to this variant.
addComponentOverrides / removeComponentOverridesupdateComponent override specs to add or replace / property IDs whose overrides to clear.
removePropertiesupdateProperty IDs to set as explicit not-on-variant overrides.
clearAttachedPropertiesupdateProperty IDs whose attachment override is cleared (inherit from base).
addSourceOverrides / removeSourceOverrides / clearSourceOverridesupdateSource-level overrides to force-add / force-remove / reset to inherit.
addBundleOverrides / removeBundleOverrides / clearBundleOverridesupdateBundle IDs to force-add / force-remove / reset to inherit.
addVariantPropertyRegexupdateSet a variant regex override { propertyId, regex, testValue }.
removeVariantPropertyRegexupdateProperty ID set to explicit no-regex on the variant.
clearVariantPropertyRegexOverrideupdateProperty ID whose variant regex override is cleared (inherit).
owner, stakeholderscreate/updateSee Owner and stakeholder fields.
set.nameSuffix, set.description, set.triggersupdateNew suffix / description / replace the trigger list.

The override surface is a three-state lattice — add* / remove* / clear* — for attached properties, source overrides, bundle overrides, and regex overrides. Use add* / remove* for explicit overrides; use clear* to fall back to the base event.

property_bundle

FieldOpsNotes
propertyBundleIdupdate, archive, unarchiveThe bundle’s ID.
descriptioncreateBundle description.
addPropertiescreate/updateProperty IDs (or $tmp:) to add to the bundle.
attachToEventscreateEvent IDs (or $tmp:) to attach the new bundle to.
removePropertiesupdateProperty IDs to remove from the bundle.
set.name, set.descriptionupdateRename / new description.

Bundle-to-event attachment after creation is managed from the event side via addPropertyBundles / removePropertyBundles on an event update.

metric

FieldOpsNotes
metricIdupdate, archive, unarchiveThe metric’s ID.
descriptioncreateMetric description.
metricTypecreateOne of Funnel, EventSegmentation, Proportion, Retention, CustomEvent, Cohort. Immutable after create — archive and recreate to change.
itemscreateNon-cohort metrics: array of metric items. Each is { kind: "Event", id, eventId, where?, groupBy? }, { kind: "EventVariant", id, baseEventId, variantId, where?, groupBy? }, or { kind: "Metric", id, metricId }. id is a caller-supplied local key used to address the item in later updates; eventId / baseEventId / metricId accept $tmp:. where entries are { propertyId, operator, values } with a non-empty values.
cohortConditionscreateCohort metrics: array of conditions — { kind: "Action", id?, eventId, performed, frequency, timeWindow } or { kind: "Variable", id?, propertyId, binOp, literals }.
setName / setDescriptionupdateRename / new description (metrics use these top-level fields).
addItems / updateItems / removeItemsupdateNon-cohort metrics: add items / replace an item’s where and groupBy by ID / remove item IDs.
addCohortConditions / updateCohortConditions / removeCohortConditionsupdateCohort metrics: manage the condition list.
addCategories / removeCategoriesupdateCategory names to attach / detach.

category

FieldOpsNotes
categoryIdupdate, archive, unarchiveThe category’s ID.
descriptioncreateCategory description.
set.name, set.descriptionupdateRename / new description.

Category membership is managed from the member side: addCategories / removeCategories on event, property, and metric updates.

source

FieldOpsNotes
sourceIdallRequired on update / archive / unarchive. On create, supply sourceId or a tempId.
platformcreate (required)The development platform this source runs on. Change later with set.platform.
programmingLanguagecreateThe source’s programming language. Change later with set.programmingLanguage (or workflow set_source_language).
libraryName / libraryDestinationcreateCodegen library name / output path. Change later via set.*.
connectDestinationsupdateDestination IDs (or $tmp:) to connect for codegen routing on the source.
disconnectDestinationsupdateDestination IDs to disconnect. Destructive — cascades to every event routing it on this source (and inheriting variants).
set.name, set.platform, set.programmingLanguage, set.libraryName, set.libraryDestinationupdateScalar edits.

A create for a source does not accept description.

destination

FieldOpsNotes
destinationIdallRequired on update / archive / unarchive. On create, supply destinationId or a tempId.
analyticsToolcreate (required)The analytics platform this destination connects to. Change later with set.analyticsTool.
includeUserPropsWithEventPropscreate/updateBoolean. Defaults to false on create.
disabledByDefaultcreate/updateBoolean — new events are disabled for this destination by default. Defaults to false on create.
apiKeyupdateSet or remove an API key for an environment { kind, env, value? }.
set.name, set.analyticsToolupdateScalar edits.

A create for a destination does not accept description.

group_type

FieldOpsNotes
groupTypeIdallRequired on update / archive / unarchive. On create, supply groupTypeId or a tempId.
set.nameupdateRename.

A create for a group type does not accept description. Attach group types to events with addGroupTypes on an event update.

gateway

🔒

Gateways are gated by a per-workspace feature. A gateway write returns 403 when the workspace does not have gateways enabled.

FieldOpsNotes
gatewayIdupdate, archive, unarchiveThe gateway’s ID. A create is server-minted, so no gatewayId is supplied then.
inputscreateInput checkpoints, each { sourceId? } (ID or $tmp:; omit or null for an unwired input).
outputscreateOutput checkpoints, each { destinationId? } (ID or $tmp:; omit or null for an unwired output).
addInputs / removeInputsupdateInput checkpoints to add, each { sourceId? } / input-checkpoint IDs to remove.
addOutputs / removeOutputsupdateOutput checkpoints to add, each { destinationId? } / output-checkpoint IDs to remove.
setInputOrigins / setOutputTargetsupdateRe-point existing checkpoints: { inputId, sourceId? } / { outputId, destinationId? }.
outputIdupdateApply this item’s transformation keys at one output checkpoint (an output ID from get, or $tmp: of a same-batch outputs / addOutputs entry) instead of at the gateway itself. Has no meaning without transformation keys.
addTransformationPropertiesupdateUpsert per-property overrides at the gateway (or at outputId). Each { propertyId, pinned?, absence?, disallowedValues?, regex?, nameMapping? }; a bare { propertyId } inherits every dimension. pinned / regex null = explicitly none; nameMapping is { kind: "set" | "clear" }. disallowedValues are add-only and must already be allowed values of the property.
removeTransformationPropertiesupdateProperty IDs to stop sending from this checkpoint on.
clearTransformationPropertiesupdateProperty IDs whose overrides are removed at this checkpoint (back to inherit). The only way to drop a disallowed value: clear, then re-add the overrides you still want.
addTransformationPropertyBundles / removeTransformationPropertyBundles / clearTransformationPropertyBundlesupdateProperty-bundle IDs to include / stop sending / reset to inherit at this checkpoint. $tmp: works for a bundle created in the same batch.
setTransformationEventNamesupdateRename events as sent from this checkpoint on. Each { eventId, sendAs }.
removeTransformationEventNamesupdateEvent IDs whose send-as rename is removed (back to the event’s own name).
set.nameupdateRename.

A property ID may appear in only one of add / remove / clear transformation fields per item. A create for a gateway does not accept description.

Name mappings

nameMappings is accepted on event and property items, on create and update. Each entry is { destination, name }, where destination is { kind: "allDestinations" } or { kind: "destination", destinationId: "…" }. name must be a non-empty string when present; pass name: null (or omit it) to remove the mapping for that destination. On a create there is nothing to remove yet, so a name: null entry is a harmless no-op. Multiple entries are allowed, one per destination scope.

Owner and stakeholder fields

⚠️

Branch-independent. Owner and stakeholder assignments take effect immediately workspace-wide, even if the branch is later discarded. Discarding the branch will not roll back these changes. Treat these fields as out-of-branch mutations, not draft edits.

owner and stakeholders are accepted inside fields on event, property, and event variant items (both create and update):

FieldNotes
owner{ action: "set", stakeholder } sets the owning stakeholder; { action: "clear" } removes it. Stakeholders are created in the Avo web app — the MCP does not create them.
stakeholders{ add?: [...], remove?: [...] } — stakeholder references to add or remove as collaborators.

Merging categories

The MCP has no dedicated “merge categories” op. To merge category A into category B, send a single save_items batch containing:

  1. An update item for every event, property, and metric in A carrying fields: { addCategories: ["B"], removeCategories: ["A"] }.
  2. A { op: "archive", type: "category", id: "<id of A>" } item.

Both must travel in the same batch — archiving a category does not cascade to its members, so step 1 has to move the members first.

Per-event property settings (eventConfigs)

eventConfigs is an array inside fields on a property item (create or update; max 50 entries). Each entry adjusts how the property behaves on a specific event, on several events, or across all events:

  • setPresence — change presence to alwaysSent, sometimesSent, or neverSent. Can be scoped per source. sometimesSent on allEvents requires a migrated workspace.
  • setPinnedValue — pin a value for the property. With events: { kind: "onEvent" } pins per event; with events: { kind: "allEvents" } pins property-wide.
  • restrictAllowedValues — change the property’s allowed value list for an event. Carries a valuesChange delta: addValues (non-empty), removeValues, or clear (no payload).

Per-event scopes (events.kind = "onEvent" / "onEvents") name events by persisted ID or $tmp: reference, on update and create. On a create, the batch must also attach the property to the referenced event (via $tmp:), otherwise the reference is unresolvable. allEvents entries apply to the freshly created property directly.

Temporary IDs (tempId / $tmp:)

To reference a newly created item from another item in the same call, declare a tempId on the create envelope and reference it elsewhere as "$tmp:<name>":

  • tempId is create-only — setting it on an update, archive, or unarchive returns an error.
  • tempId names must be unique within a single save_items call and match ^[\w-]+$ (max 64 characters).
  • $tmp: references resolve within one call only. Across calls, use the real ID returned from the previous call.
  • ID fields that accept $tmp: are ID-or-$tmp: only — a literal name is rejected. Fields that take names (addCategories / removeCategories, addGroupTypes / removeGroupTypes) rewrite a $tmp: ref to the sibling create’s name instead.
  • Sources and destinations created in the same batch can be referenced by $tmp: too, since save_items creates those types.
  • If a $tmp: ref names a tempId that wasn’t declared on any item, the server returns a validation error.

Returns

A structured result with:

  • createdEntities, updatedEntities, removedEntities, unarchivedEntities — each entry has name, entityId, and entityType. Created entries also echo the tempId you supplied, so you can map temporary handles to real IDs.
  • errors — per-item validation or audit errors, each with the item index, name, and a message.
  • warnings — non-fatal notices, same shape as errors.
  • success — overall boolean.
{
  "success": true,
  "createdEntities": [
    { "name": "Checkout Method", "entityId": "prop-9d44…", "entityType": "property", "tempId": "checkout_method" }
  ],
  "updatedEntities": [
    { "name": "Checkout Completed", "entityId": "evt-3f01…", "entityType": "event" }
  ],
  "removedEntities": [],
  "unarchivedEntities": [],
  "errors": [],
  "warnings": []
}

Examples

Create a new event with a new property in one call

Prompt: “Add a Checkout Completed event with a Checkout Method property for Web and iOS.”

Claude declares a tempId on the new property so the new event can attach it before the server has allocated a real ID. The server resolves the $tmp: reference, allocates the real propertyId, attaches the property to the event, and includes the event in both sources — all atomically.

{
  "branchId": "br-abc123",
  "items": [
    {
      "op": "create",
      "type": "property",
      "tempId": "checkout_method",
      "name": "Checkout Method",
      "fields": {
        "description": "How the user completed checkout",
        "propertyType": "string",
        "sendAs": "event",
        "addAllowedValues": ["Card", "Apple Pay", "PayPal"]
      }
    },
    {
      "op": "create",
      "type": "event",
      "name": "Checkout Completed",
      "fields": {
        "description": "Sent when a user successfully pays and their order is placed.",
        "properties": ["$tmp:checkout_method"],
        "sources": ["src-web", "src-ios"]
      }
    }
  ]
}

Rename a property and add an allowed value

Prompt: “Rename user_email to email and allow the value Unknown on Checkout Method.”

Scalar edits go in set; collection changes stay at the top level of fields.

{
  "branchId": "br-abc123",
  "items": [
    {
      "op": "update",
      "type": "property",
      "id": "prop-1a2b…",
      "fields": { "set": { "name": "email" } }
    },
    {
      "op": "update",
      "type": "property",
      "id": "prop-9d44…",
      "fields": { "addAllowedValues": ["Unknown"] }
    }
  ]
}

Define a checkout funnel metric

Prompt: “Add a funnel metric on this branch that tracks the share of users who start checkout and complete it.”

Claude creates a Funnel metric whose items reference two existing events in order. The same call could chain in new events with $tmp: references if the funnel needed events that don’t exist yet.

{
  "branchId": "br-abc123",
  "items": [
    {
      "op": "create",
      "type": "metric",
      "name": "Checkout Funnel",
      "fields": {
        "description": "Share of users who start checkout and complete it.",
        "metricType": "Funnel",
        "items": [
          { "kind": "Event", "id": "step1", "eventId": "evt-checkout-started" },
          { "kind": "Event", "id": "step2", "eventId": "evt-checkout-completed" }
        ]
      }
    }
  ]
}

Archive an event

{
  "branchId": "br-abc123",
  "items": [
    { "op": "archive", "type": "event", "id": "evt-3f01…" }
  ]
}

Common errors

  • Missing write scope — the client must re-authorize with write.
  • branchId is required / items is required — malformed request.
  • Unknown field, wrong-op field, or out-of-domain value in fields — the error names the (type, op) and echoes the type’s contract. Call describe_tool with that type and op.
  • name missing on a create.
  • tempId is only valid on create items — don’t set tempId on update, archive, or unarchive.
  • Duplicate tempId "<name>" — each tempId must be unique across items in the batch.
  • Unknown $tmp: reference — a $tmp: ref names a tempId that wasn’t declared.
  • <idField> is required for <op> <entity> items — missing identity ID.
  • id and fields.<idField> both present with different values.
  • too many items (got N, max 50) — batch is over the 50-item cap.
  • 403 on a gateway write — the workspace does not have gateways enabled.
  • Per-item audit-pipeline validation failures (e.g. illegal name, duplicate property) — returned inside the errors array rather than failing the whole call.

workflow

Scope: write

🚧

Write access is in general beta — enabled for every workspace, no need to request access. Email support@avo.app if you hit anything unexpected.

Branch-lifecycle write operations, dispatched by action:

ActionWhat it does
create_branchOpen a new branch off main.
update_branch_descriptionSet the description on an existing open branch.
pull_mainMerge the latest main into a branch.
set_source_languageSet a source’s programming language on a branch.
importImport a tracking plan document (CSV or JSON Schema) into a branch.

Call describe_tool with tool:"workflow" and an action for that action’s parameters and an example call.

💡

A branch is a draft workspace for tracking-plan changes, analogous to a git branch. All write operations via the MCP happen on a branch — save_items requires a branchId that exists. The MCP never merges to main; open the branch in the Avo app to review and merge.

Parameters

ParameterRequiredDescription
actionYesOne of the actions above.
branchNamecreate_branch (required); alternative to branchId for update_branch_description and set_source_languageThe new branch’s name, or an existing branch’s name.
branchIdpull_main, import (required); alternative to branchName elsewhereThe existing branch’s ID. Where both are accepted, provide exactly one. Never main.
descriptioncreate_branch (optional); update_branch_description (required)The branch description. Blank is a no-op on update.
sourceIdset_source_languageThe source to change. Enumerate sources with search(itemType:"source").
languageset_source_languageOne of JavaScript_V2, Reason_V2, Java, Swift, JSON, Python, Python3, PHP, Kotlin, C#, TypeScript, Objective-C, Ruby, Dart, Go. Validated against the source’s platform.
formatimport"csv" or "json_schema".
importMethodimport"add_only", "add_and_update", or "add_update_and_remove".
payloadimportThe CSV or JSON Schema document, as a string.
workspaceIdNoWorkspace ID

Returns

For create_branch: the new branch’s branchId, branchName, and a branchUrl that opens it in the Avo web app. For update_branch_description: confirmation with the resolved branchId and the updated description. The other actions return a confirmation of what changed on the branch.

Examples

Create a branch for a new feature

Prompt: “Start an Avo branch for the new checkout flow we’re shipping next sprint.”

Claude calls workflow with action: "create_branch" and a descriptive branchName. The returned branchId is required for the follow-up save_items calls that write the new events and properties.

{
  "action": "create_branch",
  "branchName": "add-checkout-tracking"
}

Update a branch’s description

Prompt: “Update the description on the add-checkout-tracking branch to mention that we’re now also tracking abandonment.”

Claude looks up the branch by name (no separate branchId lookup needed for this action) and replaces the description in one call.

{
  "action": "update_branch_description",
  "branchName": "add-checkout-tracking",
  "description": "Adds the Checkout Completed and Checkout Abandoned events with the Checkout Method property."
}

Import a JSON Schema tracking plan into a branch

{
  "action": "import",
  "branchId": "br-abc123",
  "format": "json_schema",
  "importMethod": "add_and_update",
  "payload": "{ \"$schema\": … }"
}

Common errors

  • Missing write scope — re-authorize with write.
  • Workspace access denied.
  • Unsupported action value — the error lists the valid actions.
  • Both branchId and branchName provided where exactly one is expected.
  • language not valid for the source’s platform.

list_branches

Scope: read

🚧

Transitional. This tool stays available while branch enumeration is being folded into search with type: "branch". Until that ships, use list_branches to enumerate branches.

Browse branches in a workspace with filtering and pagination. Results are paginated newest-first.

Parameters

ParameterRequiredDescription
workspaceIdNoWorkspace ID
branchStatusesNoFilter by status. Valid values: Draft, ReadyForReview, ChangesRequested, Approved, Merged, Closed, Open. Defaults to open/active branches only.
pageSizeNoResults per page, default 25. Clamped to 1–50 (an out-of-range value is coerced, not rejected).
pageTokenNoPagination token from a previous response
branchNameNoSubstring match on branch name (case-insensitive)
creatorEmailNoFilter by creator email
creatorUserIdNoFilter by creator user ID
reviewerEmailNoFilter by reviewer email
reviewerUserIdNoFilter by reviewer user ID
collaboratorEmailNoFilter by collaborator email
collaboratorUserIdNoFilter by collaborator user ID
createdAfterNoISO 8601 date — only branches created after
createdBeforeNoISO 8601 date — only branches created before
impactedSourceIdNoFilter to branches affecting a specific source

By default Merged and Closed branches are excluded. Pass branchStatuses: ["Merged"] (or any other value) to include them.

💡

To find “my branches,” pass your own email as creatorEmail or reviewerEmail. The tool does not auto-inject your identity into the filter.

Returns

Compact per-branch summary — name, status, ID, creator email — plus a nextPageToken when more results are available. Call get with type: "branch" and include: ["overview"] for full resolved data.

Examples

Find branches I’m reviewing

Prompt: “What branches am I assigned to review?”

Claude passes the user’s email as reviewerEmail and filters status to ReadyForReview. The tool does not auto-inject the caller’s identity, so the email has to be supplied explicitly.

{
  "reviewerEmail": "thora@avo.sh",
  "branchStatuses": ["ReadyForReview"]
}

Common errors

  • Workspace access denied.
  • Invalid date format on createdAfter / createdBefore.

Troubleshooting

Tool-specific behavior issues. Authentication and workspace access issues are covered in Troubleshooting on the overview page.

search returns nothing for a clearly relevant query. Semantic search requires Avo Intelligence Smart Search to be enabled. Workspace admins can turn it on in Workspace Settings. Without it, fall back to get with an exact name or search in filter mode.

The wrong branch is returned by name. branchName resolves to a best match and prioritizes open branches, so an ambiguous name can pick the wrong one. Resolve the name to a branchId with list_branches first and pass branchId to the follow-up call.

save_items rejects an item with a contract in the error. The item carried a field that type or op does not accept, or a top-level field that belongs inside fields. Read the echoed contract, or call describe_tool with the same type and op, and retry. Older examples that put fields like propertyType directly on the item (outside fields) no longer work.

My client does not show save_items at all. Some MCP clients drop tools whose advertised schema exceeds their size limits. The Avo MCP keeps every advertised schema small precisely so this does not happen; if it still does, make sure the client is talking to https://mcp.avo.app/mcp and report it to support@avo.app.