Apps
List apps, look up by name, or fetch a single app by id.
A Model Context Protocol server that exposes your TrackVia account — apps, views, records, and files — plus a rich library of higher-level helpers for query, workflow, import, dedupe, aggregation, state machines, and lifecycle — for any MCP-aware assistant.
Point an MCP-aware client at the server, pass through a TrackVia access token, and your model can work directly against your TrackVia apps.
List apps, look up by name, or fetch a single app by id.
List account users, create one, bulk-invite many, or batch-resolve by email.
List views, filter by name, page through records, run keyword search.
Read, create (single or batch), update, or delete records — including bulk delete within a view.
Download, upload, or delete files attached to record fields.
Annotate a view, record, or whole account with field metadata; export an app's full schema.
Filter, sort, select, and export records — evaluated inside the MCP server. Fan-out search across every view.
Upsert by a unique field, or bulk-update / bulk-delete by filter (with preview, backup, and safety confirm).
Duplicate records, copy between views, and expand relationships inline.
Turn human names (view, field, user) into the right ids.
Locate fields across views and walk a relationship graph around any record.
Find and merge duplicates, and surface records missing required fields.
Dry-run or execute CSV / JSON imports with casting and optional upsert.
Group-by, pivot, trend, and top-N — computed client-side over paginated records with bounded scans.
Status-field transitions with optimistic-concurrency checks, plus a bulk "advance workflow" variant.
Soft-delete and restore patterns that flip an archive field instead of destroying data.
Inventory every registered tool with version and status — useful for discovery from the model.
The server speaks MCP over streamable HTTP at the
/mcp endpoint. Every MCP request must carry a TrackVia access token (see Configure). Other MCP clients should work too, but Claude Code is the only one we
currently document.
claude mcp add --transport http trackvia https://k8s-qa4.qa.xvia.com/mcp/mcp \
--header "Authorization: Bearer YOUR_TRACKVIA_ACCESS_TOKEN"
Optional: pin a specific TrackVia host (defaults to the server's configured host) and/or target a sandbox account inside that account:
claude mcp add --transport http trackvia https://k8s-qa4.qa.xvia.com/mcp/mcp \
--header "Authorization: Bearer YOUR_TRACKVIA_ACCESS_TOKEN" \
--header "X-TrackVia-Host: qa1.qa.xvia.com" \
--header "X-TrackVia-Account-Id: 12345"
Verify with claude mcp list — TrackVia should appear as connected.
Headers your MCP client passes through on every request. The client sets them for you once you paste the values in at install time.
| Header | Required | Purpose |
|---|---|---|
Authorization |
Yes | TrackVia OAuth access token, as Bearer <token>. |
X-TrackVia-Host |
Optional |
Override the upstream TrackVia host this request targets — e.g. qa1.qa.xvia.com. Falls back to the default host https://go.trackvia.com. Must match the hardcoded allowlist: *.trackvia.com, *.xvia.com, or localhost.
|
X-TrackVia-Account-Id |
Optional | Target a sandbox account id inside the account implied by the access token. Must be a positive integer. Omit to use the access token's default account. |
Every tool the server registers at startup.
| Group | Tool | Description |
|---|---|---|
| Bootstrap | whoAmI | Returns the session's cached AccountContext: {userId, email, defaultAccountId, accounts: [...]}. |
serverCapabilities | Returns `{name, version, tools: [{name, since, status, replacedBy?}]}` — the authoritative list of what this server exposes and how stable each tool is. | |
| Apps | getApps | Returns every app visible to the caller. |
getAppByName | Returns apps whose name matches the given value. | |
getApp | Fetches a single app's definition (name, description, status, sandbox flags). | |
createApp | Creates a new app in the account. | |
updateApp | Updates an app by merging the caller's partial `updates` into the current App body. | |
deleteApp | Permanently deletes an app and its tables, views, and records. | |
duplicateApp | Creates a new app from an existing app used as a template. | |
| Tables | getTable | Fetches a table's metadata, including its field definitions. |
listTables | Lists every table in the given app. | |
createTable | Creates a new table in the app. | |
updateTable | Updates a table by merging the caller's partial `updates` into the current Table body. | |
deleteTable | Permanently deletes a table, its fields, and its records. | |
| Fields | addField | Appends a field to a table. |
updateField | Locates a field by id or name and merges `updates` into it (shallow merge). | |
removeField | Removes a field from a table. | |
reorderFields | Reorders the table's `fields` array to match the given name sequence. | |
| Calculated / triggered fields | addCalculatedField | Adds a calculated field to a table via read-modify-write on the Table object (there's no fields sub-resource). |
addTriggeredField | Adds a triggered field. | |
formulaReference | Returns the canonical TrackVia formula grammar + every supported function, grouped by category (Logic, Text, Math, Aggregate, Child aggregate, Date/time, Geospatial, Triggered-only). | |
| Views | getViews | Walks every app + every table in the account and returns view summaries. |
getViewByName | Walks every view in the account and returns the ones with an exact-matching name. | |
getViewRecords | Returns records from a view with offset pagination. | |
findViewRecords | Runs a keyword search against a view's records. | |
createView | Creates a new view on the table. | |
updateView | Applies a partial update to a view (rename, edit filters, replace column projection). | |
deleteView | Permanently deletes a view. | |
getViewLayout | Returns the /extra payload: column widths, pinned fields, grouping, and other layout metadata. | |
updateViewLayout | Replaces the view's layout metadata (columns, pinning, grouping). | |
| Records | getRecord | Returns a single record from a view via the platform's RecordController. |
addRecord | Creates a record in a view. `recordData` is a flat map of fieldName → value. | |
addRecords | Creates multiple records in a view in one request. | |
updateRecord | Updates a single record. `recordData` is a flat map of fieldName → value. | |
deleteRecord | Deletes a single record. | |
deleteAllRecordsInView | Deletes every record accessible through the view. | |
getRecordHistory | Reads the record change history via RecordHistoryController. | |
| Files | getRecordFile | Downloads a file (or image) from a record field. |
uploadRecordFile | Uploads (or replaces) a file in a record field. | |
deleteRecordFile | Removes the file stored in a record field. | |
| Forms | getForm | Fetches a single form's definition. |
listForms | Lists every form defined on the given table. | |
createForm | Creates a new form on the table. | |
updateForm | Applies a partial update to a form (rename, edit layout, replace projection). | |
deleteForm | Permanently deletes a form. | |
| Users | getUsers | Returns the TrackVia account users (paginated). |
addUser | Creates a new account user. | |
getUser | Fetches a single user by ID. | |
updateUser | Applies a field-level update to a user. | |
deactivateUser | Sets the user's status field to "Inactive". | |
reactivateUser | Restores the user's status field to "Active". | |
deleteUser | Permanently deletes a user record. | |
bulkInviteUsers | Runs `addUser` over an array of user payloads with bounded concurrency. | |
findUsersByEmail | Pages the account user list once, then builds a lookup map. | |
| User groups | listUserGroups | Lists user groups on the account. |
getUserGroup | Fetches a single user group, including its member list. | |
searchUserGroups | Keyword-search user groups by name. | |
createUserGroup | Creates a new user group. | |
updateUserGroup | Applies a partial update to a user group. | |
deleteUserGroup | Permanently deletes a user group. | |
| Roles | getRole | Fetches a single role by ID, including its full `roleRules`, `resources`, `forms`, and `views` tree. |
listRoles | Lists every role defined on the given app. | |
createRole | Creates a new role in the account. `name` and `appId` are required; `roleRules` / `resources` / `forms` / `views` describe the permission tree. | |
updateRole | PUT on `/roles/{roleId}`. | |
deleteRole | Permanently deletes a role. | |
assignUsersToRole | PUT on `/roles/{roleId}/users`. | |
listRolePermissions | Returns the users currently assigned to the role — the read-only signal for per-role membership auditing. | |
| Audit | listAuditEvents | Lists audit events for the chosen resource type. |
getAuditEvent | Returns a single audit event from a `listAuditEvents` page. | |
| Dashboards | getDashboard | Fetches a single dashboard by ID. |
listDashboards | Lists dashboards in the account. | |
createDashboard | Creates a new dashboard in the account. | |
updateDashboard | Replaces a dashboard's metadata and elements. | |
deleteDashboard | Permanently deletes a dashboard. | |
| Filters | listFilters | Lists every named filter defined on the given table. |
getFilter | Fetches a single filter by ID. | |
createFilter | Creates a named filter on the table. | |
updateFilter | Applies a full-replacement update to a filter. | |
deleteFilter | Permanently deletes a filter. | |
| Relationships | createRelationship | Creates a relationship between two tables and verifies it actually persisted on BOTH sides. |
updateRelationship | Renames a relationship. | |
deleteRelationship | Removes a relationship between two tables. | |
| Flows | listFlows | Lists every flow attached to the given app. |
getFlow | Fetches a single flow's full definition (trigger, steps, config). | |
createFlow | Creates a new flow on the app. | |
updateFlow | Applies a partial update to a flow (rename, edit steps, toggle enabled). | |
deleteFlow | Permanently deletes a flow. | |
| Notification rules | listNotificationRules | Lists every notification rule attached to the given view. |
getNotificationRule | Fetches a single notification rule by ID. | |
createNotificationRule | Attaches a new notification rule to the view. | |
updateNotificationRule | Applies a partial update to a notification rule. | |
deleteNotificationRule | Permanently deletes a notification rule. | |
| Inspect | describeView | Returns the field metadata (structure) for a view plus the total record count. |
describeRecord | Returns the record plus, for every field, its type, required flag, writability, and (for relationship fields) the linked id. | |
describeAccount | Fetches every app, every view, and (by default) a handful of sample field names per view in a single response. | |
exportAppSchema | The canonical 'load the entire schema' call. | |
| Query | queryRecords | Paginates a view's records, then applies filter / sort / select in the MCP server. |
exportView | Paginates a view fully (up to the limit) and returns the records as json / ndjson / csv text. | |
searchAllViews | Runs `/find?q=<keyword>` in parallel across every view (optionally scoped to an app) and returns the top matches per view. | |
| Workflows | upsertRecord | Looks up a record by uniqueField=uniqueValue. |
bulkUpdateRecords | Queries the view, evaluates the filter client-side, then PUTs the recordData to each matching record (bounded concurrency, default 4). | |
bulkDeleteRecords | Queries the view, evaluates the filter client-side, then DELETEs each matching record. | |
previewBulkUpdate | Takes the same {viewId, filter, recordData} as `bulkUpdateRecords` but performs no writes. | |
backupThenBulkUpdate | Step 1: paginate matching records and return them as an NDJSON resource (the backup). | |
| Compose | duplicateRecord | Fetches a record, strips system fields + id + caller-specified excludes, then creates a new record in the same view with the surviving field values plus any `overrides`. |
copyRecordsBetweenViews | Fetches records from sourceViewId (optionally filtered), remaps field names via fieldMapping, applies overrides, and batch-creates in targetViewId. | |
expandRecord | Fetches a record, then for each field in `relationshipMap` follows the 'fieldName(id)' relationship reference and embeds the linked record under a `${fieldName}__expanded` key. | |
| Discovery | whichViewHasField | Scans every view's structure (optionally scoped to an app) and returns the views whose field list contains a matching field. |
buildRecordGraph | Unifies `expandRecord`-style parent traversal with `listChildRecords`-style reverse lookup. | |
| Profile | findDuplicates | Paginates the view, groups records by the value of `field` (or a composite key from `fields[]`), and returns only the groups with count ≥ `minCount`. |
mergeDuplicates | Picks a primary record (per `keep` strategy), fills in gaps from the others per `onConflict`, updates the primary, then deletes the rest. | |
findMissingRequired | Reads the view's structure, identifies fields marked `required: true`, then scans records and returns those with any such field null/empty. | |
| Ingest | importRecordsFromCsv | Parses `csv` (or accepts a pre-parsed `records` array), optionally remaps column names via `fieldMapping`, casts values against the view's structure, then either batch-creates or upserts on `uniqueField`. |
previewImport | Same parse + cast + lint pipeline as `importRecordsFromCsv` but without writing. | |
| Aggregation | groupBy | Paginates the view (up to 10k records), optionally applies a filter, groups by `field`, then computes `aggregate` (count/sum/avg/min/max) over `valueField`. |
pivotRecords | Mirrors TrackVia's Pivot View. | |
trendRecords | Groups records into day/week/month/quarter/year buckets based on `dateField`, applies the aggregate, and returns `[{bucket, value}]` sorted ascending. | |
topN | Runs `groupBy` then slices the first N entries of the sorted result. | |
| State machines | transitionRecord | Fetches the record, verifies `statusField === fromStatus`, then writes `statusField = toStatus` (plus optional timestamp/note). |
advanceWorkflow | Queries for records where `statusField === fromStatus`, then runs `transitionRecord` semantics on each with bounded concurrency. | |
| Lifecycle | softDelete | Writes `archiveField = archiveValue` via updateRecord. |
restoreSoftDeleted | Inverse of `softDelete`. | |
| Resolver | resolveView | Returns `{viewId, viewName, appName, isDefault}` for the matching view, or `{match: null, candidates: [...]}` when the name is ambiguous. |
resolveField | Returns a single field's metadata from a view — type, required, unique, canCreate, canUpdate, and choices (if applicable). | |
resolveUser | Scans the account-users list and returns the first match. | |
| Scaffolding | scaffoldTable | Creates a table with its fields in a |
scaffoldApp | Creates an app, scaffolds each requested table (with fields inline), and by default creates at least one dashboard so the app has a landing surface from day one. | |
cloneAppStructure | **KNOWN BROKEN — platform bug, do not use.** The platform's app-create-from-template path (`AppService.populateTemplateApp`) hard-codes the 'Inventory Tracking' template and ignores both the supplied `templateId` query parameter and any body overrides — so this tool produces an Inventory Tracking app no matter which `sourceAppId` or `name` you pass. | |
inviteUserWithRoles | Creates an account user. | |
createRoleWithAccess | Creates a role and optionally pre-assigns users to it in one call. | |
createUserGroupWithMembers | Creates a user group. | |
| Cross-resource convenience | grantRoleAccessToView | GETs the role, splices a `{id, type:'resultProjection', actions[]}` entry into `resources.views[]` (replacing any prior entry for that viewId), then PUTs the role back. |
grantRoleAccessToForm | GETs the role, splices a `{id, type:'form', actions[]}` entry into `resources.forms[]`, then PUTs the role back. | |
revokeRoleAccess | Removes the matching grant from the role's `resources.{views|forms|tables}` list. | |
listRoleAccess | GETs the role and returns `{tables, views, forms}` lists with `{id, name?, permission}` entries — the high-level shape collapses the platform's `resources.*[]` action arrays back to `'read' | 'edit' | 'admin'` (or `'unknown'` when the action set is non-standard). | |
whoCanAccessView | Walks every role in the app and returns `{roleId, roleName, permission}` for each role with a grant on the given viewId. | |
duplicateView | GETs the source view, strips `id` and timestamps, applies `overrides`, then POSTs as a new view on the same table. | |
duplicateForm | GETs the source form, strips `id` and timestamps, applies `overrides`, then POSTs as a new form on the same table. | |
findViewsUsingField | Lists views on the table and returns those whose projection includes the given fieldMetaId. | |
findFormsUsingField | Fans out per-form GETs and returns the forms whose `elements[]` tree contains a Field referencing the given fieldMetaId. | |
| Form-authoring helpers | addFormShowHideRule | GETs the form, appends a rule entry to the form's top-level `rules[]` array, then PUTs the full form body back (Spring `@Valid` requires the complete FormRequest shape). |
setFormFieldDefault | GETs the form, locates the matching field element, sets its `defaultValue` setting, then PUTs the full form body. | |
togglePublicWebform | GETs the form, toggles the top-level `isPublic` boolean, then PUTs the full body back. | |
assignParentViewToRelationship | GETs the form, locates the relationship-typed field element, sets its `preferredParentView` to the supplied viewId, then PUTs the full body back. | |
bulkSetFieldRequiredOnForm | GETs the form, walks the elements tree, sets `required` on every matching field element, then PUTs the full body back. | |
addChildRecordSection | GETs the form, appends a child-view section element to the form's root container (or to top-level `elements` if no root container exists), then PUTs the full body back. | |
| View-authoring helpers | createPivotView | Creates a `pivotView` on the same table as `baseView`. |
createLanesView | Creates a `laneView` (kanban board) on the same table as `baseView`. | |
createCalendarView | Creates a `schedulerView` configured for month-grid calendar rendering. | |
createTimelineView | Creates a `schedulerView` configured for horizontal Gantt-style timeline rendering, with rows grouped by a relationship field's parent records. | |
createMapView | Creates a `mapView` on the same table as `baseView`. `locationField` is the pin coordinate; `colorField` (optional) colors each pin; `defaultZoom` (optional) sets the initial zoom. | |
createLineChartView | Creates a `chartView` of type `LineChart`. | |
createComboChartView | Creates a `chartView` of type `ComboChart` (mixed bar and line series). | |
createPieChartView | Creates a `chartView` of type `PieChart`. | |
createBarChartView | Creates a `chartView` of type `BarChart` (horizontal bars). | |
createAreaChartView | Creates a `chartView` of type `AreaChart`. | |
createSteppedAreaChartView | Creates a `chartView` of type `SteppedAreaChart` (staircase-style filled area, always stacked). | |
createColumnChartView | Creates a `chartView` of type `ColumnChart` (vertical bars). | |
createScatterChartView | Creates a `chartView` of type `ScatterChart`. | |
createParetoChartView | Creates a `chartView` of type `ParetoChart` (descending bars with a cumulative frequency line). | |
createBubbleChartView | Creates a `chartView` with `chartAttributes.type = 'BubbleChart'`. | |
createGanttChartView | Creates a `chartView` with `chartAttributes.type = 'Timeline'` (the Google Charts class name for Gantt-style bar charts). | |
createAggregateView | Creates a `gridView` with grouped rows and aggregated value columns — the platform's summary-grid variant. | |
addConditionalFormatRule | GETs the view's layout `/extra` blob (`{viewExtra: <jsonString>}`), parses it, splices a new rule of shape `{fieldId, operator, value, color, scope}` into the array under `extraKey`, then PUTs the JSON-stringified result back. | |
| Schema helpers | findFieldImpact | Returns the union of `findViewsUsingField` + `findFormsUsingField` PLUS a heuristic scan of flows and notification rules. |
createDependentDropdowns | Adds two `dropDown` fields to the table (parent first, then child) and stamps the parent->child mapping onto the child field under `dependencyMapping` (override via `dependencyMappingKey`). | |
createManyToMany | Creates a junction table and two MANY_TO_ONE relationships (junction -> tableA, junction -> tableB). | |
renameFieldSafely | Computes `findFieldImpact` first. | |
| Automation helpers | setupNotificationRule | End-to-end notification authoring: resolves viewId → location, maps `triggerFields` (field names) to fieldMetaIds via the view's projection, then POSTs a strict-shape NotificationRuleRequest to `/notificationRules`. |
publishDashboardToRole | Composes three platform primitives: GETs the dashboard, walks `elements[]` for embedded view IDs (view / viewShortCut / search / searchBarcode), grants the role read access on each via the role-permission GET-modify-PUT cycle, and optionally writes `homepageDashboardId` on the role payload. | |
listAccountAutomations | Walks every app in the account and aggregates flow + notification-rule summaries. | |
exportAccountSchemaSnapshot | Account-wide schema dump extending `exportAppSchema` with admin/automation surfaces. | |
createFlowFromTemplate | Stamps a name + `variables[]` scaffold and POSTs it to `/accounts/{a}/apps/{p}/flows`. | |
createDuplicatePreview | Paginates the view, groups records by the named `fields` composite key, and returns every group with count ≥ `minCount`. | |
| Record / user lifecycle helpers | summarizeRecordChanges | Reads the table's record history (the same endpoint getRecordHistory wraps), filters to the requested record + time range, and collapses each event into a flat list of `{fieldName, fromValue, toValue, modifiedAt, modifiedBy}` rows. |
restoreRecordsLeavingView | Finds records that recently fell out of a view (typically because a filter field was edited), and optionally reverts them. | |
offboardUser | Multi-step user lifecycle workflow: (1) deactivate the user (PUT status=Inactive); (2) when `reassignTo` + `userOwnedRecords` are provided, replace the user reference on each listed (viewId, fieldName) pair; (3) when `transferGroups:true` and `reassignTo` is set, move the user out of every group containing them and add `reassignTo` in their place; (4) when `removeFromRoles:true`, list every role this user belongs to and surface them as `pendingRoleRemovals` for the caller to finalize via assignUsersToRole. |
From your TrackVia account — exchange your API user credentials for a short-lived OAuth access token through TrackVia's OAuth flow. Refer to the TrackVia API docs for the exact steps; this server does not issue tokens.
No. Access tokens are extracted from request headers, used for the outbound TrackVia call, and discarded. The logger redacts credential fields rather than writing them.
X-TrackVia-Host?
Only when you need to point this request at a non-default TrackVia environment — e.g.
qa1.qa.xvia.com while developing against QA. The host must match the
hardcoded allowlist: *.trackvia.com, *.xvia.com, or
localhost. Omit the header to use the server's default host.
X-TrackVia-Account-Id?Only when you want to target a sandbox account inside the account your access token belongs to. Pass the sandbox's numeric account id; omit the header to use the access token's default account.
Once connected, ask your model in plain language. The server composes small tools into real workflows, so most of these are one sentence.
I'm new to this account. Give me a one-shot orientation — apps, views, and a few sample fields per view — so I know what I'm working with.
Tell me which tools this server exposes, when each was introduced, and whether any are marked experimental or deprecated.
Search every view in the "Operations" app for the word "urgent" and show me the top hits per view.
Which views anywhere in the account have a field called "Priority"?
Pull record 7421 from the "Orders" view with every field annotated — type,
required, writable, and linked ids.
Upsert this lead into the "Leads" view, keying on Email — update if it exists, otherwise create.
Preview what would happen if I set Status="Archived" on every record in "Old
Tickets" last updated before 2025-01-01. Don't write anything yet.
Back up every matching record first, then archive every "Inactive" contact in the "Contacts" view.
Here's a CSV of new leads. Dry-run the import first, using Email as the unique key, and tell me which rows would create vs. update vs. fail validation.
The dry run looks clean. Now actually run the import and upsert on Email.
Find duplicate contacts in the "Contacts" view grouped by email, case-insensitive, with at least 2 matches per cluster.
Take this cluster of duplicate contacts, merge them into one — keep the oldest record and fill any empty fields from the others.
In the "Projects" view, show me every record that's missing any required field, annotated with which fields are missing.
Build a 3-deep graph around record 7421 in "Orders" — every parent, every
child, every link.
Pull record 7421 from "Orders" and expand its Customer and Owner relationship
fields inline.
Export every "Active" deal as CSV with just Name, Amount, Stage, and CloseDate.
Page through the "Tickets" view filtered to Status="Open", sorted by Priority desc — return up to 5000 records.
Export the full schema of the "Operations" app so I can see every view, every field, every choice, and every relationship target in one JSON blob.
Describe the "Contacts" view — show me every field's type, requiredness, writability, and choices.
In "Orders", group by Status and show me the count and the sum of Amount per group.
Build a pivot of "Deals" with Stage across the rows and Region across the columns, averaging Amount.
Show me a month-by-month trend of new records created in "Leads" this year — bucket by CreatedAt.
Who are the top 10 customers by total order amount in "Orders"?
Move record 4412 from Status "Submitted" to "Approved" — only if it's still
"Submitted" right now — and stamp ApprovedAt with the current timestamp.
For every "Expense Report" still sitting in "Pending Manager" assigned to user 88, advance Status to "Pending Finance".
Archive record 8890 in "Contacts" by setting Archived=true and
ArchivedAt=now. Don't actually delete.
Restore record 8890 in "Contacts": Archived=false, clear ArchivedAt.
Invite these 20 users — pasted below as CSV — and tell me which rows failed and why. confirm: true.
Look up these emails in the account and return the user ids, plus any that didn't match.