Self-hosted MCP server options

Self-hosted MCP server options: enabling mobile AI app integration

2026-03-09 · ai-architecture tools-infrastructure mlops-deployment · medium · source → · wiki →
key claims
  1. The `add_memory` (write) path requires only an HTTPS call to the GitHub Contents API with no local storage dependency, making it fully viable as a stateless Cloudflare Worker in JavaScript within the free tier (100,000 requests/day, 10ms CPU, $0/month ongoing cost)
  2. The `search_brain` (read/search) path requires embedding inference and LanceDB vector search, both of which are architecturally impossible on Cloudflare Workers free tier: LanceDB is not available in Pyodide's WebAssembly package set, and embedding inference takes 34–177ms per document on native hardware — exceeding the 10ms CPU limit by 3–17×
  3. Fly.io Hobby ($5/month) supports persistent Python containers with mounted NVMe volumes; the LanceDB index survives restarts, and the pre-computed embedding pattern established by `lancedb-index-rebuild-from-git.md` reduces cold-start loading to under 0.2s regardless of corpus size
  4. Railway Hobby ($5/month, $5 included usage credits) is a viable alternative to Fly.io for the read service: both offer public HTTPS endpoints and persistent volumes adequate for a personal-scale LanceDB corpus; Fly.io has marginally broader community evidence for stateful Python deployments
  5. Tailscale Funnel exposes a home server to the public internet via an auto-provisioned `*.ts.net` HTTPS URL, is available on the free personal plan (3 users, 100 devices), requires no port-forwarding or static IP, and handles TLS certificate management automatically — making it zero-additional-cost for users who already run home server hardware
  6. GitHub Actions `repository_dispatch` returns HTTP 204 immediately with no synchronous response channel back to the caller; it cannot fulfil the request–response contract required by MCP tool calls and is limited to fire-and-forget write-only capture as a degraded fallback
  7. The MCP Python SDK (v1.8.0+, May 2025) supports Streamable HTTP transport via FastMCP; migrating `mcp_server.py` from stdio to remote-accessible Streamable HTTP requires changing the transport runner to `mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)` — two lines of code, with no changes to tool logic
  8. The Claude iOS Connector system supports no-auth (open endpoint) or OAuth 2.1 only; static `Authorization: Bearer` header tokens are not configurable via the claude.ai connector UI, requiring either a high-entropy URL component (URL-as-secret) or a full OAuth 2.1 implementation as the auth design

Research Question

What is the minimum viable self-hosted deployment of mcp_server.py (or a write-only HTTP wrapper) that: (a) is reachable from the public internet, (b) has zero or near-zero ongoing cost, (c) requires minimal operational maintenance, (d) is secure enough for personal memory data? Evaluate: Cloudflare Worker (stateless, GitHub API only), Fly.io/Railway free tier, home server + Tailscale, GitHub Actions as a compute backend via repository_dispatch.

Findings

Executive Summary

Self-hosting a Python MCP server for mobile AI integration resolves to a split architecture. The write path — a stateless GitHub Contents API proxy — fits naturally on Cloudflare Workers ($0/month, zero cold start). The read path — embedding inference plus LanceDB vector search — requires either a persistent container on Fly.io or Railway ($5/month) or an existing home server exposed via Tailscale Funnel at no additional cost. GitHub Actions repository_dispatch cannot serve synchronous MCP tool calls and is limited to fire-and-forget write capture. Authentication for Claude iOS is constrained to no-auth or OAuth 2.1 — static bearer tokens are not configurable via the claude.ai connector UI — making a high-entropy URL component the simplest viable approach, with OAuth 2.1 as the hardening path.

Key Findings

  1. The add_memory (write) path requires only an HTTPS call to the GitHub Contents API with no local storage dependency, making it fully viable as a stateless Cloudflare Worker in JavaScript within the free tier (100,000 requests/day, 10ms CPU, $0/month ongoing cost).

  2. The search_brain (read/search) path requires embedding inference and LanceDB vector search, both of which are architecturally impossible on Cloudflare Workers free tier: LanceDB is not available in Pyodide's WebAssembly package set, and embedding inference takes 34–177ms per document on native hardware — exceeding the 10ms CPU limit by 3–17×.

  3. Fly.io Hobby ($5/month) supports persistent Python containers with mounted NVMe volumes; the LanceDB index survives restarts, and the pre-computed embedding pattern established by lancedb-index-rebuild-from-git.md reduces cold-start loading to under 0.2s regardless of corpus size.

  4. Railway Hobby ($5/month, $5 included usage credits) is a viable alternative to Fly.io for the read service: both offer public HTTPS endpoints and persistent volumes adequate for a personal-scale LanceDB corpus; Fly.io has marginally broader community evidence for stateful Python deployments.

  5. Tailscale Funnel exposes a home server to the public internet via an auto-provisioned *.ts.net HTTPS URL, is available on the free personal plan (3 users, 100 devices), requires no port-forwarding or static IP, and handles TLS certificate management automatically — making it zero-additional-cost for users who already run home server hardware.

  6. GitHub Actions repository_dispatch returns HTTP 204 immediately with no synchronous response channel back to the caller; it cannot fulfil the request–response contract required by MCP tool calls and is limited to fire-and-forget write-only capture as a degraded fallback.

  7. The MCP Python SDK (v1.8.0+, May 2025) supports Streamable HTTP transport via FastMCP; migrating mcp_server.py from stdio to remote-accessible Streamable HTTP requires changing the transport runner to mcp.run(transport="streamable-http", host="0.0.0.0", port=8000) — two lines of code, with no changes to tool logic.

  8. The Claude iOS Connector system supports no-auth (open endpoint) or OAuth 2.1 only; static Authorization: Bearer header tokens are not configurable via the claude.ai connector UI, requiring either a high-entropy URL component (URL-as-secret) or a full OAuth 2.1 implementation as the auth design.

Assumptions

Analysis

The resource asymmetry between write and read is the key architectural driver: the write path requires nothing more than an HTTPS call, while the read path requires persistent disk, embedding inference, and milliseconds of CPU — making containers the only viable option for the latter and serverless edge the only practical option for the former.

The pre-computed embeddings finding from lancedb-index-rebuild-from-git.md is what makes the Fly.io option viable without paying for always-on capacity: cold-start loading takes under 0.2s, keeping search latency below 1s even for containers that auto-slept. This directly addresses the 11.5s rebuild penalty that would otherwise make auto-scaling [inference] unacceptably slow.

Home server + Tailscale Funnel is genuinely competitive on cost and capability for users with existing hardware. The trade-off is operational reliability: home hardware introduces failure modes (ISP outage, power cut, hardware failure) that Fly.io eliminates. For a high-availability requirement, Fly.io is preferable. For a personal assistant with acceptable occasional downtime, home server is a legitimate choice.

Railway and Fly.io are equivalent in cost and capability. Fly.io is selected as the primary recommendation based on wider community evidence for stateful Python deployments and a [inference] more mature persistent volume feature.

Risks, Gaps, and Uncertainties

Open Questions


sources


Connected items

Loading…

View full knowledge graph →