onsense
The onsense server bridges a PC-based AI agent and an Android phone, enabling access to the phone's camera, sensors, photos, and files over local Wi-Fi — no cloud services or ADB required. All communication is secured with HMAC request signing and AES-256-GCM encryption.
Here's what you can do:
Capture live camera frames (
get_live_frame): Get a real-time JPEG from the phone's camera.Read sensor data (
read_sensors): Retrieve battery level, charging state, ambient light (lux), and accelerometer values (x/y/z).List recent photos (
recent_photos): Get a list of the phone's recent photos with metadata (id, name, date, dimensions), with a configurable limit.Fetch a specific photo (
get_photo): Download a photo by ID, with optional downscaling to a maximum width.Get reference content (
get_reference): Fetch whatever the user has designated as the current share target — a live camera frame, captured image, or arbitrary file (PDF, video, document, etc.) — saved to the PC's Downloads folder.Query/set camera FPS (
get_cam_fps/set_cam_fps): Check or adjust the phone's camera frame rate (15 = high performance, 2 = balanced, 0 = power-saving/on-demand).File & clipboard transfer: Push images, text, and files from phone to PC (optionally injecting into the OS clipboard), and optionally pull the PC's clipboard content to the phone.
Integrates with Android devices via the onSense app, allowing AI agents to access phone camera, sensors, files, and clipboard over local Wi-Fi.
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., "@onsenseTake a photo with my phone's camera."
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.
onsense — Phone Camera, Sensors & Files for PC AI Agents
Don't describe it. Let your AI see it. onsense is the PC-side MCP broker for the onSense Android app: run uvx onsense pair on your PC, and any MCP-capable AI — Claude Code, Claude Desktop, Codex, or your own agent — can see through your phone's camera, read its sensors, and move files & clipboard both ways. No cloud relay. No ADB.

Claude Code, running on the PC, reads the phone's sensors and looks through its camera to answer — live, over local Wi-Fi.

