pulse-mcp-bridge
Allows interaction with an Expo mobile app to capture live device status, app logs, screenshots, and bug reports.
Provides integration with local Git repositories to retrieve today's commits for standup snapshots combined with device status.
Allows interaction with a React Native mobile app to retrieve device status, logs, screenshots, and bug reports.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pulse-mcp-bridgewhat's the device status?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
pulse-mcp-bridge
An MCP (Model Context Protocol) server that bridges your IDE to a running React Native / Expo mobile app on your local Wi-Fi network, so tools like Claude Code or Cursor can pull live device status, app logs, automatically-captured crashes (with stack traces and breadcrumbs, no manual instrumentation required), and a combined standup snapshot (device status + today's git commits).
How it fits together
IDE (MCP client) <--stdio--> pulse-mcp (index.js) <--HTTP--> mobile app (mobile-app-server.js)
or <--HTTP--> mock-phone.js (for local testing)Related MCP server: Expo MCP Server
Setup
npm install1. Try it locally with the mock phone (no device needed)
In one terminal, start the mock phone server:
node mock-phone.jsThis listens on http://localhost:8080 and fakes /status and /logs responses.
2. Register the MCP server with your IDE
See mcp-config.example.json for ready-to-paste config blocks for Cursor, Claude Desktop, and Windsurf. Point MOBILE_PHONE_IP at:
127.0.0.1when testing againstmock-phone.jsyour phone's local IP (e.g.
192.168.1.50) when testing against a real device
3. Wire up the real mobile app
index.js (the MCP server) is generic and reusable as-is — it never needs to change per app. The only thing that changes per app is mobile-app-server.js, the tiny HTTP bridge that runs inside the app.
Setup, once per new app:
Copy the bridge file into the target app, e.g. as
src/pulseServer.js:cp mobile-app-server.js /path/to/your-app/src/pulseServer.jsInstall its native dependencies in that app:
npx expo install react-native-http-bridge-refurbished react-native-device-info react-native-view-shot @react-native-async-storage/async-storageThese are native modules — if the app runs on plain Expo Go, you'll need a dev-client build instead (
npx expo prebuildthennpx expo run:ios/npx expo run:android).Wire it into
App.tsx:import { startPulseServer, setCurrentRoute, recordLog } from "./pulseServer"; useEffect(() => { if (__DEV__) startPulseServer(); }, []); // On navigation change: setCurrentRoute(routeName); // Anywhere in the app: recordLog("Synced dashboard data", "success", "SyncService"); recordLog(`Network request failed: ${error.message}`, "error", "NetworkClient");Add the bug-report recording hooks too if you want
get_bug_report/get_saved_bug_reports— see "Bug-report step recording" below.Crash capture needs no extra wiring at all beyond
startPulseServer()— see "Automatic crash capture" below.Same Wi-Fi network — your phone/emulator and dev machine must be on the same Wi-Fi network (or use
127.0.0.1for the iOS Simulator, which shares the Mac's own network stack).Point your MCP config at this device: set
MOBILE_PHONE_IP(in your IDE's MCP config, seemcp-config.example.json) to that device's IP —127.0.0.1for Simulator, the phone's LAN IP (e.g.192.168.1.50) for a real device.
Real device notes:
Real iPhone — verified. This integration has been tested end-to-end against a real Expo/React Native app on a real iPhone, including a live crash scenario — the bridge correctly goes unreachable when the app stops responding. iOS 14+ will prompt for a one-time "Local Network" permission the first time the app starts the bridge server — the user must tap Allow, or the bridge will be unreachable.
Real Android — not yet verified, though it should work in principle (
react-native-http-bridge-refurbishedsupports Android too). Android 9+ blocks plaintext HTTP by default, so you'll likely needandroid:usesCleartextTraffic="true"inAndroidManifest.xmlfor local dev builds, or the bridge will silently fail to connect.Android emulator: since it's NAT'd and can't be reached directly, use
127.0.0.1plusadb forward tcp:8080 tcp:8080.
Running demo-app on a real iPhone
demo-app/ios is checked in with manual signing (CODE_SIGN_STYLE = Manual, provisioning profile IndiaNIC-WildCard-Development, team 7BCW99KL8P, certificate Apple Development: Manish Manish) — this is intentional, not a misconfiguration, so don't "fix" it by switching to Automatic. npx expo run:ios --device <udid> doesn't handle manual signing well, so build/install directly with the Apple toolchain instead:
cd demo-app/ios
xcrun xctrace list devices # find your device's UDID (must show under "Devices", not "Devices Offline" — plug in + unlock + trust first)
xcodebuild -workspace demoapp.xcworkspace -scheme demoapp -configuration Debug \
-destination "id=<UDID>" build
APP_PATH=$(find ~/Library/Developer/Xcode/DerivedData/demoapp-*/Build/Products/Debug-iphoneos -maxdepth 1 -name "*.app")
xcrun devicectl device install app --device <UDID> "$APP_PATH"
xcrun devicectl device process launch --device <UDID> com.indianic.pulseIf xcodebuild errors with conflicting provisioning settings or No profiles for 'com.indianic.pulse' were found, the project's signing got out of sync with Xcode's UI state — open demoapp.xcodeproj in Xcode, go to the demoapp target's Signing & Capabilities tab, and re-select the IndiaNIC-WildCard-Development profile there (this rewrites project.pbxproj correctly). Don't hand-edit project.pbxproj signing fields — let Xcode do it.
Available MCP tools
Tool | Description |
| Battery level, active route/screen, OS/platform, and |
| Recent structured log entries ( |
| Pings |
| Diagnoses the most recent problem, preferring a captured crash (with its real stack trace and breadcrumbs) over a plain log message when both exist. Returns a structured |
| Combines live device status with today's local git commits (falls back gracefully outside a git repo) |
| Live screenshot of whatever screen is currently showing on the app, returned as an inline image |
| The current/live step recording (see below) plus device context, for reproducing a bug in progress |
| All bug reports auto-saved on the device, each with its full steps, logs, and device info snapshot |
| All crashes automatically captured on the device (see "Automatic crash capture" below), each with a stack trace, breadcrumb trail, and a best-guess |
Example prompts
Copy-paste any of these into Claude to trigger the matching tool:
Tool | Example prompt |
| "Check my mobile connection" |
| "What's the current status of my device?" |
| "Show me the recent app logs from my phone." |
| "Show me any crash logs from the mobile app." |
| "Take a screenshot of my phone's current screen." |
| "The app crashed on the login screen, can you diagnose why?" |
| "Get the current bug report / step recording." |
| "List all saved bug reports." |
| "Give me a standup snapshot." |
Bug-report step recording
Wire a "Start/Stop Recording" toggle in your app to startSessionRecording() / stopSessionRecording(), and call recordStep(...) at any point worth capturing (button taps, network results, errors). When recording stops, a complete report — numbered steps, full logs, and a device/build info snapshot — is auto-saved and instantly queryable via get_bug_report / get_saved_bug_reports. No manual "steps to reproduce" writeup needed.
Automatic crash capture
Unlike bug-report recording, this needs no toggle and no manual recordLog/recordStep calls at all — it's live the moment startPulseServer() runs, and catches three distinct failure paths that would otherwise vanish without a trace:
Failure path | Caught by |
|
Uncaught exception in an event handler or async code |
|
|
A crash during React's render phase | A root |
|
A rejected promise nobody | Hermes's rejection tracker (falls back to the |
|
Every crash automatically includes a breadcrumb trail — the last ~20 things that happened right before it, built with zero developer effort:
every navigation change (from
setCurrentRoute())every
fetch()call your app makes, success or failure (global.fetchis patched transparently; requests tolocalhost/Metro's own dev tooling are excluded)
Crashes survive the app dying. The instant a crash is captured, it's written to AsyncStorage before anything else runs. If the crash kills the whole JS engine before the in-memory list or an HTTP request could reflect it, it's recovered automatically the next time the app launches (tagged recoveredFromDisk: true) and cleared from disk so it isn't re-flushed again.
This is what makes get_mobile_crash_logs/diagnose_mobile_error answer "why did my app crash" for a crash that happened five minutes ago and killed the app, not just one you're actively watching for.
Remote / cloud relay mode
Everything above requires the phone and this MCP server to be on the same Wi-Fi network (MOBILE_PHONE_IP). If your tester/client's device is somewhere else entirely — a different city, a different network, cellular data — use the relay instead: the phone pushes its state to an always-on hosted service, and index.js reads from that service over HTTPS instead of a LAN IP.
When to use it: the developer and the device are not on the same network, or you want crashes/logs captured even when no one's MCP client happens to be running at that moment.
Setup:
Deploy
relay-server/somewhere always-on (Render is the simplest — seerelay-server/README.md), settingPULSE_API_KEYto a random secret.In the mobile app, alongside
startPulseServer(), call:import { configurePulseRelay } from "./pulseServer"; configurePulseRelay({ url: "https://your-relay.onrender.com", apiKey: "the-same-PULSE_API_KEY-as-the-relay", deviceId: "some-stable-id-for-this-device", // e.g. a UUID you generate once and persist });On the MCP server side, set
PULSE_RELAY_URL,PULSE_API_KEY, andPULSE_DEVICE_ID(matching the values above) instead ofMOBILE_PHONE_IP— see therelay_mode_exampleblock inmcp-config.example.json.
All 9 tools work identically in relay mode — index.js's tool handlers don't know or care whether they're talking to the phone directly or through the relay.
Security note: the relay is internet-exposed, unlike the trusted-LAN-only local bridge. Every request requires the x-pulse-api-key header; treat that key like a password (don't commit it, rotate it if it leaks). There's no per-device auth beyond the shared key and deviceId, so this is meant for a small number of trusted testers/devices, not a public multi-tenant service.
Automated crash-fix pipeline (optional): the relay can also automatically kick off a Claude Code agent on every new crash or bug report, which opens a PR with a candidate fix for you to review. This is opt-in — set GITHUB_TOKEN/GITHUB_REPO on the relay and add ANTHROPIC_API_KEY to this repo's GitHub Actions secrets to enable it (see .github/workflows/auto-fix-crash.yml and relay-server/lib/githubDispatch.js). Leave those unset and the relay works exactly the same, just without the auto-fix step.
Environment variables
Variable | Default | Purpose |
|
| IP address of the phone/mock server running the HTTP bridge (local Wi-Fi mode only) |
| unset | Base URL of the relay server (see "Remote / cloud relay mode"); when set, this replaces |
| unset | Shared secret sent as |
| unset | Which device's state to read from the relay (must match the |
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityAmaintenanceCaptures and provides access to React Native console logs from Metro bundler, enabling AI assistants to retrieve, filter, and search app logs in real-time without manual copy/paste.641,44972MIT
- AlicenseNot gradedqualityBmaintenanceEnables automated testing and development of Expo/React Native apps through session-based Expo dev server management and Maestro UI automation tools for tapping, text input, screenshots, and flow execution.147,9025MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to view and analyze screenshots from React Native/Expo applications for AI-powered mobile UI development. Integrates with Claude, Cursor, VS Code and other MCP-compatible editors.615MIT
- AlicenseBqualityDmaintenanceEnables AI agents to inspect, log, and control React Native apps on Android emulators or iOS simulators, including UI tree, tap, scroll, and hot reload.221,1065MIT
Related MCP Connectors
MCP connector for iMessage & Contacts via a local Mac agent + Vercel relay
Connect to Atlassian Jira, Confluence, and Compass to search, create, and manage your work.
Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/tarunmalpani/pulse-mcp-bridge'
If you have feedback or need assistance with the MCP directory API, please join our Discord server