android-timeline-mcp

android-timeline-mcp

Read-only MCP server exposing Android phone timeline data, including events, hourly/daily features, data coverage, and gaps, so Claude can answer questions about observed phone activity.

Category
Visit Server

README

android-timeline-home-assistant

CI Integration Cross-repository E2E Build app Security License: MIT

Status: experimental. The server side is exercised end to end in CI against the real collector, but no physical Android phone has ever fed it. See Current limitations.

A Home Assistant app (formerly "add-on") that receives raw timestamped events from the android-timeline-termux collector, stores them immutably, derives versioned hourly and daily features, measures how much of each day was actually observed, publishes a handful of summary entities, and exposes a read-only MCP server so Claude can ask questions about the data.

What it does

  • Authenticated ingestion. Device-specific bearer tokens, stored only as keyed hashes. Idempotent on event_id, so a replay is always a no-op.
  • Immutable raw events. Features are derived and versioned; recomputing them never rewrites history.
  • Explicit missingness. Every hour is a row, including the empty ones. A flat line and a dead collector are different things and are reported differently.
  • Read-only MCP. No SQL, no shell, no filesystem, no mutation, no phone control. Bounded ranges, pagination, and redaction that cannot be turned off.
  • Minimal privileges. Ingress only, no published port, no Supervisor role, no Home Assistant directory mounted.

Architecture

flowchart TD
    phone["Android phone<br/><i>android-timeline-termux</i>"]

    subgraph app["Home Assistant app (this repository)"]
        direction TB
        api["FastAPI ingestion<br/>POST /api/v1/events/batch"]
        auth["Device token auth<br/>+ rate limiting"]
        store[("SQLite event store<br/>append-only")]
        features["Feature pipeline<br/>hourly + daily, versioned"]
        cov["Coverage and gap detection"]
        tl["Timeline API<br/>GET /api/v1/timeline/yesterday"]
        mcp["Read-only MCP server<br/>/mcp"]
        ent["Summary entity publisher"]

        api --> auth --> store
        store --> features --> cov
        cov --> tl
        cov --> mcp
        features --> ent
    end

    ha["Home Assistant Core<br/>sensor.* / binary_sensor.*"]
    claude["Claude / MCP client"]

    phone -->|"HTTPS, Bearer token,<br/>X-Batch-ID"| api
    api -->|"per-event acknowledgement"| phone
    ent -->|"Supervisor API proxy"| ha
    mcp --> claude

Installation

  1. In Home Assistant: Settings -> Apps -> App store -> ⋮ -> Repositories

  2. Add https://github.com/resace3/android-timeline-home-assistant

  3. Install Android Timeline from the store, then Start it.

  4. Open the app's web UI (ingress) to reach the diagnostic page.

  5. Enroll your phone:

    curl -X POST http://<app>/api/v1/admin/devices \
      -H 'Content-Type: application/json' \
      -d '{"device_id": "device-my-pixel-001"}'
    

    The response contains the device token once. Copy it into the collector's ~/.config/android-timeline/token. Only a keyed hash is stored here; there is no way to recover it later, only to rotate.

Full details, including running behind ingress and the optional custom integration: docs/installation.md.

Configuration

Option Default Notes
timezone UTC Where a "day" starts. Events are always stored in UTC.
features_enabled true Turning it off stops the pipeline; nothing is deleted.
publish_entities true Summary entities only, never one per event.
mcp_enabled true Read-only MCP endpoint, ingress-protected.
trust_ingress_admin true Safe because no port is published.
admin_token (empty) Only needed outside ingress.
retention_enabled false Raw events are kept forever by default.

API

Endpoint Auth Purpose
GET /api/v1/health none liveness; no user data
POST /api/v1/events/batch device token ingestion
GET /api/v1/devices/{id}/status device token (own device) queue and sync state
GET /api/v1/timeline/yesterday admin the day timeline
GET /api/v1/timeline/{date} admin a specific local date
GET /api/v1/features/hourly admin stored hourly features
GET /api/v1/coverage admin coverage and gaps
POST /api/v1/admin/devices admin enroll, returns a token once
POST /api/v1/admin/devices/{id}/rotate admin rotate, revoking the old token
DELETE /api/v1/admin/tokens/{id} admin revoke

