← Back to list

MCP for React Native: How to Connect Your Mobile App to AI Agents

Everyone’s wiring AI agents into mobile apps. Almost no one is honest about which machine runs the MCP client — and getting it wrong ships…

Suresh Kumar Ariya Gowder in React Native Journal · 2026-06-16 02:25 · 0 claps · 8.8 min read paywalled
#react-native #model-context-protocol #ai-agent #mobile-development #artificial-intelligence
Open on Medium ↗
Wiki topics: AGT · AI Agents AI · AI · General 🌐 · Web Development 📱 · Mobile Development

MCP for React Native: How to Connect Your Mobile App to AI Agents

Everyone’s wiring AI agents into mobile apps. Almost no one is honest about which machine runs the MCP client — and getting it wrong ships a security hole.

Last week I tried to do the obvious thing. I had a React Native app, I had a remote MCP server exposing some tools, and I wanted the app to call those tools the way Claude Desktop or Cursor does. So I reached for @modelcontextprotocol/sdk, dropped it into my Expo project, and hit Metro bundler.

It broke. Not in a small way. The SDK leans on Node.js primitives — child processes for the stdio transport, globalThis.crypto for auth — and React Native's JavaScript runtime is not Node. The "just install the client" mental model I'd borrowed from desktop tutorials fell apart on contact with a phone.

That failure is the whole point of this article. The interesting question isn’t “how do I add MCP to my app” — it’s “which machine runs the MCP client, and why almost never the phone.” Once that clicks, MCP on mobile stops being mysterious and starts being an architecture decision you can reason about. Let me walk you through what MCP actually is, where it runs, the pattern that works, and an honest correction to my own title along the way.

What MCP actually is

The Model Context Protocol is a standard way for an AI application to discover and call external tools. Anthropic introduced it in November 2024 and open-sourced the spec and reference SDKs; through 2025 and into 2026, OpenAI, Google DeepMind, and a long list of toolmakers adopted it too. The popular shorthand is “USB-C for AI” — one connector so any model can plug into any tool — and like most analogies it’s three-quarters true and worth not over-trusting.

Under the hood it’s deliberately unglamorous. The wire format is JSON-RPC 2.0. Tools are described with JSON Schema. There are exactly three roles, and keeping them straight is most of the battle:

  • Host — the AI application that wants to use tools (Claude Desktop, Cursor, or your backend).
  • Client — the connector that lives inside the host and manages one connection to one server.
  • Server — the thing exposing tools (functions the AI can call), resources (read-only data), and prompts.

The npm registry showed roughly 1,200 published MCP servers as of Q2 2026, per a developer survey of the registry — Slack, GitHub, Linear, Postgres, Figma, file-system, browser-control, and more. That ecosystem is the actual reason to care: implement the client once, and all of it becomes reachable.

The contribution of MCP isn’t novel technology — JSON-RPC and JSON Schema are decades old. The contribution is the packaging: a single contract every tool and every model agrees to speak. — paraphrased from the MCP specification (2025–11–25) and practitioner write-ups

The three MCP roles. Host holds the AI loop; the client (inside the host) manages one connection per server; the server exposes tools, resources, and prompts over JSON-RPC. The role that trips up mobile devs is host — on a phone, that’s your backend, not the app.

The three MCP roles. Host holds the AI loop; the client (inside the host) manages one connection per server; the server exposes tools, resources, and prompts over JSON-RPC. The role that trips up mobile devs is host — on a phone, that’s your backend, not the app.

Why “now,” and why mobile devs specifically

Two things changed that make this a 2026 problem and not a 2025 curiosity. First, the transport story settled. The original spec shipped an HTTP+SSE transport; that was deprecated on 2025–03–26 in favor of Streamable HTTP, a single-endpoint, bidirectional-streaming transport designed for serverless and load-balanced deployments. Remote MCP — the kind a mobile backend would actually use — stopped being a moving target.

Second, the tool ecosystem crossed the threshold where reinventing integrations by hand looks foolish. When there’s a maintained Postgres server, a GitHub server, and a Linear server already speaking the protocol, the build-vs-adopt math flips.

For mobile developers, this collides with a constraint web developers don’t fully share: your client runtime is hostile to Node. That single fact reorganizes every architecture decision below.

Why “now.” The remote transport settled in March 2025 when Streamable HTTP replaced HTTP+SSE, and a stable spec/SDK 2.0 is slated for July 28, 2026. Targeting the current transport is how you avoid building on a deprecated foundation.

