Blog

  • Building an MCP Server to Let Claude Read My Blood Sugar

    Disclaimer: Think carefully before exposing your data to any third party — this is doubly important with health data. Everything here is for fun and in no way should be construed as medical advice.

    Overview

    A few years back I was diagnosed with type 2 diabetes — due to a series of lab errors. This BBC News article has more detail, but in short: my HbA1c was reported five points over its actual value, making me officially diabetic. It came as a shock, and brought with it a whole lot of worry.

    Shortly after I got the news, I was invited to the local surgery to have a Libre 2 sensor explained and fitted. These are small discs that stick a needle into your arm and report your blood sugar to an app on your phone.

    Abbott’s LibreView dashboard is fine for glancing at trends. But I wanted to interrogate my data: correlate glucose spikes with meals, compare patterns across weeks, ask questions I hadn’t thought of yet. Most of all, I wanted my data on my server.

    This post covers step one: building an MCP server to make that data conversational.

    What is MCP?

    Model Context Protocol is Anthropic’s open standard for connecting AI assistants to external data sources. Instead of copying and pasting data into Claude, you build a small server that exposes tools Claude can call directly.

    You define what data is accessible and how it authenticates. Claude does the rest.

    For my glucose data, this means I can ask things like:

    • “What was my average blood sugar last week?”
    • “Show me a graph of my readings over the past 24 hours”
    • “What time of day do I typically see spikes?”

    And Claude will fetch live data, analyse it, and respond conversationally.

    The Architecture

    Before the code, a few design decisions worth explaining.

    FastMCP over raw MCP: The mcp library has a low-level server API, but FastMCP gives you a decorator-based interface that’s much closer to how you’d write a Flask or FastAPI app. For a project this size, the abstractions are net positive — you get tool registration, schema generation, and transport handling for free.

    stdio transport: MCP supports both stdio and HTTP transports. For a local desktop integration (Claude Desktop), stdio is simpler — no ports, no auth, no networking. The server process is spawned by the client and communicates over stdin/stdout. The trade-off is that it’s desktop-only; an HTTP transport would be needed for remote access.

    uv for dependency management: Using uv keeps the project isolated and makes the Claude Desktop config clean. The entire run command is uv --directory /path/to/gcm-mcp run main.py — no virtualenv activation, no path juggling.

    Connection pooling: One thing to be aware of with the pattern below is that you don’t want to re-authenticate on every tool call. In the real implementation, the PyLibreLinkUp client is initialised once at module load, not inside each function.

    The Implementation

    The server is around 100 lines of Python. The core structure:

    from mcp.server.fastmcp import FastMCP
    from pylibrelinkup import PyLibreLinkUp
    import os
    
    mcp = FastMCP("blood_sugar")
    
    # Initialise once at module load — not per-call
    client = PyLibreLinkUp(
        username=os.getenv("API_USERNAME"),
        password=os.getenv("API_PASSWORD")
    )
    
    @mcp.tool()
    def get_blood_sugar() -> dict:
        """Fetch current blood sugar reading from Libre sensor."""
        return client.get_current()
    
    @mcp.tool()
    def get_blood_sugar_history() -> dict:
        """Fetch blood sugar history from Libre sensor."""
        return client.get_history()
    
    if __name__ == "__main__":
        mcp.run(transport="stdio")

    The @mcp.tool() decorator handles everything: registering the function, generating a JSON schema from the type hints and docstring, and exposing it to Claude. When you ask “what’s my current blood sugar?”, Claude matches the question to the right tool, calls it, receives the JSON, and formulates a human-readable reply.

    Configuration lives in Claude’s desktop config file. usually ~/Library/Application\ Support/Claude/claude_desktop_config.json:

    "mcpServers": {
        "blood_sugar": {
            "command": "uv",
            "args": ["--directory", "/path/to/git-checkout/gcm-mcp", "run", "main.py"],
            "env": {
                "API_USERNAME": "your@email.com",
                "API_PASSWORD": "your-password"
            }
        }
    }

    What Can You Do With It?

    Simple queries: “What’s my blood sugar right now?” returns the current reading with trend direction.

    Analysis: “Draw a graph of my blood sugar over the past 24 hours” – Claude fetches the history, generates a visualisation, and displays it inline.

    Pattern recognition: “When do I typically see my highest readings?” – Claude analyses the timestamps and surfaces patterns I might have missed in a static dashboard.

    The key insight is that this isn’t just a dashboard replacement. It’s a conversational interface to my health data. I can ask follow-up questions, request different visualisations, and explore correlations – without switching contexts or learning a new tool.


    Why Build This?

    Partly curiosity. MCP was new and I wanted to understand how it worked from the inside.

    Partly practical. I genuinely wanted better access to my glucose data, and the official tools weren’t designed for interrogation.

    But mostly, I think something interesting is happening here. We’re moving from “apps that display your data” to “assistants that understand your data”. The interface is no longer a dashboard.

    For health data, this matters. I don’t always know what questions to ask. A dashboard shows me what its designers anticipated. A conversational interface can explore the unexpected.

    Try It Yourself

    Try It Yourself

    The code is on GitHub: github.com/chrishannam/gcm-mcp

    You’ll need:

    • A Freestyle Libre 2 Plus sensor (or compatible)
    • A LibreLinkUp account connected to your sensor
    • Claude Desktop with MCP support
    • Python and uv for dependency management

    Setup takes about ten minutes. The README walks through the configuration. Some Python knowledge is needed at the moment – there’s no GUI setup flow yet.

    What I Built Next

    After getting this working, I extended the same pattern to pull in other health data sources: blood pressure and body composition from my Withings devices, and activity data from Strava. I also added observability with Logfire so I could trace tool calls across all three MCP servers.

    That architecture – multiple data sources, a unified conversational interface, and proper instrumentation – is covered in the next post: Building a Personal Health Data Platform with MCP, Withings, Strava, and Logfire (coming soon).

    If you’re sitting on interesting personal data and want to make it conversational, MCP is worth exploring. Just take care, it’s your data, and no AI assistant is a substitute for a trained medical professional.


    Chris Hannam is a software engineer with 20+ years of Python experience, currently based in Northern England. He’s interested in health tech, data engineering, and building tools that make complex information accessible.

    Chris's Blog

    My thoughts and projects.

    Twenty Twenty-Five

    Designed with WordPress

  • Withings MCP

    Talking to My Scales: A Withings MCP Server

    I’ve been building a small collection of personal MCP (Model Context Protocol) servers that let an AI assistant like Claude pull data from the services I actually use — Strava, Spotify, Garmin, and my Withings body scale. This post covers the Withings one: how it authenticates, what it exposes, and how to set up the developer application on Withings’ side so it actually works.

    What the Withings MCP server does

    At its core, the server is a thin, read-only wrapper around the Withings Public API. It exposes a handful of MCP tools that an assistant can call:

    • withings_body_measures — returns a time series of weight, fat mass, muscle mass, fat ratio, and vascular age over a given date range (or a rolling number of days), with options to downsample to one reading per day and cap the total number of points returned.
    • withings_latest_body — a convenience wrapper that just returns the most recent reading for each of those metrics.
    • withings_ecg_list — lists ECG recordings and AFib classifications taken with a Withings device, paginated with offset/limit.
    • withings_ecg_get — fetches the raw ECG signal for a specific recording, truncated to a sensible number of samples so it doesn’t flood the conversation.

    Nothing here writes data back to Withings — it’s purely a read layer that turns “what was my weight trend last month?” into a couple of API calls the assistant can make on its own.

    How authentication works

    Withings uses standard OAuth2. Rather than have each MCP server run its own OAuth dance, I built one small FastAPI app that handles the browser-based authorization flow for Strava, Spotify, and Withings together. You open it in a browser once, click “Connect Withings,” approve the requested scopes, and it stores the resulting access and refresh tokens in a local SQLite database. From then on, the MCP server reads the token straight out of that database. If the access token has expired, it transparently refreshes it using the stored refresh token before making the API call — so once you’ve connected your account, you shouldn’t need to touch the browser again unless Withings revokes access.

    Setting up the application on the Withings developer site

    Before any of this works, you need to register an application with Withings so it will hand out a client ID and secret. Here’s the process:

    • Create a new OAuth application from the developer dashboard.
    • Set the application’s redirect URI. For local development this is:
      http://127.0.0.1:8888/auth/withings/callback
    • Once the application is created, copy the Client ID and Client Secret Withings gives you.

    Drop those values into your .env file:

    WITHINGS_CLIENT_ID="your-withings-client-id"
    WITHINGS_CLIENT_SECRET="your-withings-client-secret"
    WITHINGS_REDIRECTION_URI="http://127.0.0.1:8888/auth/withings/callback"
    WITHINGS_API_ENDPOINT="https://wbsapi.withings.net"

    The redirect URI in your .env file needs to match the one registered in the Withings app exactly — same scheme, host, port, and path. A mismatch here is the most common reason the token exchange fails.

    Connecting your account

    With the credentials in place, start the OAuth app:

    uv run uvicorn main:app --host 127.0.0.1 --port 8888 --reload

    Open http://127.0.0.1:8888 in a browser, click the Withings connect button, and approve the requested scopes — in this case user.infouser.metrics, and user.activity. Withings redirects back to the callback URL, and a row gets written to a local withings_tokens table with your access and refresh tokens.

    From there, you can run the Withings server on its own:

    uv run python mcp_servers/withings_mcp.py

    or as part of the combined server that also exposes Strava, Spotify, and Garmin tools together:

    uv run python mcp_servers/connected_services_mcp.py

    Why bother with a whole MCP server for this?

    The appeal is being able to ask an assistant something like “how has my weight trended over the last three months?” or “did I have any AFib flags on my last few ECGs?” and have it genuinely go fetch that data rather than guess. Once the OAuth handshake is done, the assistant doesn’t need any special knowledge of Withings’ API shape, it just calls a tool with a date range and gets clean, already-summarised data back.

    It’s a small piece of infrastructure, but it’s the kind of thing that makes an AI assistant feel less like a chatbot and more like something that’s actually looking at your data.

  • Straify – Strava meet Spotify

    Straify: Finding My Running Rhythm Through Data

    From Curiosity to Comprehensive Health Tracking

    It started with a simple question: Which Spotify tracks make me run faster?

    As a runner who always trains with music, I thought I picked up the pace and pushed on during certain songs.

    That curiosity led me to build Straify, a project that began as a way to correlate my Spotify listening history with my Strava running data. What started as a single integration has morphed into a data platform that brings together my strava activities, music listening habits, and biometric measurements into one place.

    The Core Idea: Music Meets Motion

    The point of Straify is answering that original question about music and running performance. Here’s how it works:

    1. Pull running data from Strava – Every run includes timestamps, GPS tracks, pace splits, heart rate, and distance
    2. Sync Spotify playback history – Track exactly what songs were playing during each activity
    3. Match timestamps – Map each song to specific points in the run, down to GPS coordinates
    4. Analyze pace correlation – Calculate running pace during each track to identify “pace boosters”

    The result? I can now see definitively which tracks correlate with my fastest splits. Well mostly… The first few tracks tend to creep to the top as I’m usually running faster at the start.

    Beyond Music: Expanding the Health Data Universe

    Once I had the Strava-Spotify integration working, I realised the potential for a broader health tracking platform.

    Withings Health Metrics

    I integrated my Withings smart scale to track:

    • Body composition: Weight, fat mass, muscle mass, and fat percentage over time
    • Vascular age: An interesting metric that estimates cardiovascular health
    • ECG recordings: Heart rhythm data with AFib detection

    Now I can correlate my running volume with body composition changes, or see if increased exercise impacts my vascular age.

    The Full Picture

    Straify now connects three major data sources:

    Strava – Running and fitness activities

    • Distance, pace, heart rate, elevation
    • GPS tracks and photos
    • Activity splits and performance metrics

    Spotify – Music listening patterns

    • Recently played tracks with timestamps
    • Playlists and audio features (tempo, energy, danceability)
    • Real-time playback status

    Withings – Biometric measurements

    • Body composition trends
    • Cardiac health data
    • Historical measurements with time-series analysis

    The Technical Stack

    Straify is built with Python, using:

    • Flask for the web interface
    • SQLite for local data storage
    • InfluxDB for remote time data storage
    • OAuth 2.0 for secure service authentication
    • Model Context Protocol (MCP) servers to expose data as tools for Claude

    The MCP integration is particularly powerful, it lets me have conversational AI access to all my health data. I can ask Claude questions like “What were my top pace-boosting songs last month?” or “How has my muscle mass changed since I started trail running?”.

    Key Features

    Activity Analysis Dashboard

    The main dashboard shows:

    • Connection status for all three services
    • Recent runs with key metrics
    • Recently played tracks with album art
    • Latest health measurements

    Detailed Activity Views

    For each run, I can see:

    • Split-by-split pace analysis alongside the playlist
    • GPS track visualization with markers showing where each song played
    • “Pace booster” rankings identifying the top 5 songs that coincided with fastest pacing
    • Photos captured during the activity

    Music-Activity Correlation

    The system handles different activity types intelligently:

    • Auto-recorded activities: Matches Spotify timestamps to activity windows
    • Manual activities: Pulls playback history from the time window
    • Playlist analysis: Can compare different playlists against the same activity

    Health Trends

    Withings integration provides:

    • Latest measurements displayed as cards
    • Time-series charts showing trends
    • Daily downsampling for long-term analysis
    • ECG data with AFib classification history

    What I’ve Learned

    Beyond confirming that faster-tempo music helps my pace, Straify has revealed some interesting patterns:

    1. Consistency matters more than intensity – My body composition improved more with regular, moderate runs than sporadic hard efforts
    2. Manual vs. auto-tracked activities – Manually logged runs often have less accurate pace data, making music correlation less reliable

    The Future

    While Straify started as a weekend project to satisfy my curiosity about music and running, it’s become a valuable tool for understanding my health holistically. The MCP integration with Claude opens up exciting possibilities for AI-powered insights.

    Open Source?

    I built Straify primarily for personal use, but the architecture is modular enough that others could adapt it. The MCP servers make the data accessible to any Claude-compatible application, which is a powerful pattern for personal health data projects.

    Final Thoughts

    What began as a simple question – “Which songs make me run faster?” led to building a comprehensive personal health data platform. The answer to that original question? Yes, certain songs consistently correlate with faster paces.


    Straify is a personal project integrating Strava, Spotify, and Withings data through OAuth 2.0 and exposed via MCP servers for Claude integration. Built with Python, Flask, and SQLite