Documentation
MCP, REST API & Actions
Server-side integration: MCP for AI tools, REST API for everything else, and interactive actions on your cards.
MCP Support
TailStats supports the Model Context Protocol (MCP), enabling AI assistants like Claude to directly interact with your dashboard cards.
What is MCP?
MCP (Model Context Protocol) is an open standard by Anthropic that allows AI assistants to use external tools. With TailStats MCP support, AI coding agents can list, read, update, and create cards.
Setup
1. Enable Local Push Server
In TailStats, go to Settings → General → Local Push Server and enable:
- Local Push Server (master toggle)
- HTTP & WebSocket
2. Configure Claude Code
Add to ~/.claude/settings.json:
3. Start Using
Ask Claude naturally:
- "List my TailStats cards"
- "Update the build-status card to 'Passing' with green color"
- "Create a card called 'Deploy Status' with identifier 'deploy'"
Available Tools
list_cards
List all TailStats cards with their current values and status.
Parameters:
None
read_card
Read detailed data from a specific card.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| card | string | Yes | Card name or identifier |
update_card
Push new data to a Local Push card. Supports three modes (exactly one required): value, items, or notification.
Parameters:
| Name | Type | Description |
|---|---|---|
| card | string | Card identifier (required) |
| value | string | Value to display (single item mode) |
| title | string | Title/label for the value |
| type | string | string, number, progress, status |
| color | string | Color name or hex (red, green, #FF5500) |
| icon | string | SF Symbol name |
| emoji | string | Emoji to display |
| items | array | Array of items (multi-item mode) |
| notification | object | Send notification: {title, body?, subtitle?, sound?} |
| columns | integer | Grid columns (1-4) |
| menuBar | boolean | Show in menu bar |
Example (single item):
Example (multi-item):
Example (notification):
create_card
Create a new Local Push card for AI/automation updates.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Display name for the card |
| identifier | string | Yes | Unique identifier for push updates |
Use Cases
AI Coding Agent Tracking
Track Claude Code, Codex, or other AI agents in real-time. Show task status, project names, and completion states.
Build Pipeline Status
Display CI/CD status on your desktop. Show build, test, and deploy states with color-coded indicators.
Project Dashboard
Create a multi-project overview with status indicators for frontend, backend, and mobile progress.
Progress Tracking
Show completion progress for migrations, deployments, or long-running tasks with progress bars.
Cloud MCP (Remote)
For syncing across devices or accessing from remote AI agents, use the Cloud MCP endpoint with your API token.
Claude Code Configuration:
| Feature | Local MCP | Cloud MCP |
|---|---|---|
| Endpoint | localhost:9876/mcp | app.tailstats.com/mcp/tailstats |
| Authentication | None (localhost only) | Bearer token |
| Cross-device sync | No | Yes (via Supabase) |
| Extra parameter | — | workspace_id (optional) |
Security: Local MCP only accepts connections from localhost. Cloud MCP requires Bearer token authentication. All tools use the same API contract.
REST API
Manage cards and card data programmatically via the TailStats REST API.
Authentication
All requests require a Bearer token. Generate an API token in Settings → API Tokens.
Base URL:
https://app.tailstats.com/api/v1
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json
List Cards
/workspaces/{workspace}/cards
Returns all cards in the workspace.
Response:
{
"data": [
{
"cardId": "build-status",
"name": "Build Status",
"source": "push",
...
}
]
}
Get Card
/cards/{cardId}
Returns a single card by identifier. Workspace resolved from token.
Response:
{
"data": {
"workspaceId": "ws_abc123",
"cardId": "build-status",
"name": "Build Status",
"source": "push",
"url": null,
"refreshInterval": null,
"headers": null,
"jsonPath": null,
"filePath": null,
"parsingMode": null,
"authType": null,
"oauth2": null,
"jsonPathExtractions": null,
"displayRules": null,
"menuBar": null,
"createdAt": "2025-03-15T10:30:00Z",
"updatedAt": "2025-03-15T10:30:00Z"
}
}
Create Card
/workspaces/{workspace}/cards
Creates a new card. The cardId is auto-generated from the name if not provided.
Body Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Display name (max 255) |
| source | string | Yes | remote, push, localPush, or fileWatch |
| cardId | string | No | Custom identifier (auto-generated from name if omitted) |
| url | string | Conditional | API endpoint URL (required for remote source) |
| refreshInterval | integer | No | Polling interval in seconds (10–86400, remote only) |
| headers | object | No | Custom HTTP headers for remote requests |
| authType | string | No | none, basic, bearer, or oauth2 |
| jsonPath | string | No | JSONPath expression (remote source) |
| jsonPathExtractions | array | No | Multiple JSONPath extractions |
| displayRules | array | No | Conditional display rules |
| menuBar | object | No | Menu bar config: {enabled, background, textColor} |
Example:
POST /api/v1/workspaces/ws_abc123/cards
{
"name": "Deploy Status",
"source": "push",
"cardId": "deploy-status"
}
Returns 201 with the created card.
Upsert Card
/cards/{cardId}
Creates or updates a card. Same body parameters as Create Card. Workspace resolved from token.
Example:
PUT /api/v1/cards/deploy-status
{
"name": "Deploy Status",
"source": "push"
}
Returns 200 if updated, 201 if created.
Delete Card
/cards/{cardId}
Deletes a card and its data. Workspace resolved from token. Returns 204.
Get Card Data
/cards/{cardId}/data
Returns the current data/value for a card. Workspace resolved from token.
Push Card Data
/cards/{cardId}/data
Push data to a card. Supports three modes — exactly one required.
Body Parameters:
| Name | Type | Description |
|---|---|---|
| value | any | Single value (simple mode) |
| title | string | Label for value (default: "Value") |
| type | string | Display type (string, number, progress, etc.) |
| items | array | Array of items (multi-item mode) |
| notification | object | {title, body?, subtitle?, sound?} |
| columns | integer | Grid columns (1–4) |
Example (simple):
POST /api/v1/cards/build-status/data
{"value": "Passing", "title": "Build", "type": "status"}
Example (items):
POST /api/v1/cards/project-status/data
{
"items": [
{"title": "Tests", "value": "142 passed", "color": "green"},
{"title": "Coverage", "value": 94, "type": "progress"}
],
"columns": 2
}
Returns 200 with {"success": true}.
Clear Card Data
/cards/{cardId}/data
Clears all data from a card without deleting the card itself. Returns 204.
Token Abilities: API tokens can be scoped with read and write abilities. GET endpoints require read, all others require write.
Actions
Add interactive buttons to cards that trigger HTTP requests, with optional confirmation dialogs, form inputs, and post-execution feedback.
Available on macOS, iOS, and Android. HTTP-based actions work on all platforms. Script execution is macOS only.
Overview
Actions can be attached at two levels:
Card-Level
Top-level actions array in the push payload. Always visible as a button row at the bottom of the card.
Item-Level
Per-item actions array on individual items. Revealed on hover (desktop).
Quick Example
Push a card with deploy, restart, and stop buttons:
curl -X POST http://localhost:9876/push/deploy-control \
-H "Content-Type: application/json" \
-d '{
"items": [
{"title": "Production", "type": "status", "value": "Running", "level": "ok"}
],
"actions": [
{
"id": "deploy",
"label": "Deploy",
"icon": "arrow.up.circle",
"style": "primary",
"confirm": "Deploy to production?",
"inputs": [
{
"id": "branch",
"label": "Branch",
"type": "text",
"value": "main",
"required": true
},
{
"id": "env",
"label": "Environment",
"type": "select",
"options": [
{"label": "Production", "value": "prod"},
{"label": "Staging", "value": "staging"}
],
"value": "prod"
}
],
"exec": {
"type": "http",
"url": "https://api.example.com/deploy",
"method": "POST",
"body": {
"branch": "${input.branch}",
"env": "${input.env}"
}
},
"result": {
"message": "Deployment started!"
}
},
{
"id": "restart",
"label": "Restart",
"icon": "arrow.clockwise",
"confirm": "Restart the server?"
},
{
"id": "stop",
"label": "Stop Server",
"icon": "stop.circle",
"style": "destructive",
"confirm": "Stop the production server?"
}
]
}'
Action Fields
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique identifier |
| label | string | Yes | Button text |
| icon | string | No | SF Symbol icon name |
| style | string | No | default, primary, or destructive |
| confirm | string | No | Confirmation dialog text. Supports ${...} interpolation |
| inputs | array | No | Form fields shown before execution |
| exec | object | Yes | What to execute when triggered |
| result | object | No | Post-execution feedback |
Button Styles
| Style | Appearance | Use Case |
|---|---|---|
| default | Subtle background | Secondary actions (restart, refresh) |
| primary | Accent color | Main actions (deploy, save) |
| destructive | Red tint | Dangerous actions (stop, delete) |
Execution
The exec object defines what happens when a button is pressed.
| Field | Type | Description |
|---|---|---|
| type | string | http or script |
| url | string | HTTP URL with ${...} interpolation |
| method | string | HTTP method. Default: POST |
| headers | object | HTTP headers with ${...} interpolation |
| body | any | JSON body — strings are interpolated recursively |
| path | string | Script: absolute path to executable |
| args | array | Script: arguments with ${...} interpolation |
HTTP example:
"exec": {
"type": "http",
"url": "https://api.example.com/deploy",
"method": "POST",
"headers": {"Authorization": "Bearer ${card.id}"},
"body": {"branch": "${input.branch}", "env": "${input.env}"}
}
Script example (macOS only):
"exec": {
"type": "script",
"path": "/usr/local/bin/deploy.sh",
"args": ["--branch", "${input.branch}", "--env", "${input.env}"]
}
Form Inputs
Add an inputs array to show a form sheet before execution. Each input value is available via ${input.<id>} in interpolation.
| Field | Type | Description |
|---|---|---|
| id | string | Unique ID, used as key in ${input.<id>} |
| label | string | Label shown above the input |
| type | string | text, textarea, select, radio, checkbox, file, directory, number, slider, toggle, date, color, password |
| placeholder | string | Placeholder text (text/textarea/password/file) |
| options | array | Choices for select/radio/checkbox. Strings or {"label", "value"} objects |
| value | string | Default value. Checkbox: comma-separated. Toggle: "true"/"false". Date: ISO 8601. Color: hex (e.g. "#FF5733") |
| required | boolean | Block submit if empty. Default: false |
| min | number | Minimum value (number/slider) |
| max | number | Maximum value (number/slider) |
| step | number | Step increment (number/slider). Default: 1 |
| accept | string | Comma-separated file extensions for file picker (e.g. "csv,json,txt"). Ignored for directory type. |
Interpolation
All string fields in exec, confirm, and result support token interpolation:
| Token | Resolves To |
|---|---|
| ${card.id} | Card UUID |
| ${card.name} | Card display name |
| ${item.id} | Item ID (item-level actions only) |
| ${item.title} | Item title |
| ${item.value} | Item display value as string |
| ${input.<id>} | Form input value by input ID |
Result Feedback
Control what happens after execution with the result object:
| Field | Type | Description |
|---|---|---|
| message | string | Toast message shown on success |
| refresh | boolean | Auto-refresh card after execution. Default: true. Skipped when updateCard succeeds. |
| updateCard | boolean | Parse the action's HTTP response body (or script stdout) as card data and update the card directly. Supports {"items": [...]} format and simple values. Eliminates the need for a separate refresh round-trip. |
| notification | object | System notification with title and body |
| refreshCards | array<string> | Names of other cards to refresh after success (additive with refresh: true's self-refresh). Missing names log + no-op; duplicate names fan out. macOS |
| emit | object | Fire an event on the in-process bus after success: {event: string, data?: object<string,string>}. The data values support ${...} interpolation. macOS |
| onFailure | object | Sibling branch run only when exec fails. Supports refreshCards, notification, and emit. macOS |
| patch | object | Partial card-data update: {items?: [...], columns?: int}. Matches items[*].id against existing items and deep-merges; never adds or removes items. Every string inside supports ${event.*} / ${state.*} / ${input.*} interpolation. macOS |
Optional exec: on clients that implement the events runtime, an action's exec block can be omitted entirely — the action then runs no HTTP/script and just fires its result side effects (emit, patch, refreshCards, notification). Useful for list-row clicks that only emit an event, and for reaction subscribers that only patch their own fields from the triggering event payload.
Top-level on map: push payloads can carry "on": { "eventName": <CardAction> } to install reaction subscribers on the target card. Each value is a full CardAction with the same result shape documented above. Reactions fire on the local bus only (in-process per device; no cross-device routing). Clients without the events runtime decode and ignore on.
Execution Flow
When a user taps an action button:
- If
confirmis set, show confirmation dialog. Cancel aborts. - If
inputsis set, show form sheet. Cancel aborts. - Button enters loading state (spinner). Sibling buttons are disabled.
- Interpolate all
execfields with context values. - Execute the HTTP request or script.
- On success: show checkmark (2s), display toast. If
updateCardis true, parse response as card data; otherwise refresh card. Optionally send notification. - On error: show error indicator (4s), display error toast.
Update Card from Response
Use updateCard: true to parse the action's HTTP response (or script stdout) as card data and apply it directly — no separate refresh needed.
{
"items": [
{"title": "Revenue", "type": "number", "value": 1250, "format": "currency:USD"}
],
"actions": [
{
"id": "refresh-metrics",
"label": "Refresh",
"icon": "arrow.clockwise",
"exec": {
"type": "http",
"url": "https://api.example.com/dashboard",
"method": "GET"
},
"result": {
"updateCard": true
}
}
]
}
The endpoint should return card data in the standard format:
// Response from https://api.example.com/dashboard
{
"items": [
{"title": "Revenue", "type": "number", "value": 1340, "format": "currency:USD"},
{"title": "Users", "type": "number", "value": 892, "format": "number:compact"}
],
"columns": 2
}
How it works: When the action succeeds, the response body is parsed as {"items": [...]} and applied to the card immediately. If parsing fails, the card falls back to a normal refresh. Works with both HTTP actions and script actions (stdout is parsed).
Item-Level Actions
Add actions to individual items. Buttons appear on hover, trailing the item row.
{
"items": [
{
"id": "server-1",
"title": "Production",
"type": "status",
"value": "Running",
"level": "ok",
"actions": [
{
"id": "ssh",
"label": "SSH",
"icon": "terminal",
"exec": {
"type": "http",
"url": "https://api.example.com/ssh/${item.id}"
}
}
]
}
]
}
1–2 actions show inline. 3+ actions collapse into an overflow menu.
Security: Actions execute HTTP requests from the user's device. Ensure your endpoints use proper authentication. Script execution is only available on macOS.
Error Handling
TailStats handles errors gracefully to keep your dashboard running.
Error Types
| Error | Cause | Display |
|---|---|---|
| Offline | No internet connection | Shows cached data with "offline" indicator |
| Timeout | Request took longer than 30 seconds | Shows cached data or error |
| Server Error | HTTP 500+ response | Shows error with status code |
| Not Found | HTTP 400+ response | Shows error with status code |
| Invalid URL | Malformed URL | Shows configuration error |
| Parse Error | Response isn't valid JSON | Shows parse error |
| Auth Error | Authentication failed | Shows auth error message |
| JSONPath Error | Path doesn't match data | Shows path error |
Offline Behavior
When your device goes offline:
- Cards display their last successful data
- A "stale" indicator shows data may be outdated
- Last successful update time is displayed
- Data refreshes automatically when back online
Partial Failures
For cards with multiple JSONPath extractions:
- Successfully extracted values are displayed
- Failed extractions show individual errors
- One failing extraction doesn't hide the others