Why “now.” The remote transport settled in March 2025 when Streamable HTTP replaced HTTP+SSE, and a stable spec/SDK 2.0 is slated for July 28, 2026. Targeting the current transport is how you avoid building on a deprecated foundation.

An honest correction to my own title

The title says “connecting your RN app to AI agents.” Read literally — the MCP client running inside the app’s JavaScript bundle — that’s the path I’d gently steer you away from for anything you plan to ship. Here’s the honest version.

The official TypeScript SDK runs on Node.js, Bun, and Deno. Its stdio transport spawns servers as child processes — impossible on iOS and Android. Its auth helpers expect the Web Crypto API on globalThis.crypto, which React Native doesn't fully provide without polyfills. The MCP Bridge project, an academic proxy for exactly this problem, states the constraint plainly: edge devices, mobile devices, and browsers can't efficiently run npm or Python MCP servers, and direct connections from resource-constrained environments are impractical.

Honesty flag : I genuinely hit the Node-runtime wall described in the hook — that part is reproducible by anyone who tries npm install @modelcontextprotocol/sdk in a bare Expo app. I have not personally benchmarked a production MCP-over-backend deployment end to end; the architecture recommendations below are synthesized from the SDK docs, the MCP Bridge paper, and practitioner guides, not from a system I've shipped. Treat the "do this" parts as well-sourced advice, not battle scars.

So when a tutorial says “add an MCP client to your React app in 30 minutes,” look closely at whether it’s a web React app with a Node-friendly path, or whether the client is really sitting on a server the frontend talks to over REST. The honest mobile pattern keeps the MCP client off the phone.

The pattern that actually works: the backend host

Here’s the architecture I’d reach for. Your React Native app stays a thin, well-behaved client. It sends user intent to your backend over plain HTTPS. Your backend is the MCP host: it runs the model loop, holds the MCP client, connects to MCP servers over Streamable HTTP, and streams results back to the app.

The backend-host pattern. The RN app is a thin client over HTTPS; the backend is the MCP host that runs the model loop, holds the MCP client, and authenticates to servers with OAuth 2.1. API keys and tokens never ship inside the app bundle — which is the entire security argument in one picture.

The backend-host pattern. The RN app is a thin client over HTTPS; the backend is the MCP host that runs the model loop, holds the MCP client, and authenticates to servers with OAuth 2.1. API keys and tokens never ship inside the app bundle — which is the entire security argument in one picture.

Why this is the sane default comes down to three things mobile makes worse:

1. Secrets can’t live in the bundle

Anything shipped in a mobile binary is extractable. MCP servers increasingly authenticate with OAuth 2.1 using PKCE per the spec; those tokens and any API keys belong on a server you control, never in an app a determined user can unzip. The backend-host pattern makes this structural, not a discipline you have to remember.

It’s worth being concrete about the failure mode, because “secrets leak” sounds abstract until it isn’t. If you embed a server credential in the app to let the on-device client connect directly, anyone can pull the binary from their own device, extract that credential, and now hold a key that talks to your tools — your database server, your internal API — with none of your rate limits or user scoping in between. The backend-host pattern closes that door by construction: the phone never possesses anything worth stealing, so there’s nothing to extract.

2. The model loop is heavy and chatty

Agentic tool-calling means many round trips: discover tools, call one, feed the result back, call another, maybe call a third based on what came back. Doing that orchestration on-device burns battery, competes with your UI thread, and fights a runtime that wasn’t built for it. On a server it’s just a normal long-running program with none of those constraints — and you can add caching, retries, and observability without touching the app.

3. You want to change tools without shipping an app update

Add a new MCP server backend-side and every user has it instantly. Bake tool wiring into the app and you’re waiting on App Store review to add a capability. For anything iterating fast, that alone settles it.

What the backend code looks like

Minimal and close to the official client examples — the host side, where Node is a friend, not a foe:

// backend (Node) — simplified; check current @modelcontextprotocol/sdk docs
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://tools.example.com/mcp"),
  { requestInit: { headers: { Authorization: `Bearer ${token}` } } }
);

const client = new Client({ name: "my-app-backend", version: "1.0.0" });

await client.connect(transport);

const { tools } = await client.listTools();        // discovery
const result = await client.callTool({
  name: "search_issues",
  arguments: { query: "open bugs" }
});

