frisian-mcp in Production: A Consumer iOS Fitness Application
Date: May 2026
FMCP Version: 0.9
Agent: GPT
Category: reference
Slug: production-consumer-fitness-app
Audience: Developers evaluating frisian-mcp for consumer-facing Django backends
What This Document Is
This is a case study of frisian-mcp running in production in a consumer iOS fitness application. The Django backend serves a mobile app tracking workouts, exercise libraries, training programs, and user challenges. AI agents connect to the backend via MCP to build features, fix bugs, and manage data — the same backend that serves real users.
This is the contrast case to the multi-agent orchestration platform documented elsewhere on this server. Same package. Different domain, different load profile, different architecture. Both running in production.
The Application
The backend is a Django 5.x application using Django REST Framework, deployed on AWS. It serves a native iOS app (including a watchOS companion app) with endpoints covering:
- Exercise library — 108+ active exercises with category, equipment, muscle groups, exercise type, and instructions
- Training programs — structured workout programs with exercise sequencing, difficulty ratings, and tier gating
- Challenges — server-downloadable challenges with versioning, allowing new challenges to deploy without an app release
- User accounts — Cognito JWT authentication, subscription tiers, HealthKit integration
- Scheduling — workout scheduling linked to calendar events and Apple Intelligence integration
- RAG-backed coaching — on-device LLM inference consuming a server-side RAG corpus for workout recommendations
frisian-mcp exposes four of these surfaces as MCP tools. The rest — user accounts, HealthKit data, scheduling, mobile-specific endpoints — are marked @mcp_ignore. The MCP surface is scoped to what agents need to build and maintain the application, not the full API.
The MCP Surface: Four Tools
The exposed surface is intentionally narrow:
| Tool | Operations | Purpose |
|---|---|---|
exercises |
list, get, create, update, bulk_update | Exercise library management |
programs |
list, get, create, update, delete, set_exercises | Training program management |
challenges |
list, get, create, update, delete | Challenge content management |
rag |
search | Semantic search over the coaching knowledge corpus |
Four tools covering 16 operations. Agents building features, writing data migrations, or validating the content library call these tools. The mobile REST API endpoints — the ones the iOS app actually hits — are a separate surface not exposed via MCP.
This is @mcp_ignore in its intended use. The ViewSets serving /api/v1/exercises/, /api/v1/programs/, and /api/v1/challenges/ to the iOS app are not the MCP tools. The MCP tools are a separate, agent-facing layer over the same underlying data.
A Non-Standard Integration Path
This application has no DRF ViewSets. Every backend view is a function-based view decorated with @api_view. This was discovered during integration testing and is worth documenting because it is not an edge case — many Django projects are built entirely with FBVs.
frisian-mcp's auto-discovery (FRISIAN_MCP_AUTODISCOVER = True) reads ViewSetMixin subclasses. On a project with zero ViewSets, auto-discovery produces zero tools with no error — it simply finds nothing to register. This is correct behavior, but without a clear warning it appears as a silent misconfiguration.
This finding led directly to a package improvement: frisian-mcp now logs a startup warning when auto-discovery runs and finds zero tools, with a hint pointing to the @mcp_tool manual registration path. A developer who installs frisian-mcp on an FBV-heavy project now gets immediate feedback rather than a blank tools/list.
The integration used @mcp_tool manual registration. The existing tool logic — already written for the application's previous hand-rolled MCP gateway — was adapted to frisian-mcp's signature and registered at startup via AppConfig.ready(). The migration from a custom MCP implementation to frisian-mcp was completed without rewriting the underlying tool logic.
Bugs Found During Integration
The integration was run as an adversarial test — two agents collaborating, one owning the host-app side, one intentionally stress-testing frisian-mcp to find failures before any PyPI release. Five issues were surfaced:
Auth surface incompatibility (resolved — became a package feature):
The application uses Cognito JWT for its REST API and a separate DB-backed token system (OAuthAccessToken + MCPToken fallback) for its MCP surface. frisian-mcp's endpoint was a plain Django function view, not a DRF APIView, so DRF authentication classes were never evaluated. Host apps with non-standard auth had no way to configure the MCP endpoint without a middleware workaround.
Resolution: frisian-mcp's McpEndpointView was converted to a DRF APIView. FRISIAN_MCP_AUTHENTICATION_CLASSES and FRISIAN_MCP_PERMISSION_CLASSES settings were added. Host apps now point these settings at any DRF authentication class. No middleware workaround required.
camelCase/snake_case schema asymmetry (surfaced, documented):
The application serializers use camelCase field names for mobile API responses. frisian-mcp's schema generation from serializer introspection produced inconsistent field names between read and write schemas, requiring agents to guess the correct casing for tool call parameters.
Generic error on invalid UUID (surfaced, documented):
Passing a malformed UUID to any tool that accepted a resource ID returned "Internal tool error" rather than a structured JSON-RPC error message. DRF's ValidationError and DoesNotExist exceptions were not being translated to agent-readable errors.
exercise_type field missing from create/update schemas (host-app fix):
90+ exercises had been misclassified in the database due to exercise_type being absent from the create and update input serializers. A backfill corrected the existing records; the serializers were updated to include the field going forward.
Auth model coupling blocking clean decommission (architectural finding):
After migrating all tool logic to frisian-mcp, full removal of the old MCP app was blocked because the MCPToken, OAuthAccessToken, and OAuthClient models lived in that app and were required by the auth backend now serving frisian-mcp. The old app had to remain in INSTALLED_APPS to keep its migrations alive.
This finding directly informed the design of frisian_mcp.contrib.tokens and frisian_mcp.contrib.oauth — the auth contrib modules that ship with frisian-mcp. Host apps that use these modules own nothing custom. When they migrate away from a previous MCP implementation, there is no orphaned model dependency blocking the cleanup.
What the Integration Validated
By the time integration testing closed, the following were confirmed working on a real production Django backend:
@mcp_toolmanual registration as a complete alternative to auto-discoveryFRISIAN_MCP_AUTHENTICATION_CLASSESsettings-based auth configurationFRISIAN_MCP_PERMISSION_CLASSESsettings-based permission configuration- MCP endpoint coexisting alongside a pre-existing REST API at separate URL prefixes
- Full tool lifecycle:
tools/list,tools/callwith valid token,tools/callwith invalid token returning 401 - All 16 tool operations validated against live database records (108 exercises, 4 programs, 5 challenges)
- Zero errors across the full validation suite
The application's previous hand-rolled MCP gateway — a custom implementation purpose-built for this app — was decommissioned. frisian-mcp replaced it without changes to the underlying tool logic or the Django REST API serving the iOS app.
The Versatility Point
The multi-agent orchestration platform described elsewhere on this server runs 194+ worker registrations across 19 roles, coordinates Claude and GPT simultaneously, manages 50 concurrent projects, and handles complex multi-step workflows with human approval gates. Its MCP surface is the primary interface — there is no other way to interact with it.
This application is a consumer fitness product. Its primary users are humans on an iPhone. AI agents interact with the backend to build and maintain the product, not to use it. The MCP surface is a narrow maintenance layer over a mobile API.
The same package installs the same way in both. pip install, INSTALLED_APPS, urls.py, connect your client. The differences — what to expose, what to ignore, which auth backend to wire, how many tools to register — are configuration decisions in the host application. frisian-mcp does not know or care whether it is serving a fitness app or an agent orchestration platform.
That is the claim. Both systems are running. Both are documented here.
Build and testing executed by Claude.ai (claude-sonnet-4-6) | 2026-05-07
Source: Live inspection of integration testing records via MCP — room discussions, task history, and project artifacts examined directly.