by P3GLEG
Allows AI agents (e.g., Cursor, Claude Code) to debug within Tauri apps via screenshot capture, window management, DOM access, and simulated user inputs.
# Add to your Claude Code skills
git clone https://github.com/P3GLEG/tauri-plugin-mcpGuides for using ai agents skills like tauri-plugin-mcp.
Last scanned: 6/16/2026
{
"issues": [
{
"type": "npm-audit",
"message": "picomatch: Picomatch: Method Injection in POSIX Character Classes causes incorrect Glob Matching",
"severity": "high"
}
],
"status": "WARNING",
"scannedAt": "2026-06-16T09:27:07.179Z",
"npmAuditRan": true,
"pipAuditRan": true,
"promptInjectionRan": true
}tauri-plugin-mcp is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by P3GLEG. Allows AI agents (e.g., Cursor, Claude Code) to debug within Tauri apps via screenshot capture, window management, DOM access, and simulated user inputs. It has 103 GitHub stars.
tauri-plugin-mcp returned warnings in SkillsLLM's automated security scan. It has no critical vulnerabilities, but review the flagged issues in the Security Report section before adding it to your workflow.
Clone the repository with "git clone https://github.com/P3GLEG/tauri-plugin-mcp" and add it to your Claude Code skills directory (see the Installation section above).
tauri-plugin-mcp is primarily written in Rust. It is open-source under P3GLEG on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh tauri-plugin-mcp against similar tools.
No comments yet. Be the first to share your thoughts!
Requires a passing catalog security scan. Resolve the flagged issues and resubmit to enable featuring.
A Tauri plugin and MCP server that allow AI agents such as Cursor and Claude Code to interact with and debug your Tauri application through screenshots, DOM access, input simulation, and more.
Upgrading? Behavior changes are listed in CHANGELOG.md.
npm install tauri-plugin-mcp
npm install -g tauri-plugin-mcp-server
# or run directly
npx tauri-plugin-mcp-server
Coming soon to crates.io. For now, use a git dependency:
[dependencies]
tauri-plugin-mcp = { git = "https://github.com/P3GLEG/tauri-plugin-mcp" }
The MCP server exposes 19 high-level tools to AI agents:
| Tool | Description |
|---|---|
| take_screenshot | Captures a screenshot of an application window. Saves full image to disk with small thumbnail inline (optimized for token efficiency). |
| query_page | Inspects the current page. Modes: map (structured element refs), html (raw DOM), state (URL/title/scroll/viewport), find_element (CSS pixel coordinates for clicking), app_info (app metadata, windows, monitors). |
| click | Clicks via selector (ref, id, class, css, tag, text) or at raw x/y coordinates. Selector-based left clicks dispatch synthetic pointer events at the element (no OS permissions needed); right/middle/double and raw x/y clicks use native clicking. scope_selector/match/nth disambiguate repeated matches. |
| read_text | Reads visible text of elements matching a CSS selector: per-element {tag, text, visible, attrs?}, whitespace-collapsed, output hard-capped with a truncated flag. The structured replacement for execute_js text-scraping snippets. |
| inspect_element | Bounding rect, computed styles (default layout/color set or explicit style_props), classList and attributes — for visual/layout QA without execute_js getComputedStyle snippets. |
| dispatch_pointer | Synthetic pointer/mouse gesture chains (click, dblclick, down, up, hover, drag) on the exact matched element, no retargeting. Element-relative offset for canvas hit-testing; drags interpolate moves on the element and document (d3-drag compatible). Events are isTrusted=false. |
| app_bridge | Calls helpers the host app registered via window.__MCP_BRIDGE__.register(name, fn, description) — list to discover, call to invoke (async supported, results serialized + truncated). The sanctioned path to app state instead of execute_js against internals. |
| type_text | Types text into the page. Supports a fields array for bulk form fill, selector targeting, or typing into the focused element. Selects options in <select> dropdowns by value or label, and attaches files to <input type="file"> via a files array. Works with inputs, textareas, contentEditable, React, Lexical, and Slate. |
| press_key | Presses keyboard keys the typing tools can't express: Escape, Enter, Tab, arrows, Backspace/Delete, F-keys, and modifier chords (cmd+a). Emulates default actions (Enter submits, Tab moves focus) unless the app prevents them. |
| mouse_action | Non-click mouse actions: hover, scroll (by direction/amount/to element/to top/bottom), drag (start to end coordinates). |
| navigate | Webview navigation: goto (URL), back/forward (with optional delta), reload. |
| execute_js | Runs arbitrary JavaScript in the webview. Returns the last expression's value; promises are awaited. The universal escape hatch. |
| manage_storage | localStorage operations (get/set/remove/clear/keys) and cookie management (get/clear). |
| manage_window | Window control (list/focus/minimize/maximize/close/position/size/fullscreen), zoom, devtools, and webview state management. |
| wait_for | Waits for a condition: text appearing/disappearing, element visible/hidden/attached/detached. Useful after async content loads. |
| restart_app | Restarts the Tauri application and waits for it to come back online. Force-kills a frozen app (IPC mode only). Refuses under tauri dev — restarting would orphan the app outside the dev supervisor; reload the frontend with navigate instead. |
| manage_ipc | Tauri IPC access: invoke any #[tauri::command] with JSON args through the app's real IPC path, inspect captured webview↔Rust invoke traffic (names, args/result previews, latency, error rates), and drive events — emit fires one, arm_event registers a background listener before you act (arm → act → check captured to assert an event fired), wait_event blocks for recurring events. Entries an app self-reports via push_ipc are labeled [self-reported] — any page script can forge them, so they're surfaced as untrusted. |
| query_logs | Queries buffered app logs (Rust log!() output, webview console.* calls, and intercepted dialogs) with level/source/substring filters, pagination, and a summary mode. |
| log_mark | Inserts begin/end markers into the log buffer so query_logs can return exactly the logs produced by an action. |
Only include the MCP plugin in development builds:
#[cfg(debug_assertions)]
{
builder = builder.plugin(tauri_plugin_mcp::init_with_config(
tauri_plugin_mcp::PluginConfig::new("APPLICATION_NAME".to_string())
.start_socket_server(true)
// IPC socket (default — recommended)
.socket_path("/tmp/tauri-mcp.sock")
// Or TCP socket
// .tcp_localhost(4000)
// For multi-webview apps where the webview label differs from the window label
// .default_webview_label("preview".to_string())
// Optional explicit auth token (IPC and TCP). If omitted, a random
// token is generated and written to a `.token` sidecar file that
// the MCP server discovers automatically — no wiring needed.
// .auth_token("my-secret-token".to_string())
));
}
By default the plugin replaces window.alert/confirm/prompt with non-blocking stubs — native dialogs block the webview's JS thread and would deadlock every MCP tool that round-trips through JS. Intercepted dialogs are auto-answered (confirm → false — the safe answer for a consent gate, prompt → its default value) and recorded in the log buffer under target "dialog" so query_logs can report them. Opt out with .stub_dialogs(false), or override answers at runtime by setting window.__TAURI_MCP_DIALOG_RESPONSES__ = { confirm: true, prompt: "value" } (e.g. via execute_js).
The #[cfg(debug_assertions)] guard keeps the plugin out of release binaries entirely. As a second line of defense, the plugin also refuses to start its socket server in release builds unless you explicitly opt in with .allow_release_builds(true).
The webview side of the plugin must be initialized by your frontend — tools like execute_js, query_page, type_text, click (selector mode), and wait_for depend on it. Without this step those tools fail with a timeout ("Timeout waiting for JS execution").
npm install tauri-plugin-mcp
// In your app's entry point (e.g. main.ts / main.tsx)
import { setupPluginListeners } from 'tauri-plugin-mcp';
if (import.meta.env.DEV) {
setupPluginListeners();
}
Like the Rust side, gate it to development builds.
If your app defines an explicit
app.security.capabilitieslist intauri.conf.json, you must add the plugin's capability to it. In Tauri v2 a non-emptycapabilitieslist is an allowlist — capabilities not named in it are silently ignored, even though they compile. If the list omits the mcp capability, the webview→plugin commands (push_log,push_ipc) are denied with"mcp.push_log not allowed", and console/dialog logging and IPC capture silently produce nothing while every other tool keeps working (socket-driven tools don't go through this path). Symptom:window.__TAURI_MCP_LOG_STATS__in the webview showsok: 0, err: N. Either grant the mcp capability in a capability file and remove the explicit allowlist (Tauri then auto-enables all capability files), or add the capability's identifier to the list — dev-only, since a release build won't have compiled it.
{
"mcpServers": {
"tauri-mcp": {
"command": "npx",
"args": ["tauri-plugin-mcp-server"]
}
}
}
With a custom socket path:
{
"mcpServers": {
"tauri-mcp": {
"command": "npx",
"args": ["tauri-plugin-mcp-server"],
"env": {
"TAURI_MCP_IPC_PATH": "/custom/path/to/socket"
}
}
}
}
For Docker, remote debugging, or when IPC doesn't work:
{
"mcpServers": {
"tauri-mcp": {
"command": "npx",
"args": ["tauri-plugin-mcp-server"],
"env": {
"TAURI_MCP_CONNECTION_TYPE": "tcp",
"TAURI_MCP_TCP_HOST": "127.0.0.1",
"TAURI_MCP_TCP_PORT": "4000"
}
}
}
}
Make sure your Tauri app uses the same connection mode:
.plugin(tauri_plugin_mcp::init_with_config(
tauri_plugin_mcp::PluginConfig::new("MyApp".to_string())
.tcp_localhost(4000)
))
The Rust plugin honors the TAURI_MCP_IPC_PATH environment variable (which overrides the configured IPC socket path), TAURI_MCP_TCP_PORT for TCP mode, and TAURI_MCP_AUTH_TOKEN (overrides the configured/auto-generated auth token; the TS server reads the same variable). To drive several app instances side by side, launch each instance with its own socket path:
TAURI_MCP_IPC_PATH=/tmp/myapp-a.sock pnpm tauri dev
TAURI_MCP_IPC_PATH=/tmp/myapp-b.sock pnpm tauri dev
Then register one MCP server entry per instance, each with the matching TAURI_MCP_IPC_PATH in