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:

{
"mcpServers": {
"tailstats": {
"type": "http",
"url": "http://localhost:9876/mcp"
}
}
}

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):

{ "card": "build-status", "value": "Passing", "color": "green", "menuBar": true }

Example (multi-item):

{
"card": "project-status",
"items": [
{"title": "Project", "value": "TailStats"},
{"title": "Status", "value": "Complete", "color": "green"}
],
"columns": 2
}

Example (notification):

{
"card": "build-status",
"notification": {
"title": "Build Complete",
"body": "All tests passed",
"sound": "default"
}
}
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:

{
"mcpServers": {
"tailstats": {
"type": "http",
"url": "https://app.tailstats.com/mcp/tailstats",
"headers": {
"Authorization": "Bearer YOUR_API_TOKEN"
}
}
}
}
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

GET /workspaces/{workspace}/cards

Returns all cards in the workspace.

Response:

{
  "data": [
    {
      "cardId": "build-status",
      "name": "Build Status",
      "source": "push",
      ...
    }
  ]
}

Get Card

GET /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

POST /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

PUT /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

DELETE /cards/{cardId}

Deletes a card and its data. Workspace resolved from token. Returns 204.

Get Card Data

GET /cards/{cardId}/data

Returns the current data/value for a card. Workspace resolved from token.

Push Card Data

POST /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

DELETE /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:

  1. If confirm is set, show confirmation dialog. Cancel aborts.
  2. If inputs is set, show form sheet. Cancel aborts.
  3. Button enters loading state (spinner). Sibling buttons are disabled.
  4. Interpolate all exec fields with context values.
  5. Execute the HTTP request or script.
  6. On success: show checkmark (2s), display toast. If updateCard is true, parse response as card data; otherwise refresh card. Optionally send notification.
  7. 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:

  1. Cards display their last successful data
  2. A "stale" indicator shows data may be outdated
  3. Last successful update time is displayed
  4. 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