The Togo MCP server at https://mcp.togohq.ai/mcp offers 21 tools. This page is generated from the server’s own tool definitions, so each description below is word for word what your agent reads when it lists the tools. To connect, see The Togo MCP server.
Every tool except list_projects and create_project takes a projectId, required on all but give_feedback, where it is optional: one connection reaches every project you can, so each call names the one it is about. Call list_projects first. A Read only connection sees the read tools and give_feedback; a Read and change connection sees all of them.
Read tools
list_projects
Which projects can I reach. Any connection. Reads only.
Lists the active Togo projects this connection can read, across the member’s organizations: each one’s id, name, organization, public write keys (test and live), how fresh its analytics data is, whether it has ever received an event on any key (hasReceivedEvents: true, false, or null when that could not be checked), and whether this connection can change it — plus the active organizations and whether it can create projects there (create_project). Set archivedOnly to true to list archived projects instead. Call this first, then search the codebase for the write key passed to the Togo SDK — a key belongs to exactly one project — and use that project’s id as projectId on every other tool. If no key matches and the user asked about data, ask which project they mean; when setting Togo up, follow get_setup_instructions’ project order instead.
| Argument | Type | Required | Description |
|---|---|---|---|
archivedOnly |
boolean | no | true lists only archived projects, to read an old project’s data. Default false. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
get_project
Which project is this. Any connection. Reads only.
One Togo project in depth, and how to confirm it is the right one: its public write keys (search the codebase for the key passed to the SDK — a key belongs to exactly one project), its time zone, whether its PII filter drops email addresses from event properties, when it first received events, its most recent event keys, and how fresh its analytics data is. Takes only projectId, from list_projects.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
list_events
List events. Any connection. Reads only.
Every event key in this project: the raw names the code sends it as, whether it is defined (has an event definition) and its description, its property names (use them in filters and breakdowns; get_event has their types), when it was first and last received, and any merge. Other tools name events by these keys — never by display names. Optionally only keys or raw names containing search.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
search |
string | no | — |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
get_event
Describe an event. Any connection. Reads only.
One event key in full: its event definition if it has one (defined: true) — what it means, when it fires, its defined properties with their types and allowed values — the other property names and types its traffic carries, the raw names it is sent as, and its revision. Use the property names here in filters and breakdowns.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
key |
string | yes | — |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
get_trend
Trend of an event. Any connection. Reads only.
How often one event happened, or how many unique people did it, per day, week or month in the project’s time zone. Ranges: up to 365 days by day, 104 weeks by week, 36 months by month — a longer range is refused, never shortened. Optional filters (call get_event first to learn an event’s properties), and an optional breakdown by one property (the 10 largest values). Unique people are approximate; counts of events are exact. Data is a few hours behind (see analyticsDataThrough).
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
event |
string | yes | The event key to count. |
measure |
"events" | "people" |
no | events counts occurrences; people counts unique people, merges resolved. Default "events". |
grain |
"day" | "week" | "month" |
no | Up to 365 days by day, 104 weeks by week, 36 months by month. Default "day". |
fromDate |
string | yes | First day, inclusive, in the project’s time zone. |
toDate |
string | yes | Last day, inclusive, in the project’s time zone. |
filters |
object[] | no | Default []. |
breakdown |
string | no | Split by one property of this event; the 10 largest values are returned. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
run_funnel
Run a funnel. Any connection. Reads only.
Conversion through 2–10 events in order: of the people who did step 1 between fromDate and toDate (up to 365 days, in the project’s time zone), how many reached each later step within conversionWindowDays (default 7; 1 for an in-session flow such as checkout, up to 90 for a long trial or a renewal). Other events may happen between steps. Narrow a step with property filters — a landing-page view is page_viewed filtered on its page property; call get_event first to learn an event’s properties. People are counted exactly, with merged identities resolved. Always state the window and range you used.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
steps |
object[] | yes | Strict order; other events may happen between steps. |
fromDate |
string | yes | First day a person may enter (do step 1), inclusive. |
toDate |
string | yes | Last day a person may enter, inclusive; up to 365 days after fromDate. |
conversionWindowDays |
integer | no | Days a person has from step 1 to the last step. 7 by default; 1 for an in-session flow such as checkout, up to 90 for a long trial or a renewal. Default 7. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
get_metric
Read a metric. Any connection. Reads only.
A Togo platform metric for this project, by day or week in the project’s time zone, from precomputed observations: the value, its numerator and denominator, the definition version and, for a conversion, its window. onboarding_completion is the share of people who completed onboarding within 7 days of starting, by the day or week they started; a week’s value changes until its last day’s window has passed. A bucket that is absent has not been computed — not zero.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
metricId |
"onboarding_completion" |
yes | A platform metric id. |
grain |
"day" | "week" |
no | Default "week". |
fromDate |
string | yes | — |
toDate |
string | yes | — |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
verify_tracking
Verify tracking. Any connection. Reads only.
Checks the events a test run sent, found by who sent them: pass filter.deviceId (the SDK’s getDeviceId() on the device the run used), or userId, anonymousId or sessionId — all ANDed — and get the newest matching events (last, default 50), newest first, each with its diagnostics. If your SDK calls returned event ids, use verify_tracking_by_event_ids instead. Give expectedEventNames (names exactly as the code sends them), expectIdentify or expectProfileProperties to get only those, plus missingCount and missing for each that never arrived — call the SDK’s flush() first, since it uploads in batches. Every diagnostic has a code and the property and type it is about; diagnosticCodes gives each code’s severity (error: production drops or loses the data; warning: kept, but not what its definition says, or likely a bug), description and agentFix, the change to make. errorCount and warningCount total the returned events’ diagnostics. Apply each agentFix, run again, and check again until errorCount, warningCount and missingCount are all 0. It reads what the project’s TEST keys sent, within seconds, with values as sent; production traffic is watched in the dashboard’s Live View, never here. Events are kept two hours. It never counts users or events: use get_trend or run_funnel for that.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
filter |
object | no | Which events: the ones sent with these ids. Omit for the newest events of every sender. Default {}. |
expectedEventNames |
string[] | no | Event names the run should have sent, exactly as the code sends them: only these are returned, and any that did not arrive is missing. |
expectIdentify |
boolean | no | True when the run should have called identify(); one that did not arrive is missing. |
expectProfileProperties |
string[] | no | Person properties the run should have set with setPersonProperties(); one never sent is missing. |
last |
integer | no | How many of the newest matching events to return; events are kept two hours. Default 50. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
verify_tracking_by_event_ids
Verify tracking by event ids. Any connection. Reads only.
Checks exactly the events whose ids your SDK calls returned — track(), identify() and setPersonProperties() each return the eventId they queued. Collect them during the test run, call the SDK’s flush(), then pass them as eventIds. Returns those events, each with its diagnostics, and missingCount and missing for every id that never arrived (not sent, the wrong key, consent still pending, or not uploaded yet). A rejected event arrived: it is an event with an error. diagnosticCodes gives each code’s severity (error: production drops or loses the data; warning: kept, but not what its definition says, or likely a bug), description and agentFix, the change to make; errorCount and warningCount total the events’ diagnostics. Apply each agentFix, run again with the new ids, and check again until errorCount, warningCount and missingCount are all 0. Without ids — a click-through in a browser — use verify_tracking with filter.deviceId. It reads what the project’s TEST keys sent, with values as sent; production traffic is watched in the dashboard’s Live View, never here. Events are kept two hours.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
eventIds |
string[] | yes | The eventId each SDK call returned for the run being checked. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
get_setup_instructions
How to add Togo to this app. Any connection. Reads only.
The step-by-step playbook for adding Togo analytics to an app in this project: which write key each build uses, giving each system its own key pair, defining the tracking plan before the code, installing the SDK, identify() and profile properties, proving a run’s events arrive and are right with verify_tracking_by_event_ids or verify_tracking, leaving a note in the repository’s agent-instructions file, and confirming production. Call it before adding or changing Togo tracking, and follow it. Returns the playbook and the project’s key pairs.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
get_person
Look up a person. Any connection. Reads only.
One person, by exactly one of userId (what the app passes to identify()), anonymousId (the SDK’s visitor id) or personId (Togo’s id). Returns Togo’s personId, every userId and anonymousId linked to them, their profile properties, and when they were first and last active. An anonymous visitor nobody identified has no profile (hasProfile false) but still has a personId. Identities are linked only by the app calling identify(); no tool can link them.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
userId |
string | no | The id the customer’s app passes to identify() |
anonymousId |
string | no | The SDK’s anonymous id for a visitor or device. |
personId |
string | no | Togo’s person id, as get_person and other tools return it. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
get_person_events
A person’s events. Any connection. Reads only.
What one person did: their events per hour or per day over a range, by event key, in the project’s time zone. Identify the person with exactly one of userId, anonymousId or personId (as get_person). By hour covers up to 7 days, by day up to 365. Only buckets with events are listed. When idsTruncatedAt is present the person has more linked ids than one answer covers, and the counts are a lower bound. Events are curated every few hours, so the most recent ones are not in the answer yet: nothing after analyticsDataThrough is counted, and a range reaching past it is incomplete — say so rather than reporting the person as inactive. For test traffic just sent, use verify_tracking.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
userId |
string | no | The id the customer’s app passes to identify() |
anonymousId |
string | no | The SDK’s anonymous id for a visitor or device. |
personId |
string | no | Togo’s person id, as get_person and other tools return it. |
fromDate |
string | yes | First day, inclusive, in the project’s time zone. |
toDate |
string | yes | Last day, inclusive, in the project’s time zone. |
grain |
"hour" | "day" |
no | By hour for up to 7 days; by day for up to 365. Default "day". |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
list_person_properties
List person properties. Any connection. Reads only.
The person (profile) properties this project defines: name, type, description and allowed values. email and name are defined for every project. A setPersonProperties() call keeps only defined keys; any other key is dropped, so define a property before the app sends it — values sent before it is defined are not recovered. dropped lists the keys production traffic sent that were dropped and are not fixed yet, each with a code, the types sent, and expected (the snake_case name to rename it to, for person_property_key_invalid); diagnosticCodes gives each code’s description and agentFix, the change to make. Production drops are a few hours behind; a key is listed when it was dropped in the last 7 days, and its droppedCount and firstSeenAt cover every drop recorded for it, not only those 7 days; for a test run just sent, use verify_tracking. droppedUnnamed counts keys that looked like an email address or were too long to record by name. droppedIncomplete: true means the project has recorded more distinct problems than are kept, so other dropped keys may be missing from the list.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
Tools that change data
update_event_definitions
Create or update event definitions. Needs a Read and change connection. Changes data.
Creates event definitions — what an event key means: its description, when it fires and when it does not, its properties — or changes them. Takes a list of 1 to 50, each applied on its own; the answer gives every entry its status, by key (created, updated, unchanged, or rejected with the issues and how to fix them), so resend only the rejected ones. Define a whole tracking plan in one call; a single change is a list of one. An event is defined once it has a definition. Per entry: omitted fields keep their value; given fields replace it; properties are matched by name (a given one replaces or adds; others are untouched); a property is removed only by naming it in removeProperties. Creating needs description, firesWhen and at least one doesNotFireWhen. Changing an existing event definition needs its revision from get_event. Once an event has traffic, a change that would break code already sending it — a narrower type, a removed allowed value — is rejected with the reason. Each key once per call.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
definitions |
object[] | yes | — |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
merge_events
Merge duplicate events. Needs a Read and change connection. Changes data, and the change cannot be undone.
Merges the event key from into into: the raw names counted under from count under into from now on, and every past answer re-counts with the merged history. Use it when two keys are the same event sent under different names (list_events marks likely pairs with looksLike). It cannot be undone — confirm with the person first.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
from |
string | yes | The duplicate key; its raw names move to into. |
into |
string | yes | The key that survives. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
update_person
Set a person’s profile properties. Needs a Read and change connection. Changes data.
Sets defined profile properties on the person the app identifies by userId, and removes those named in unsetProperties; properties not mentioned are untouched. Creates the person if the app has not identified that userId yet (result “created”). Only defined properties are accepted — see list_person_properties, and define new ones with update_person_property. A later setPersonProperties() call from the app overwrites what this sets. It never links identities: only the app’s identify() does that.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
userId |
string | yes | The id the customer’s app passes to identify() — never Togo’s person id. |
properties |
object | no | Defined properties to set; others on the profile are untouched. |
unsetProperties |
string[] | no | Properties to remove from the profile — the only way one is removed. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
update_person_property
Define or update a person property. Needs a Read and change connection. Changes data.
Defines a person (profile) property, or changes its definition. A setPersonProperties() call keeps only defined keys, so define a property before the app sends it. Defining needs type and description. Omitted fields keep their value; allowedValues replaces the list. The type never changes once defined; allowedValues and maxLength can be narrowed only while no stored profile holds a value they would refuse. email and name are defined for every project.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
key |
string | yes | The property name, as setPersonProperties() sends it. |
type |
"string" | "number" | "boolean" |
no | Required to define; never changes afterwards. |
description |
string | no | What the value means — required to define. |
allowedValues |
string[] | no | For a string with a fixed vocabulary: every value it may take; replaces the list. |
maxLength |
integer | no | For a string: the longest value kept. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
create_project
Create a project. Needs a Read and change connection. Changes data.
Creates a Togo project and its first write-key pair (a test key for development and staging, a live key for production), returning the project id and both keys. ONE PRODUCT IS ONE PROJECT — its marketing site, web app, mobile apps and server together, each with its own write-key pair — because Togo follows a person across surfaces only inside one project. So before calling this, check list_projects: if a project for this product exists (same name or domain, or this repository is one part of a product whose other parts already send), use it and call create_write_key for this system instead — when it has received events and you are not sure, ask the user as a multiple-choice question; a project that has never received an event (hasReceivedEvents false) is the one signup made — use it and rename it with update_project, without asking. Never create a project per environment. Create only when neither exists, without asking, and tell the user afterwards what you created. keyName is the first system you are wiring, a name you choose in lowercase kebab-case (web-app, api-server); reportingTimeZone is this machine’s IANA time zone unless the user named one. Calling again with the same name returns the existing project.
| Argument | Type | Required | Description |
|---|---|---|---|
organizationId |
string | yes | The organization to create it in — an id from list_projects’ organizations. |
name |
string | yes | The product’s name — one project per product, every surface of it. |
keyName |
string | yes | The first write-key pair’s name: the system you are wiring first, e.g. web-app. |
reportingTimeZone |
string | no | Where the project’s reports start and end each day; UTC when omitted. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
update_project
Rename a project or change its settings. Needs a Read and change connection. Changes data.
Changes a project’s name, its reporting time zone or the day its reporting weeks start; anything omitted is unchanged. Mostly used to rename the project signup made — one that has never received an event — after the product it now tracks, without asking, and to set its time zone to this machine’s. Changing the time zone moves where every report’s days begin — stored data is UTC and nothing is rewritten, but charts and comparisons shift — so on a project that has received events change it only when the user asks. piiFilterEnabled turns on dropping email addresses from event properties; it is off unless the user asks for it, and turning it on never removes what is already stored.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
name |
string | no | — |
reportingTimeZone |
string | no | Moves every report’s day boundaries; stored data is UTC and nothing is rewritten. |
weekStartsOn |
6 | 0 | 1 |
no | The first day of a reporting week: 6 Saturday, 0 Sunday, 1 Monday. |
piiFilterEnabled |
boolean | no | true drops any event property whose name or value contains an email address before it is stored, from the next curation run on; false (the default) stores properties as sent. Never retroactive. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
create_write_key
Create a write key for a system. Needs a Read and change connection. Changes data.
Creates a public write-key pair for one system of this product — its test key for development and staging builds, its live key for production — and returns both. Give every system that sends its own pair, named for the system in lowercase kebab-case: web-app, api-server, marketing-site, ios-app, jobs-worker (or the repository’s name when there are two of a kind). Choose the name yourself; never ask the user for one. A pair named Default is the one signup made: do not use it or mention it. Never put an environment in the name: the pair’s test and live keys are the environments. Calling again with the same name returns the existing pair. Keys are public and can only send events; revoking one is done on the dashboard.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | yes | The project to ask about — an id from list_projects. |
name |
string | yes | The system the pair is for, e.g. api-server. |
intent |
string | no | Optional. In one sentence, why you are making this call — the user’s goal, not the operation (for example “checking whether last week’s onboarding change lifted signups”). Infer it from the conversation; never ask the user. Never include personal data, email addresses or secrets. |
Reporting a problem
give_feedback
Send feedback to the Togo team. Any connection. Changes data.
Tell the Togo team about the Togo tools: an unexpected error, a confusing or wrong-looking answer, a capability you needed and could not find, a description that misled you, a workaround you had to invent, or something you wish they did. At the end of setting Togo up, send one install_report even if everything worked. Say what you were trying to do, what you called, what you expected and what happened, and pass the projectId you were working in if there is one. Never include personal data — no email addresses, names, person ids, property values or write keys. Nobody replies; it is read by the people who build Togo. After sending, tell the user in one line that you reported it and what about.
| Argument | Type | Required | Description |
|---|---|---|---|
projectId |
string | no | The project you were working in, if there is one — an id from list_projects. Optional. |
message |
string | yes | What you were trying to do, what you called, what you expected and what happened. No personal data. |
category |
"tool_error" | "missing_capability" | "confusing_output" | "documentation" | "other" | "install_report" | "feature_request" |
no | tool_error, missing_capability, confusing_output, documentation, feature_request, other — or install_report, the one report at the end of setting Togo up. Default "other". |
toolName |
string | no | The Togo tool the report is about, if there is one. |
severity |
"high" | "medium" | "low" |
no | high: you were blocked; medium: you found a workaround; low: a minor annoyance, a wish, or nothing went wrong. Default "medium". |