…and the same with Codex. onSense is a standard MCP server, so any MCP client works.
Architecture
Android phone (onSense app) PC (this package) AI client
HTTP provider :8080 ←→ stdio MCP broker Claude / Codex / …
camera frames, photos, onsense serve natural-language or
sensors, QR pairing onsense clip :8770 /onsense tool callsThe phone runs an HTTP provider on port 8080. It exposes camera frames, recent photos, and sensor readings, all gated by a pairing token.
The PC package (
onsense) is a stdio MCP broker. It translates MCP tool calls from your AI client into HTTP requests to the phone.Discovery uses mDNS (
_onsense._tcp.local.). If the phone's IP changes, the broker rediscovers it automatically — no manual reconfiguration needed.An optional clip bridge daemon on port 8770 lets the phone push camera frames, files, and clipboard content to the PC (and, if enabled, lets the phone pull from the PC clipboard).
Related MCP server: MCP Scrcpy Vision
Requirements
uv (provides
uvx; downloads a managed Python automatically — no separate Python install needed)The onSense Android app installed on a phone on the same local Wi-Fi network as your PC
An MCP-compatible AI client such as Claude Code, Codex, or any stdio MCP client
Quick Start
0. Fresh PC without uv? Use the app's setup helper (recommended)
On a clean PC, uvx doesn't exist yet and the command below will fail with "'uvx' is not recognized". The easiest fix: install the onSense app first, tap "Start PC setup helper", and open the shown address on your PC. It gives you a one-line command that installs uv, pairs, and registers the MCP server in one go — and because the PC connects out to the phone, it also sidesteps the Windows firewall entirely.
Prefer installing uv yourself? One line:
# Windows (PowerShell)
irm https://astral.sh/uv/install.ps1 | iex
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path" # make uvx visible in this same shell# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"1. Pair your phone
Run this once. The PC prints a QR code; scan it from the onSense app ("Scan PC QR"). The phone pushes its address and token to the PC, which registers the MCP server automatically.
uvx onsense pairAfter pairing, restart your AI client once so it picks up the new onsense MCP server.
2. Use it
Ask your AI client naturally:
"Take a photo of what's in front of my phone." "What are the current sensor readings?" "Show me the last 5 photos on my phone."
The MCP tools are called automatically. In Claude Code you can also use the bundled /onsense slash command (installed during pairing).
3. Diagnose problems
uvx onsense doctor # checks Python, uv, MCP, Claude registration, mDNS, phone reachability
uvx onsense doctor --base http://192.168.1.5:8080 --token YOUR_PAIRING_TOKENWindows: QR scan times out?
The #1 cause is the Windows firewall dropping the phone's inbound connection:
If your Wi-Fi network profile is Public, inbound traffic is blocked hard. Switch it to Private (Settings → Network → your Wi-Fi → Network profile), or just use the app's PC setup helper, which needs no inbound port at all.
On a Private network, add a durable allow rule once (run as administrator):
uvx onsense pair --fix-firewallThe first-run firewall popup is program-path-scoped and uvx's ephemeral paths silently invalidate it — the port-scoped rule above (TCP 8765–8774, Private) is what actually sticks.
If port 8765 is taken,
pairautomatically falls back to the next free port (up to 8774) and the QR reflects the real port — no action needed.
Subcommands
Command | What it does |
| Display a QR code on the PC; phone scans it and pushes |
| Parse a pairing URI directly (phone-displayed QR → manual copy) |
| Decode a pairing QR from a screenshot file (requires opencv) |
| Run the MCP server (stdio). Also starts the clip daemon automatically unless |
| Run the MCP server only, without starting the clip daemon |
| Run the clip bridge daemon standalone (port 8770) |
| Enable phone→pull: phone can GET /clip to retrieve the PC clipboard |
| Auto-inject received content into the PC OS clipboard (off by default) |
| (Windows, admin) Add the durable port-scoped firewall rule, then pair as usual |
| Diagnose installation, connectivity, and phone reachability |
| Show local-only activation stats ( |
Other MCP clients (Claude Desktop, Codex, …)
uvx onsense pair auto-registers the server with Claude Code (via claude mcp add) — this one-line auto-setup is Claude Code-specific. The MCP server itself is standard stdio MCP, so any MCP-compatible client works once you add it manually. Run uvx onsense pair once first: it saves your phone's address and token to ~/.onsense/pair.json, which the server reads at request time — so you don't put the token in each client's config, and the phone's IP is auto-tracked via mDNS.
Claude Desktop — add to claude_desktop_config.json:
{ "mcpServers": { "onsense": { "command": "uvx", "args": ["onsense", "serve"] } } }Codex — register via the CLI (verified with Codex CLI 0.142.5):
codex mcp add onsense -- uvx onsense serveCodex sandbox note: Codex's default sandbox blocks network access, so the MCP server can't reach your phone and tool calls fail silently. Run Codex with network access enabled (e.g.
--sandbox danger-full-access, or a sandbox policy that permits network) so onsense can talk to the phone on your LAN.
or add to ~/.codex/config.toml:
[mcp_servers.onsense]
command = "uvx"
args = ["onsense", "serve"]Restart the client once after adding the server. Any other stdio MCP client works the same way — point it at uvx onsense serve.
MCP Tools
These tools are exposed to your AI client after pairing:
Tool | Description |
| Capture the current camera frame from the phone (returns JPEG image) |
| Return phone sensor readings as JSON: battery level/charging state, ambient light (lux), accelerometer (x/y/z) |
| List recent photos on the phone: id, name, date_added, size, width, height |
| Fetch a specific photo by id (downscaled to max_width); use ids from |
| Rename a fetched file to describe what the image actually shows ( |
| Fetch whatever the phone has designated as its reference source — a live camera frame, a captured photo, or an arbitrary file (incl. non-images) — saved to disk with path + metadata. The core of the file/capture bridge |
| Read the phone's current camera FPS setting (15 = high-performance, 2 = balanced, 0 = on-demand) |
| Set the phone's camera FPS: |
If the phone's IP changes, the broker retries using mDNS autodiscovery before surfacing an error.
Clip Bridge (Phone ↔ PC File & Clipboard)
onsense serve automatically starts a clip daemon on port 8770. You can also run it standalone with onsense clip.
Phone → PC push (POST /clip)
The onSense Android app can push content to the PC:
Images are saved to disk as
latest.jpg(inONSENSE_CLIP_DIR, default<tempdir>/onsense/).Text files are saved to disk.
Other files (video, PDF, etc.) are saved to disk by filename.
If
--set-clipboardis active, images and text are also injected into the PC OS clipboard so you can paste with Ctrl+V immediately.
By default, --set-clipboard is off — files are saved to disk but the clipboard is not touched.
PC → Phone pull (GET /clip)
Off by default. Enable with:
uvx onsense clip --allow-pullWhen enabled, the phone can GET /clip to retrieve the current PC clipboard content (copied files first, then images, then text). Returns 204 if the clipboard is empty.
Ports and environment variables
Variable | Default | Purpose |
| (from pairing) | Phone HTTP base URL, e.g. |
| (from pairing) | Pairing auth token |
|
| Directory where pushed files are saved |
|
| Maximum incoming file size in MB (0 = unlimited) |
|
| Set to |
|
| Set to |
| (unset) | Local JPEG path returned by |
Security
Local network only. The PC-side services bind to all interfaces but reject connections from non-private IP addresses at the application layer. They are not intended to be exposed to the internet.
HMAC request signing. The pairing token is never sent in cleartext. Every authenticated request is signed with HMAC-SHA256 over METHOD\npath\ntimestamp\nnonce\nalgorithm, keyed by a signing key derived from the pairing token via HKDF-SHA256 (a key separate from the encryption key), and carries X-Ts / X-Nonce / X-Sig / X-Enc headers. Servers verify in constant time, reject timestamps outside a ±300 s window, and reject reused nonces — so a sniffed request cannot be replayed and the token cannot be stolen off the wire. New Android installs generate a 128-bit random token, stored on the phone and in ~/.onsense/pair.json (chmod 600) after pairing. (The /health endpoint is unauthenticated.) See PROTOCOL.md for the exact wire format.
Pull and clipboard injection are off by default. GET /clip (phone pulls PC clipboard) and OS clipboard auto-injection (phone push → Ctrl+V) are disabled unless you explicitly pass --allow-pull or --set-clipboard.
Encrypted bodies (AES-256-GCM). Sensitive payloads — camera frames, photos, sensor data, files, and clipboard content — are encrypted between the phone and your PC with AES-256-GCM (no cloud in between, so there is no third party to decrypt them). The key is derived from the pairing token via HKDF-SHA256 (a key separate from the signing key); each message uses a fresh 96-bit nonce, and the GCM tag authenticates the body and binds it to its request (so tampering or response substitution is rejected). A passive sniffer on the same Wi-Fi sees only ciphertext. Low-sensitivity metadata stays plaintext: the open /version and /health endpoints, HTTP error responses, and the saved-file path returned after a push. (Note: large transfers currently buffer the body in memory while encrypting/decrypting — chunked streaming for very large files is a future step. Transport-level TLS is also a possible future hardening.)
File size cap. Incoming pushes are rejected if they exceed ONSENSE_CLIP_MAX_MB (default 200 MB). Set to 0 to remove the cap.
Reporting a vulnerability. Please report security issues privately — see SECURITY.md. Do not open a public issue for security reports.
License
MIT. See LICENSE.
Available Tools
4 toolsget_cam_fpsA
Query the phone's current camera FPS setting (15=high performance, 2=balanced, 0=on-demand).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that it is a query operation and explains return values, but does not mention side effects, authentication needs, or error cases. For a simple read-only tool, this is acceptable but not exemplary.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that is front-loaded with the main action and includes clarifying details. No superfluous words are present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no parameters and an existing output schema, the description adequately conveys the tool's purpose. The value mapping is included. Minor missing context about error handling or compatibility is not critical for a simple query.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, so schema coverage is 100% trivially. The baseline for no parameters is 4, and the description adds no parameter-specific context because none is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool queries the phone's current camera FPS setting and explains the meaning of the return values (15=high performance, 2=balanced, 0=on-demand). This specific verb+resource distinguishes it from sibling tools like get_live_frame and read_sensors.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not explicitly state when to use this tool versus alternatives. Usage is implied from the naming and explanation, but no guidance on when not to use it or prerequisites is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_live_frameA
One current frame from the phone camera (JPEG). Falls back to a local test image (if configured) when the phone is unreachable.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, description takes full burden. It discloses the return type (JPEG) and the fallback to test image when phone unreachable. Missing details like blocking nature or error handling, but adequately transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, front-loaded with main purpose. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero parameters and no output schema, description provides essential behavior and fallback. Could mention if the frame is real-time or cached, but complete enough for a simple tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so schema coverage is 100%. Baseline is 4; no additional parameter info needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it returns one current frame from phone camera in JPEG format, distinguishing it from siblings like get_cam_fps (frame rate) and read_sensors (sensor data).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implies usage for getting a single camera frame but does not explicitly compare with alternatives or specify when not to use. The fallback behavior is mentioned but no guidance on choosing between this and other tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_referenceA
Download whatever the phone currently designates as the 'share target' to the PC, save it, and return the path and metadata (JSON).
Depends on the phone app's reference mode: LIVE = real-time camera frame, Capture = a fixed captured image, File = an arbitrary file the user chose. Non-image files (PDF, video, documents, etc.) are fetched as-is too. (If you only need an image preview, get_live_frame is simpler.) Returns: {"path", "mime", "bytes", "name"} — path is the PC-local save path (the user's Downloads folder, so it's easy to find and use later — not a temp folder). Always call this to fetch the phone's CURRENT designation — never reuse files already sitting in the save folder (they are stale copies from earlier fetches, not what the user has designated now).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses behavior: dependency on phone's reference mode (LIVE, Capture, File), handling of non-image files, return format, and storage location (Downloads folder, not temp). It also warns against reusing stale copies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence adds value. The description is front-loaded with the core action, then details modes and return values. No redundancy or unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero parameters and the existence of an output schema, the description explains the output fields (path, mime, bytes, name) and covers edge cases like non-image files and different modes. It provides complete context for using the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters (100% coverage). Since there are no parameters, the description does not need to add parameter semantics; it correctly focuses on behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool downloads the phone's current 'share target' to the PC, saves it, and returns path and metadata. It explicitly distinguishes from sibling tool 'get_live_frame' by noting the latter is simpler for image previews only.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context on when to use (to fetch the current designation) and when not to (avoid reusing stale files). It mentions an alternative ('get_live_frame') but does not address other siblings like 'get_cam_fps' or 'read_sensors'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_sensorsA
The phone's current sensor values (battery level/charging, illuminance lux, acceleration x/y/z) as JSON.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses that it returns current instantaneous values as JSON. Lists included sensors. Could be more explicit about one-time read nature and lack of side effects, but adequate given no annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence, highly efficient, lists all key info (what, format, sensors).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Zero parameters and output schema present. Description sufficiently explains tool behavior and return content; omitted units are minor.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters exist; schema coverage is 100%. Description adds no parameter info, but none needed. Baseline score of 4 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it reads phone sensor values (battery, illuminance, acceleration) and returns as JSON. Differentiates from camera-related sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use or when-not-to-use guidance, but sibling names imply it is for general sensor data, not camera-specific data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool has a distinct, non-overlapping purpose: camera FPS query, live frame capture, fetching the current share target, and sensor data. No ambiguity.
Tools use snake_case consistently, but mix verbs 'get' (3 tools) and 'read' (1 tool). This is a minor inconsistency.
4 tools is well within the ideal range for a focused server. Each tool serves a clear function without redundancy.
Covers core read operations for camera, sensors, and file sharing, but lacks set/control tools (e.g., setting FPS, switching reference mode). Minor gaps for a read-only interface.
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 Connectors
Turns a phone into a camera+Bluetooth remote so AI assistants can see and control any PC.
Reach your own phone from an AI agent: notifications, approval questions, reminders, ring, files.
Control real Android and iOS devices with LLM agents — tap, swipe, type, automate flows.
Melaya is a remote MCP server. It gives an assistant hands on your own Android phone and browser: it reads the screen through the accessibility tree, then taps, types and navigates inside the apps and sites you allow-list, with no per-app API. It also builds, schedules and runs agent pipelines across 6k+ connected tools. OAuth 2.1, nothing to install.
Related MCP Servers
- AlicenseCqualityBmaintenanceA lightweight bridge enabling AI agents to perform real-world tasks on Android devices such as app navigation, UI interaction, and automated QA testing without requiring computer-vision pipelines or preprogrammed scripts.14826MIT
- AlicenseAqualityFmaintenanceProvides AI agents with real-time vision and control over Android devices through screen streaming, UI automation, and fast input control via scrcpy protocol.3317MIT
- AlicenseAqualityCmaintenanceAgent Droid Bridge gives AI agents programmatic control over Android devices and emulators via ADB, exposed as an MCP server.1121MIT
- AlicenseBqualityCmaintenanceEnables AI agents to control Android devices via ADB, supporting gestures, input, screenshots, UI analysis, and app management.1917ISC
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/hufirst/onsense'
If you have feedback or need assistance with the MCP directory API, please join our Discord server