MCP

Twelve read-only tools: list_devices, list_phone_sources, get_phone_latest, query_phone_events, get_day_timeline, get_hourly_features, get_daily_features, get_data_coverage, find_data_gaps, get_collector_status, export_phone_window and describe_server.

Guaranteed absent: arbitrary SQL, shell execution, filesystem access, mutation of any kind, and phone control. Date ranges are capped at 31 days, pages at 1000 rows, and precise coordinates, message bodies and contact names are stripped with no parameter to re-enable them.

Client configuration (placeholders only): docs/mcp.md.

Testing

Layer Status What it proves
Unit required database, auth, ingestion, features, coverage, timeline
API + MCP required the HTTP surface and the MCP protocol, in-process
Contract required Pydantic models and published JSON Schemas agree
E2E (in-process) required synthetic day -> ingest -> features -> timeline -> MCP, across a restart
Container (Layer A) required the real image: build, boot, drive, restart
Mock Supervisor (Layer B) required the one Supervisor endpoint this app calls
App image build (Layer D) required current official HA builder actions, amd64 + aarch64
Cross-repository E2E required the real collector uploading to the real image
Home Assistant Core (Layer C) non-blocking the custom integration loads in a real HA container
Supervised HA (Layer E) not attempted see below

The cross-repository workflow installs the actual collector from android-timeline-termux at a pinned revision, runs its own outbox and uploader against a container built from this repository, then asserts on storage, idempotency, features, coverage and MCP. Details: docs/testing.md.

Current limitations

Stated plainly:

  • No physical phone has ever fed this. Every event CI has ever ingested is synthetic.
  • Supervisor is not tested in CI. A real Supervisor needs privileged Docker-in-Docker or a full OS image; a flaky green result would be worse than an honest gap. Layer B tests the one endpoint this app actually calls, and nothing more.
  • Ingress trust is a design assumption. Treating an ingress request as an authenticated admin is only safe because no port is published. If you publish one, set admin_token and turn trust_ingress_admin off.
  • SQLite, single writer. Fine for a personal deployment; not a fleet.
  • Features are approximations. charging_minutes and wifi_connected_minutes are inferred from periodic samples, so a state change between samples is invisible. Every value ships with a coverage proportion for exactly this reason.
  • The timeline has no polished UI. The / page is a diagnostic table.

Privacy considerations

  • Raw events are stored as the phone sent them; the phone is where redaction happens, and it defaults to metadata only.
  • The MCP server redacts precise coordinates, message bodies and contact names again on the way out, with no override.
  • Home Assistant entities carry aggregates only, so the recorder database never accumulates behavioural detail.
  • No fixture, test or CI artifact contains real personal data, and CI fails if a credential-shaped string appears anywhere in history.

Relationship to the other repository

android-timeline-termux runs on the phone: collection, the outbox, the upload client
This repository runs in Home Assistant: ingestion, storage, features, coverage, MCP

This repository is the source of truth for the protocol schemas in schemas/. The collector vendors a byte-identical copy; the cross-repository workflow diffs them directly and fails on any difference. Both speak protocol_version 1. Compatibility policy: docs/data-model.md.

Development

python -m pip install -e ".[dev]"
ruff format . && ruff check . && mypy
pytest

Run the whole pipeline locally without Home Assistant:

docker compose -f test-harness/docker-compose.yml up --build

Roadmap

  • [ ] Ingest from a real phone (blocking for 1.0)
  • [ ] QR-code device enrollment
  • [ ] A real timeline UI
  • [ ] Optional Postgres backend for larger deployments
  • [ ] Intervention annotations feeding the causal-inference use case
  • [ ] Feature definitions v2 with dwell-time and place transitions

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured