Avo MCP tools reference
Every tool except list_workspaces 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 five canonical tools mapped to agent intents:
| Intent | Tool | Scope |
|---|---|---|
| Entry point — find your workspace IDs | list_workspaces | read |
| Discover — find items by meaning or by structural filter | search | read |
| Understand — full details for an event, property, branch, source, etc. | get | read |
| Change — create, update, archive, or restore items on a branch | save_items | write |
| Progress — create a branch, update its description, pull main, set a source’s language, or bulk-import a plan | workflow | write |
Branch read flows are covered by get and search. One transitional tool — list_branches — remains available while branch enumeration is folded into search (as itemType: "branch").
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.
search
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 is rejected (the tool returns an error message, not an HTTP status) — pick one mode. branch and pageToken are filter-mode only and likewise cannot be combined with query. For ID-based lookups use get.
- Semantic search — pass
queryto 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"matchesAccount CreatedorRegistration Completedeven when no keyword overlaps. - Structured listing — omit
queryand pass filters to enumerate exact matches with keyset pagination.
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
| Parameter | Required | Description |
|---|---|---|
itemType | No | Filter by type: event (default), property, metric, category, propertyBundle, eventVariant, source, destination, or groupType. The workspace-metadata types (source / destination / groupType) enumerate the workspace list and are only valid in filter mode (omit query). |
maxResults | No | Semantic mode: 1–20, default 10. Filter mode: 1–500, default 10. |
workspaceId | No | Workspace ID. |
Semantic mode (pass query)
| Parameter | Required | Description |
|---|---|---|
query | Yes | Natural 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)
| Parameter | Required | Description |
|---|---|---|
tags | No | Filter by tag. |
categories | No | Filter by category name. |
sources | No | Filter by source name. Does not apply to metrics. |
eventNames | No | Filter by event name. With itemType: "property", returns properties on those events. |
variantNames | No | Filter by event variant name. |
properties | No | With itemType: "event", returns events referencing any of these properties. |
includeVariants | No | With itemType: "event", interleaves each event’s variants in the result set. |
stakeholders | No | Filter by stakeholder. |
owners | No | Filter by owner. |
destinations | No | Filter by destination name. |
type | No | With itemType: "event", filter by event type. |
customField | No | Filter by custom-field name. Resolve valid names from get with type: "workspaceConfig". |
pii | No | Filter by PII type. Resolve valid types from get with type: "workspaceConfig". |
nameMapping | No | Filter 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. |
branch | No | Branch ID to enumerate items on. Defaults to main. (Filter mode only — there is no branchName alias on search; resolve a name to an ID with list_branches first.) |
pageToken | No | Pagination token from a previous response. |
Multiple values inside one array are OR’d; values across different filter keys are AND’d.
Returns
A Markdown document (not JSON) — a # Search Results heading, a result count, and a ranked table. Rows are ordered best-match first; there is no relevance score (ranking uses a fused rank, not an intuitive 0–100% relevance). Descriptions are truncated to ~80 characters.
- Semantic mode columns:
Rank | Name | Type | Item ID | Branch | Description. - Filter mode columns:
Rank | Name | Type | Item ID | Description— event-variant rows instead useRank | Name | Base Event | Variant ID | Description.
In filter mode, when more results are available the document ends with a Next page instruction: call search again with the same itemType / filters / branch plus the supplied pageToken (the token alone is not enough — you must repeat the original filters). Any filters that were ignored or coerced are listed under a Filter warnings section.
# Search Results
Found 2 results for "user signed up"
| Rank | Name | Type | Item ID | Branch | Description |
|------|------|------|---------|--------|-------------|
| 1 | **Account Created** | event | evt-9f2b… | main | Sent when a new account is successfully created. |
| 2 | **Signup Started** | event | evt-3c11… | main | 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
}Common errors
queryand structural filters combined — rejected with an error (no HTTP status). Choose one mode.querycombined withbranchorpageToken— rejected; those are filter-mode-only parameters.- 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,propertyBundle,eventVariant. Look up byidor exactname— excepteventVariant, which is identified by the base event’sidplusvariantId(never by name). For events,includePropertyDetails: truereturns each property’s type, constraints, and allowed values inline. - Workspace metadata —
source,destination,groupType.getreturns a single item, so passidorname. To enumerate the workspace list, usesearch(itemType: "source"/"destination"/"groupType"). - Workspace config —
workspaceConfig. Naming/casing rules and event/property validation rules (with the enforcement point), custom-field definitions, the PII type list, and the workspace’s tags and categories. Custom-field and PII-type names plug straight intosearch’scustomFieldandpiifilters. - Branches —
branch. Identify withbranchIdorbranchName. Useincludeto pick content:"overview"(branch metadata + baseline status + resolved creator/reviewer/collaborator emails + impacted sources + comments/approvals stats),"all_changes"(full diff vs. main, like the web branch screen),"event_changes"(events + event variants only),"property_changes"(properties + property bundles + categories only),"code_snippets"(per-source generated code; requiressourceId),"implementation_guide"(numbered implementation steps + per-event codegen instructions). Multiple values union, andevent_changes+property_changesequalsall_changes.includedefaults to["overview"].
Defaults to the main branch when no branch is specified.
Parameters
| Parameter | Required | Description |
|---|---|---|
type | Yes | Item type. One of: event, property, metric, category, propertyBundle, source, destination, groupType, eventVariant, branch, workspaceConfig. |
id | Varies by type | The item’s unique ID. Required for event, property, metric, category, propertyBundle unless name is provided. For source/destination/groupType, provide id or name — get is single-item only, so enumerate with search instead. eventVariant uses id (the base event ID) plus variantId, not name. For branch, identify with branchId/branchName (id/name are not branch identifiers; omitting both errors). Not used by workspaceConfig. |
name | Varies by type | Exact name match. Alternative to id for most types. May return multiple matches for ambiguous names (especially properties) — use search for fuzzy lookup. |
variantId | For eventVariant | The variant ID. Combined with id (the base event ID). |
include | For branch | Array of branch facets to return: overview, all_changes, event_changes, property_changes, code_snippets, implementation_guide. Defaults to ["overview"]. Multiple values union. The deprecated value changes is accepted as an alias for all_changes. Unknown values are dropped with a warning. Combine all_changes and code_snippets (or use implementation_guide) for an implementer-ready picture of the branch. |
sourceId | Required for code_snippets; optional elsewhere | Source ID to scope branch content. Required when include contains code_snippets (single-source in v1). Optional on all_changes / event_changes / property_changes / implementation_guide: it filters event-shaped diffs to one source (property, bundle, and category diffs stay workspace-wide) and gates the per-event codegen instructions in implementation_guide. Find source IDs with search (itemType: "source"). |
branchId | No | Branch to look up on. Defaults to main. branchId takes precedence over branchName. |
branchName | No | Alternative to branchId. |
includePropertyDetails | No | Events only. When true, includes full property definitions (type, constraints, allowed values). Defaults to false, which returns only property ID + name references. |
includeArchived | No | When true (default), includes archived items in results. When false, only active items. |
workspaceId | No | Workspace ID |
Returns
Full details for the item, shaped per item type.
type: "event" \| "property" \| "metric" \| "category" \| "propertyBundle" \| "eventVariant"— the item’s full definition.type: "source" \| "destination" \| "groupType"— a single entity;idornameis required (enumerate the workspace list withsearch).type: "branch"— branch facets requested viainclude.overviewreturns resolved emails for the creator, reviewers, and collaborators, branch status, impacted source IDs, comments/approvals stats, and description.all_changesreturns the full structured diff vs. main (new, modified, and deleted events and properties with their descriptions);event_changesandproperty_changesreturn just the event- or property-side of that diff.code_snippetsreturns per-event code diffs for the source named insourceId— exact unified diffs for Avo Codegen sources and illustrative pseudocode for manually-instrumented sources.implementation_guidereturns numbered implementation steps plus per-event codegen instructions (scoped tosourceIdwhen provided).type: "workspaceConfig"— the workspace’s event/property naming conventions and casing rules, the event and property validation rules (with their severities and the enforcement point — where Avo blocks), custom field definitions, the list of recognized PII types, and the workspace’s tags and categories listings. Use this before proposing new events or properties so names match the workspace’s audit rules.
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).
sourceIdmissing whenincludecontainscode_snippets.- Workspace access denied.
save_items
Scope: write · Destructive: archive (and legacy remove)
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, and op: "unarchive" restores it. Archiving a property cascades — references on every event that uses the property are also removed. All archives are reversible from the Avo web app, but the cascade means a single call can touch many events.
Batch create, update, archive, and unarchive events, properties, event variants, property bundles, metrics, categories, sources, destinations, and group types on a branch. A single call can mix item types and operations, and can cross-reference new items via temporary IDs.
Quick reference. Common patterns:
- Create an event with new properties — pair
create-eventandcreate-propertyitems in one batch, usingtempIdto cross-reference. - Add allowed values to a property —
update-propertywith top-leveladdAllowedValues. - Rename an event or property —
update-event/update-propertywithset.name. - Archive an event —
op: "archive"(or legacyop: "remove"). - Create a funnel metric —
create-metricwithmetricType: "Funnel"anditems. - Toggle a property between scalar and list —
update-propertywith top-levelisList: true/false.
Parameters
Top-level
| Parameter | Required | Description |
|---|---|---|
branchId | Yes | The branch to write to. Get it from workflow (action: "create_branch"). |
items | Yes | Array of items to apply. Each item is typed by its type field and has an op (default create). |
workspaceId | No | Workspace ID |
The request is capped at 50 items per call.
Item shape
Every item shares these fields:
| Field | Type | Notes |
|---|---|---|
op | "create" | "update" | "archive" | "unarchive" | Defaults to "create". "archive" archives an item (recoverable) and "unarchive" restores it — both apply uniformly to every archivable type (event, event_variant, metric, property, property_bundle, category, source, destination, groupType). "remove" is a legacy alias accepted only for events and properties (behaves as archive); on any other type "remove" is rejected with a “use op: \"archive\"” error. Not every op applies to every type — see “Supported ops” below. |
type | "event" | "property" | "event_variant" | "property_bundle" | "metric" | "category" | "source" | "destination" | "groupType" | Required. |
name | string | Required on create for events, properties, property bundles, metrics, and categories. Cosmetic on event_variant items and on update/remove/archive of other types. |
tempId | string | Create only. Declares a temporary handle (e.g. "prop1"). Reference it elsewhere in the same call as "$tmp:prop1". The server allocates a real ID and resolves all $tmp: references before writing. |
eventId | string | Required on update / archive / unarchive (or legacy remove) of events. |
propertyId | string | Required on update / archive / unarchive (or legacy remove) of properties. |
propertyBundleId | string | Required on update / archive / unarchive of property bundles. |
metricId | string | Required on update / archive / unarchive of metrics. |
categoryId | string | Required on update / archive / unarchive of categories. |
sourceId | string | Required on update / archive / unarchive of sources. On create, supply either sourceId or a tempId. |
destinationId | string | Required on update / archive / unarchive of destinations. On create, supply either destinationId or a tempId. |
groupTypeId | string | Required on update / archive / unarchive of group types. On create, supply either groupTypeId or a tempId. |
baseEventId | string | Required for event_variant items — the parent event’s ID. |
variantId | string | Required on update / archive / unarchive of event_variant. On create, provide either variantId directly or a tempId on the same item. |
nameSuffix | string | Required on create of event_variant — suffix appended to the parent event name (e.g. buy_now produces click / buy_now). |
description | string | Create-only. Event / property / event variant / bundle / metric / category description. |
Supported ops by type:
| Type | create | update | archive | unarchive | remove (legacy) |
|---|---|---|---|---|---|
event | ✅ | ✅ | ✅ | ✅ | ✅ (alias for archive) |
property | ✅ | ✅ | ✅ (cascades references) | ✅ | ✅ (alias for archive) |
event_variant | ✅ | ✅ | ✅ | ✅ | ❌ |
property_bundle | ✅ | ✅ | ✅ | ✅ | ❌ |
metric | ✅ | ✅ | ✅ | ✅ | ❌ |
category | ✅ | ✅ | ✅ (does not cascade) | ✅ | ❌ |
source | ✅ | ✅ | ✅ | ✅ | ❌ |
destination | ✅ | ✅ | ✅ | ✅ | ❌ |
groupType | ✅ | ✅ | ✅ | ✅ | ❌ |
Create-event fields:
| Field | Notes |
|---|---|
properties | Array of property IDs (or $tmp: refs) to attach. |
propertyBundles | Array of property bundle IDs (or $tmp: refs) to attach to the event. |
sources | Array of source IDs to include the event in. Find source IDs with search (itemType: "source"). |
tags | Array of literal tag-name strings to apply to the event. |
nameMappings | Per-destination name mappings. Array of tagged objects — { kind: "allDestinations", name: "..." } to map across every destination, or { kind: "destination", destinationId: "...", name: "..." } to map per destination. Also accepted on update-event items. |
Create-property fields:
| Field | Notes |
|---|---|
propertyType | string, int, long, float, bool, object, any (aliases like integer, boolean, double accepted). |
sendAs | event, user, or system. |
tags | Array of literal tag-name strings to apply to the property. |
nameMappings | Per-destination name mappings. Array of tagged objects — { kind: "allDestinations", name: "..." } or { kind: "destination", destinationId: "...", name: "..." }. Also accepted on update-property items. |
eventConfigs | (optional) Per-event/per-source property settings on a fresh property. On create, only events: { kind: "allEvents" } entries are accepted — per-event-scoped entries are rejected because the property isn’t attached to any event yet. See “Per-event property settings (eventConfigs)” below. |
Create-event_variant fields:
| Field | Notes |
|---|---|
attachProperties | Array of property IDs (or $tmp: refs) to attach to the variant. |
overrides | Component-level overrides. Each entry: { propertyId, pinned } or { propertyId, allowed }. pinned and allowed are mutually exclusive per override. |
bundleOverrides | Bundle IDs to attach to the variant as property bundles. |
Create-property_bundle fields:
| Field | Notes |
|---|---|
addProperties | Property IDs (or $tmp: refs) to include in the bundle. |
attachToEvents | Event IDs (or $tmp: refs) the new bundle should be attached to. |
Create-metric fields:
| Field | Notes |
|---|---|
metricType | Required. One of Funnel, EventSegmentation, Proportion, Retention, CustomEvent, Cohort. Immutable after create — archive and recreate to change. |
items | Required for non-cohort metrics. Array of metric items referencing events by eventId (or $tmp: ref), with optional baseEventId for event variants. |
cohortConditions | Required for Cohort metrics. Array of conditions referencing events by eventId (or $tmp: ref) and optional propertyId. |
Update-event fields: (require eventId)
| Field | Notes |
|---|---|
set.name | Rename the event. Renaming to the same name is a no-op; renaming to a name already held by another live event is rejected. |
set.description | New event description. |
addProperties / removeProperties | Property IDs (or $tmp: refs) to associate / disassociate. |
addPropertyBundles / removePropertyBundles | Property bundle IDs (or $tmp: refs) to attach / detach. |
addSources / removeSources | Source IDs to include / exclude. |
addTags / removeTags | Top-level on the item, not inside set. Tag-name strings to apply or remove. |
addCategories / removeCategories | Top-level on the item. Category names (or $tmp: refs to create-category items in the same batch) to add or remove. Note: categories are referenced by name, not ID. |
Update-event_variant fields: (require baseEventId + variantId)
| Field | Notes |
|---|---|
set.nameSuffix | New variant suffix. |
set.description | New variant description. |
set.triggers | Replace the trigger list on the variant. |
attachProperties / removeProperties | Property IDs to attach / detach from this variant. |
clearAttachedProperties | Boolean — when true, detaches all properties from the variant in one call. |
addComponentOverrides | Override specs to add or replace. Same shape as create overrides. |
removeComponentOverrides | Property IDs whose component overrides should be cleared. |
addSourceOverrides / removeSourceOverrides | Source-override specs to add or remove. |
clearSourceOverrides | Boolean — when true, clears all source overrides on the variant. |
addBundleOverrides / removeBundleOverrides | Bundle-override specs to add or remove. |
clearBundleOverrides | Boolean — when true, clears all bundle overrides on the variant. |
addVariantPropertyRegex / removeVariantPropertyRegex | Variant property regex specs to add or remove. |
clearVariantPropertyRegexOverride | Boolean — when true, clears all variant property regex overrides. |
The variant override surface uses a three-state lattice — add* / remove* / clear* — for attached properties, source overrides, bundle overrides, and variant property regex overrides. Use add* / remove* for incremental changes; use clear* only when you need to wipe the whole set in one call.
Update-property fields: (require propertyId)
| Field | Notes |
|---|---|
set.name | Rename the property. Renaming to the same name is a no-op; renaming to a name already held by another live property is rejected. |
set.description | New property description. |
set.propertyType | New type. Same value set as create: string, int, long, float, bool, object, any (aliases like integer, boolean, double accepted). |
addAllowedValues | Top-level on the item, not inside set. String values to add to a string-typed property’s allowed list. |
removeAllowedValues | Top-level on the item, not inside set. Values not in the current list are silently no-ops. |
addTags / removeTags | Top-level on the item, not inside set. Tag-name strings to apply or remove. |
addCategories / removeCategories | Top-level on the item. Category names (or $tmp: refs) to add or remove. Categories are referenced by name, not ID. |
isList | Top-level on the item, not inside set. Boolean — switches the property between scalar (false) and list (true). Property-only. |
eventConfigs | Top-level on the item. Per-event/per-source property settings — change presence, pin a value, or restrict allowed values per event. See “Per-event property settings (eventConfigs)” below. |
Update-property_bundle fields: (require propertyBundleId)
| Field | Notes |
|---|---|
set.name | Rename the bundle. |
set.description | New bundle description. |
addProperties / removeProperties | Property IDs (or $tmp: refs) to add / remove from the bundle. Bundle-to-event attachment is managed from the event side via addPropertyBundles / removePropertyBundles on event-update items. |
Update-metric fields: (require metricId)
| Field | Notes |
|---|---|
setName | Rename the metric. |
setDescription | New metric description. |
addItems / removeItems | For non-cohort metrics, add or remove metric items. |
addCohortConditions / updateCohortConditions / removeCohortConditions | For Cohort metrics, manage the cohort condition list. |
addCategories / removeCategories | Top-level on the item. Category names (or $tmp: refs) to add or remove. Categories are referenced by name, not ID. |
Update-category fields: (require categoryId)
| Field | Notes |
|---|---|
set.name | Rename the category. |
set.description | New category description. |
Source, destination, and group-type items:
These workspace-metadata types also support create / update / archive / unarchive. On create, set the shared name field and supply either the type’s ID or a tempId; on update / archive / unarchive, supply the type’s ID (sourceId / destinationId / groupTypeId).
| Type | Fields |
|---|---|
source | Create: platform (required — one of Avo’s source platforms), programmingLanguage, libraryName, libraryDestination. Update: change these with set.platform / set.programmingLanguage / set.libraryName / set.libraryDestination. (A source’s language can also be set via workflow action: "set_source_language".) |
destination | Create: analyticsTool (the analytics platform), includeUserPropsWithEventProps (bool, default false), disabledByDefault (bool, default false). Update: set or remove an API key with apiKey: { kind: "set", env: "dev" | "prod", value: "..." } or { kind: "remove", env: "dev" | "prod" }. |
groupType | Create: name only (group types have no description). |
The tool’s per-field schema (the describe text on each parameter) is the authoritative reference for the full set of accepted fields.
Archive and unarchive (every archivable type). op: "archive" archives an item on the branch; op: "unarchive" restores it. Both take the type’s lookup-ID field (eventId, propertyId, propertyBundleId, metricId, categoryId, sourceId, destinationId, groupTypeId) — or, for event variants, baseEventId + variantId. All archives are reversible from the Avo app.
| Type | Archive example | Notes |
|---|---|---|
event | { op: "archive", type: "event", eventId: "..." } | op: "remove" is accepted as a legacy alias. |
property | { op: "archive", type: "property", propertyId: "..." } | Cascades — references on every event using the property are removed. op: "remove" is accepted as a legacy alias. If you only have the name, resolve the ID first with search so name-conflict ambiguity surfaces before the mutation runs. |
event_variant | { op: "archive", type: "event_variant", baseEventId: "...", variantId: "..." } | op: "remove" is not supported for variants. |
property_bundle | { op: "archive", type: "property_bundle", propertyBundleId: "..." } | — |
metric | { op: "archive", type: "metric", metricId: "..." } | — |
category | { op: "archive", type: "category", categoryId: "..." } | Does not cascade — events/properties/metrics keep their addCategories history pointing at the now-archived category. Migrate members first (see “Merging categories”). |
source / destination / groupType | { op: "archive", type: "source", sourceId: "..." } (likewise destinationId / groupTypeId) | — |
op: "remove" on any type other than event / property is rejected with an error directing you to op: "archive".
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 fields are accepted on event, property, and event variant items (both create and update):
| Field | Notes |
|---|---|
owner.stakeholder | Sets the owning stakeholder. Reference must point to an existing stakeholder (stakeholders are created in the Avo web app — the MCP does not create them). |
stakeholders.add | Array of stakeholder references to add as collaborators. |
stakeholders.remove | Array of stakeholder references to 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:
- An
updateitem for every event, property, and metric inAcarryingaddCategories: ["B"], removeCategories: ["A"]. - A
{ op: "archive", type: "category", categoryId: "<id of A>" }item.
Both must travel in the same batch — the category archive in step 2 does not cascade to its members, so step 1 has to move the members first.
Per-event property settings (eventConfigs)
eventConfigs is a top-level array on an update-property item (and, restricted to events: { kind: "allEvents" }, on a create-property item). Each entry adjusts how the property behaves on a specific event or across all events:
setPresence— change presence toalwaysSent,sometimesSent, orneverSent. Can be scoped per source.setPinnedValue— pin a value for the property. Withevents: { kind: "onEvent" }pins per-event; withevents: { kind: "allEvents" }pins property-wide.restrictAllowedValues— change the property’s allowed value list for an event. Carries avaluesChangedelta:addValues(non-empty),removeValues, orclear(no payload).
eventConfigs entries reference events by eventId, and $tmp: references are supported here: an eventConfigs[*].events.eventId (or eventIds) may point at a create-event item earlier in the same batch via $tmp:, and preprocessing rewrites it to the real event ID before saving — no separate call needed. (On a property create, the referenced event must also attach this property in the same batch, otherwise the call fails with UnresolvableReference.)
Not yet implemented. set.sendAs on op: "update" of a property item returns a NotYetImplemented error — sendAs is immutable after create.
Everything else works today: create / update for events, properties, event variants, property bundles, metrics, categories, sources, destinations, and group types; archive / unarchive for every archivable type; rename events and properties via set.name; toggle a property between scalar and list via isList; apply or remove tags via addTags / removeTags; per-event property settings via eventConfigs. (To remove an event variant, use op: "archive" — op: "remove" on a variant is rejected.)
Temporary IDs (tempId / $tmp:)
To reference a newly-created item from another item in the same call, declare a tempId on the create item and reference it elsewhere as "$tmp:<name>":
tempIdis create-only — setting it on anupdate,remove, orarchivereturns an error.tempIdnames must be unique within a singlesave_itemscall.$tmp:references are resolved in these array fields:properties,addProperties,removeProperties,attachProperties,propertyBundles,addPropertyBundles,removePropertyBundles,attachToEvents,addSources,removeSources,bundleOverrides; insideoverrides[].propertyId/addComponentOverrides[].propertyId; withineventConfigs[*].events.eventId/eventIds; and within nested metric fields (items[].metricId/eventId/baseEventId,cohortConditions[].eventId/propertyId). InaddCategories/removeCategories/addGroupTypes/removeGroupTypes, a$tmp:ref instead rewrites to the siblingcreateitem’s name (those fields take names, not IDs). Sources, destinations, and group types can be created in the same batch and referenced by theirtempIdtoo.- 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 hasname,entityId, andentityType(event,property,event_variant,property_bundle,metric,category,source,destination, orgroupType). Archived items are reported underremovedEntities(a legacy field name); restored items underunarchivedEntities. (updatedEntitiesentries may also carry areasonwhen the update was a no-op.)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" }
],
"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",
"propertyType": "string",
"sendAs": "event",
"description": "How the user completed checkout"
},
{
"op": "create",
"type": "event",
"name": "Checkout Completed",
"description": "Fired when the user finishes checkout",
"properties": ["$tmp:checkout_method"],
"sources": ["src-web", "src-ios"]
}
]
}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",
"description": "Share of users who start checkout and complete it.",
"metricType": "Funnel",
"items": [
{ "eventId": "evt-checkout-started" },
{ "eventId": "evt-checkout-completed" }
]
}
]
}Common errors
- Missing
writescope — the client must re-authorize withwrite. branchId is required/items is required— malformed request.tempId is only valid on create items— don’t settempIdonupdateorremove.Duplicate tempId "<name>"— eachtempIdmust 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— missingeventId/propertyId/baseEventId/variantId/propertyBundleId/metricId.too many items (got N, max 50)— batch is over the 50-item cap.NotYetImplemented— one of the unsupported operations above.- Per-item audit-pipeline validation failures (e.g. illegal name, duplicate property, etc.) — returned inside the
errorsarray rather than failing the whole call.
workflow
Scope: write · Destructive: import with importMethod: "add_update_and_remove"
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, selected by the action parameter. Five actions are supported:
create_branch— open a new branch.update_branch_description— set the description on an existing open branch.pull_main— pull the latest changes from main into an open branch. Requires Codegen access; on overlapping changes, incoming main changes win.set_source_language— set a source’s programming language on an open branch.import— bulk-import a tracking-plan export (CSV or Avo JSON Schema) into an open branch. Requires Admin role; never targets main.
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.
Destructive import. import with importMethod: "add_update_and_remove" removes properties from events when they are absent from the import payload. Only use it with a complete export — never a partial one. The change lands on a branch and is reviewable before merge, but a partial payload can strip large numbers of properties.
Parameters
Which parameters apply depends on action — see “Required” below.
| Parameter | Required | Description |
|---|---|---|
action | Yes | The workflow action. One of: create_branch, update_branch_description, pull_main, set_source_language, import. |
branchName | For create_branch; alternative to branchId for update_branch_description / set_source_language | Name for the new branch (create_branch), or the existing branch’s name. |
branchId | Alternative to branchName for update_branch_description / set_source_language; required for pull_main and import | ID of the existing branch. For update_branch_description and set_source_language, provide exactly one of branchId or branchName. |
description | For update_branch_description (optional on create_branch) | Branch description text. On create_branch, optionally sets the new branch’s description. Empty / whitespace-only strings are treated as a no-op on update_branch_description. |
sourceId | For set_source_language | The source whose language to set. Find it with get (type: "source") or search (itemType: "source"). |
language | For set_source_language | The source’s programming language. One of: Swift, JavaScript_V2, Reason_V2, Java, JSON, Python, Python3, PHP, Kotlin, C#, TypeScript, Objective-C, Ruby, Dart, Go. The server validates the language against the source’s platform and returns the supported list on a mismatch. |
format | For import | Payload format. csv (a CSV export — auto-detects Avo, Amplitude, Mixpanel, Segment, and spreadsheet formats) or json_schema (an Avo JSON Schema document). |
payload | For import | The raw CSV text or Avo JSON Schema document, as a string. |
importMethod | Optional for import | add_only (default — only appends new items), add_and_update (also overwrites existing items with imported values), or add_update_and_remove (destructive — additionally removes properties from events when absent from the import; use only with a complete export). |
workspaceId | No | Workspace ID |
Returns
create_branch— the new branch’sbranchId,branchName, and abranchUrlthat opens it in the Avo web app.update_branch_description— confirmation with the resolvedbranchIdand the updated description.pull_main— confirmation that main was pulled into the branch.set_source_language— confirmation with the resolved source and language.import— a summary of what the import added, updated, and removed 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."
}Set a source’s codegen language
Prompt: “Set the iOS source on the add-checkout-tracking branch to Swift.”
Claude resolves the sourceId with get (type: "source"), then sets the language on the branch.
{
"action": "set_source_language",
"branchName": "add-checkout-tracking",
"sourceId": "src-ios",
"language": "Swift"
}Bulk-import a tracking plan onto a branch
Prompt: “Import this Amplitude CSV export onto a fresh branch.”
Claude opens a branch with create_branch, then calls import with the CSV payload on the returned branchId. add_only (the default) only appends new items, so it never removes anything.
{
"action": "import",
"branchId": "br-abc123",
"format": "csv",
"payload": "Event Name,Property Name,...\nCheckout Completed,checkout_method,...",
"importMethod": "add_only"
}Common errors
- Missing
writescope — re-authorize withwrite. - Workspace access denied.
- Unsupported action value.
- Both
branchIdandbranchNameprovided —update_branch_descriptionandset_source_languagerequire exactly one. pull_mainwithout Codegen access, orimportwithout Admin role — permission error.set_source_languagewith a language the source’s platform doesn’t support — the error lists the supported tokens.importmissingformatorpayload, or with an unknownformat/importMethodtoken.
list_branches
Scope: read
Transitional. This tool stays available while branch enumeration is being folded into search (as itemType: "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
| Parameter | Required | Description |
|---|---|---|
workspaceId | No | Workspace ID |
branchStatuses | No | Filter by status. Valid values: Draft, ReadyForReview, ChangesRequested, Approved, Merged, Closed, Open. Defaults to open/active branches only. |
pageSize | No | Results per page (1–50, default 25) |
pageToken | No | Pagination token from a previous response |
branchName | No | Substring match on branch name (case-insensitive) |
creatorEmail | No | Filter by creator email |
creatorUserId | No | Filter by creator user ID |
reviewerEmail | No | Filter by reviewer email |
reviewerUserId | No | Filter by reviewer user ID |
collaboratorEmail | No | Filter by collaborator email |
collaboratorUserId | No | Filter by collaborator user ID |
createdAfter | No | ISO 8601 date — only branches created after |
createdBefore | No | ISO 8601 date — only branches created before |
impactedSourceId | No | Filter 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, creation date, and (when present) creator email, reviewer count, and description — 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
pageSize(outside 1–50). - 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 returns a NotYetImplemented error. Changing a property’s sendAs is not supported — it is immutable after create. (To remove an event variant, use op: "archive"; op: "remove" on a variant is rejected, not NotYetImplemented.) See the save_items reference.