Skip to main content

tauri_plugin_mcp_bridge/
lib.rs

1//! # Tauri MCP Bridge Plugin
2//!
3//! A Tauri plugin that bridges the Model Context Protocol (MCP) with Tauri applications,
4//! enabling deep inspection and interaction with Tauri's IPC layer, backend state, and
5//! window management.
6//!
7//! ## Overview
8//!
9//! The MCP Bridge plugin extends MCP servers with direct access to Tauri internals.
10//! It provides real-time IPC monitoring, window state inspection, backend state access,
11//! and event emission capabilities.
12//!
13//! ## Features
14//!
15//! - **IPC Monitoring**: Capture and analyze all Tauri IPC calls with timing information
16//! - **Window Information**: Query detailed window state (size, position, focus, visibility)
17//! - **Backend State**: Access application backend state and metadata
18//! - **Event Emission**: Trigger custom events for testing and automation
19//! - **WebSocket Server**: Real-time event streaming on dynamically allocated port
20//!
21//! ## Usage
22//!
23//! Add the plugin to your Tauri application:
24//!
25//! ```rust,ignore
26//! use tauri_plugin_mcp_bridge;
27//!
28//! fn main() {
29//!     tauri::Builder::default()
30//!         .plugin(tauri_plugin_mcp_bridge::init())
31//!         .run(tauri::generate_context!())
32//!         .expect("error while running tauri application");
33//! }
34//! ```
35//!
36//! ## Architecture
37//!
38//! The plugin consists of three main components:
39//!
40//! - **Commands Module**: Tauri commands for IPC interaction
41//! - **Monitor Module**: IPC event capture and storage
42//! - **WebSocket Module**: Real-time event streaming server
43//!
44//! ## Examples
45//!
46//! ### Start IPC Monitoring
47//!
48//! ```typescript
49//! import { invoke } from '@tauri-apps/api/core';
50//!
51//! await invoke('plugin:mcp-bridge|start_ipc_monitor');
52//! ```
53//!
54//! ### Get Window Information
55//!
56//! ```typescript
57//! const info = await invoke('plugin:mcp-bridge|get_window_info');
58//! console.log(info); // { width, height, x, y, title, focused, visible }
59//! ```
60//!
61//! ## Permissions
62//!
63//! The plugin's default permission set enables all commands. Individual permissions
64//! can be configured in your `capabilities` using the autogenerated permission
65//! identifiers:
66//!
67//! - `allow-capture-native-screenshot` / `deny-capture-native-screenshot`
68//! - `allow-emit-event` / `deny-emit-event`
69//! - `allow-execute-command` / `deny-execute-command`
70//! - `allow-execute-js` / `deny-execute-js`
71//! - `allow-get-backend-state` / `deny-get-backend-state`
72//! - `allow-get-ipc-events` / `deny-get-ipc-events`
73//! - `allow-get-window-info` / `deny-get-window-info`
74//! - `allow-list-windows` / `deny-list-windows`
75//! - `allow-report-ipc-event` / `deny-report-ipc-event`
76//! - `allow-request-script-injection` / `deny-request-script-injection`
77//! - `allow-script-result` / `deny-script-result`
78//! - `allow-start-ipc-monitor` / `deny-start-ipc-monitor`
79//! - `allow-stop-ipc-monitor` / `deny-stop-ipc-monitor`
80
81pub mod commands;
82pub mod config;
83pub mod discovery;
84mod logging;
85pub mod monitor;
86pub mod screenshot;
87pub mod script_registry;
88pub mod websocket;
89
90pub use config::{Builder, Config};
91
92use commands::ScriptExecutor;
93use discovery::find_available_port;
94use logging::{mcp_log_error, mcp_log_info};
95use monitor::IPCMonitor;
96use script_registry::create_shared_registry;
97use std::sync::{Arc, Mutex};
98use tauri::{plugin::Builder as PluginBuilder, plugin::TauriPlugin, Manager, Runtime};
99
100/// Initializes the MCP Bridge plugin.
101///
102/// This function creates and configures the MCP Bridge plugin with all necessary
103/// command handlers and background services. It sets up:
104///
105/// - IPC monitoring state management
106/// - WebSocket server for real-time event streaming (automatic port selection)
107/// - All plugin commands for Tauri IPC interaction
108///
109/// # Type Parameters
110///
111/// * `R` - The Tauri runtime type (typically `tauri::Wry`)
112///
113/// # Returns
114///
115/// A configured `TauriPlugin` ready to be added to your Tauri application.
116///
117/// # Examples
118///
119/// ```rust,ignore
120/// use tauri_plugin_mcp_bridge;
121///
122/// tauri::Builder::default()
123///     .plugin(tauri_plugin_mcp_bridge::init())
124///     .run(tauri::generate_context!())
125///     .expect("error while running tauri application");
126/// ```
127///
128/// # Background Services
129///
130/// The plugin automatically starts a WebSocket server on an available port
131/// (starting from 9223). This server runs in the background and does not
132/// block the main application thread.
133pub fn init<R: Runtime>() -> TauriPlugin<R> {
134    init_with_config(Config::default())
135}
136
137/// Initializes the MCP Bridge plugin with custom configuration.
138///
139/// # Arguments
140///
141/// * `config` - The configuration options for the plugin
142///
143/// # Examples
144///
145/// ```rust,ignore
146/// use tauri_plugin_mcp_bridge::{Config, init_with_config};
147///
148/// // Localhost only:
149/// let config = Config::localhost_only();
150/// tauri::Builder::default()
151///     .plugin(init_with_config(config))
152///     .run(tauri::generate_context!())
153///     .expect("error while running tauri application");
154/// ```
155pub fn init_with_config<R: Runtime>(config: Config) -> TauriPlugin<R> {
156    let bind_address = config.bind_address.clone();
157    let base_port = config.base_port;
158
159    PluginBuilder::<R>::new("mcp-bridge")
160        .invoke_handler(tauri::generate_handler![
161            commands::execute_command::execute_command,
162            commands::window_info::get_window_info,
163            commands::backend_state::get_backend_state,
164            commands::emit_event::emit_event,
165            commands::ipc_monitor::start_ipc_monitor,
166            commands::ipc_monitor::stop_ipc_monitor,
167            commands::ipc_monitor::get_ipc_events,
168            commands::ipc_monitor::report_ipc_event,
169            commands::execute_js::execute_js,
170            commands::script_executor::script_result,
171            commands::screenshot::capture_native_screenshot,
172            commands::list_windows::list_windows,
173            commands::script_injection::request_script_injection,
174        ])
175        .js_init_script(include_str!("bridge.js").to_string())
176        .setup(move |app, _api| {
177            // Initialize script executor state
178            app.manage(ScriptExecutor::new());
179
180            // Initialize IPC monitor state
181            let monitor = Arc::new(Mutex::new(IPCMonitor::new()));
182            app.manage(monitor.clone());
183
184            // Initialize script registry for persistent script injection
185            let script_registry = create_shared_registry();
186            app.manage(script_registry);
187
188            // Find an available port for WebSocket server
189            let port = find_available_port(&bind_address, base_port);
190
191            // Log app information for debugging
192            let app_name = app
193                .config()
194                .product_name
195                .clone()
196                .unwrap_or_else(|| "Tauri App".to_string());
197
198            let identifier = app.config().identifier.clone();
199
200            // Start WebSocket server in background
201            let app_handle = app.clone();
202            let (ws_server, _event_rx) =
203                websocket::WebSocketServer::new(port, &bind_address, app_handle);
204
205            tauri::async_runtime::spawn(async move {
206                if let Err(e) = ws_server.start().await {
207                    mcp_log_error("PLUGIN", &format!("WebSocket server error: {e}"));
208                }
209            });
210
211            mcp_log_info(
212                "PLUGIN",
213                &format!(
214                    "MCP Bridge plugin initialized for '{app_name}' ({identifier}) on {bind_address}:{port}"
215                ),
216            );
217            Ok(())
218        })
219        .build()
220}