And the app side stays boringly familiar — the thing React Native devs already write every day:

// React Native — just talk to your backend over HTTPS
const res = await fetch("https://api.myapp.com/agent", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ intent: "find my open bugs" })
});
const data = await res.json();  // rendered in your UI; MCP stayed server-side

Notice what’s missing from the app: no SDK, no transport, no tokens. That absence is the design.

The honest counter argument: “but I want it on the device”

Let me steelman the opposite view, because there are real cases where on-device is the right call and dismissing them would be dishonest.

The privacy and offline argument is legitimate. If your whole pitch is that user data never leaves the phone — a journaling app, a health tool, anything privacy-first — routing everything through a backend undermines the product. And the on-device LLM story has matured fast: Callstack’s @react-native-ai packages run open models through MLC LLM's optimized runtime on-device, and on-device Apple Foundation Models support arrived in preview in late 2025 for RN 0.80+ with the New Architecture. On-device tool-calling is no longer science fiction.

The fair rebuttal: on-device LLM execution and an on-device MCP client are different problems, and only the first is close to solved. MLC requires iOS devices with enough memory — Callstack cites a 1–8GB range depending on the model, gated behind the “Increased Memory Limit” capability. And even with a local model happily generating text, you still hit the same Node-runtime wall for the MCP client itself: stdio needs child processes, remote transports need robust crypto and networking the bundle doesn’t hand you for free. The pragmatic middle path most teams land on is a local proxy — exactly what MCP Bridge exists to be — so the device talks to a lightweight REST layer that owns the awkward MCP plumbing. That’s a real architecture, not a cop-out. It’s just not “the MCP client runs in my JS bundle.”

So the steelman holds for the model, weakens for the client, and points at a proxy rather than a bundled SDK. Honest conclusion: device-resident AI is coming for mobile; device-resident MCP clients are the laggard, and pretending otherwise sets you up for the exact afternoon I lost to Metro.

Practical takeaways

  • Make your backend the MCP host. Run the model loop and the MCP client server-side; keep the RN app a thin HTTPS client. This is the default unless you have a hard privacy or offline requirement.
  • Never ship MCP credentials in the bundle. OAuth 2.1 / PKCE tokens and API keys live on the server. Anything in a mobile binary is extractable — treat it as already leaked.
  • Use Streamable HTTP, not HTTP+SSE. SSE was deprecated on 2025–03–26; new remote work should target the current transport to avoid building on a deprecated path.
  • Audit “30-minute MCP client” tutorials before trusting them on mobile. Check whether the client runs in a Node-friendly context or is quietly a backend the frontend calls over REST.
  • If you truly need on-device, separate the two problems. Pick an on-device LLM runtime (MLC, Apple Foundation Models) for generation, and a local proxy like MCP Bridge for the tool plumbing — don’t expect one bundled SDK to do both.
  • Pin the SDK version and re-check the docs. The TypeScript SDK’s main-branch docs describe an unreleased 2.0 split-package API; write against the version you actually npm install, with a stable-release spec slated for July 28, 2026.

What you keep

The lesson that outlasts this particular protocol is a question, not a fact: which machine holds the loop? Every “add AI to my app” decision — MCP or whatever replaces it next year — is really a decision about where the agent’s reasoning lives, who holds the secrets, and how much of that you can safely push toward the user’s device. MCP didn’t invent that question; it just made it impossible to keep ignoring, because the moment you have real tools and real credentials in play, the boundary stops being theoretical. Get the boundary right and the protocol is almost an implementation detail you could swap out. Get it wrong and no amount of clever client code saves you — you’ve just moved the security hole somewhere harder to see.

And tell me a war story in the comments: where did you first try to run an AI client that turned out to belong on a server? I want the one that cost you an afternoon — those are the ones that teach the boundary.


메타데이터
post_id
9e223b66ffca
slug
mcp-for-react-native-how-to-connect-your-mobile-app-to-ai-agents-9e223b66ffca
url
https://medium.com/react-native-journal/mcp-for-react-native-how-to-connect-your-mobile-app-to-ai-agents-9e223b66ffca
canonical_url
https://medium.com/react-native-journal/mcp-for-react-native-how-to-connect-your-mobile-app-to-ai-agents-9e223b66ffca
author_url
https://medium.com/@sureshdotariya
status
ok
fetched_at
2026-06-17 08:20:12