Skip to content

Commit 0a64eb3

Browse files
committed
Add Tauri MCP server
- Add dependency to `Cargo.toml` for the MCP bridge - Register plugin in `lib.rs` ` Configure `tauri.conf.json` and permissions - Tested, it works!
1 parent c968dae commit 0a64eb3

14 files changed

Lines changed: 334 additions & 10 deletions

File tree

AGENTS.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ See [docs/adr](docs/adr) for all key technical decisions, and the
9595
[ADR-005](docs/adr/005-scoped-css-for-file-explorer.md)
9696
- **Clippy `--allow-dirty --allow-staged`** is used locally to allow auto-fixes even with uncommitted changes
9797

98+
## MCP
99+
100+
There should be an MCP server available to access Tauri. If it isn't, and you need it, ask the user for it! (There are
101+
guidelines to add it in [CONTRIBUTING.md](CONTRIBUTING.md).) Run the app in dev mode, then use the MCP server to take
102+
screenshots, click buttons, read front-end logs, and the such.
103+
104+
## Security warnings
105+
106+
- When adding new code that loads remote content (like `fetch` from external URLs or `iframe`), always add a condition
107+
to **disable** that functionality in dev mode, and use static/mock data instead. See
108+
[security docs](docs/security.md#withglobaltauri) for more reasoning.
109+
98110
## Useful references
99111

100112
- Tauri docs: https://tauri.app/v2/

CONTRIBUTING.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,36 @@ pnpm tauri build
4949

5050
This creates a production build for your current platform in `src-tauri/target/release/`.
5151

52+
## Agent integration (MCP)
53+
54+
The app uses [MCP Server Tauri](https://github.com/hypothesi/mcp-server-tauri) to let AI assistants (Claude Code,
55+
Cursor, etc.) control this app: take screenshots, click buttons, read front-end logs, etc. It's quite helpful.
56+
57+
### Setting up your AI assistant
58+
59+
For `claude-code`, `cursor`, `vscode`, or `windsurf`, there is autoconfig available. Run this command in your terminal
60+
for your specific client: `npx -y install-mcp @hypothesi/tauri-mcp-server --client <your-client>`.
61+
([source](https://github.com/hypothesi/mcp-server-tauri)).
62+
63+
If the automated setup doesn't work for you, check the MCP documentation for your specific client. For example:
64+
65+
- [Claude Desktop](https://docs.anthropic.com/en/docs/agents-and-tools/mcp)
66+
- [Cursor](https://docs.cursor.com/context/model-context-protocol)
67+
- [Antigravity](https://medium.com/google-developer-experts/google-antigravity-custom-mcp-server-integration-to-improve-vibe-coding-f92ddbc1c22d)
68+
69+
This snippet will likely come handy:
70+
71+
```json
72+
{
73+
"mcpServers": {
74+
"tauri": {
75+
"command": "npx",
76+
"args": ["-y", "@hypothesi/tauri-mcp-server"]
77+
}
78+
}
79+
}
80+
```
81+
82+
Since the agent shares the context with your IDE/client, enabling the MCP server makes the tools available to the agent automatically.
83+
5284
Happy coding!

docs/security.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Security
2+
3+
## withGlobalTauri
4+
5+
The app uses [MCP Server Tauri](https://github.com/hypothesi/mcp-server-tauri) to let AI assistants (Claude Code,
6+
Cursor, etc.) control this app: take screenshots, click buttons, read front-end logs, etc.
7+
8+
The MCP bridge requires `withGlobalTauri: true` which exposes `window.__TAURI__` to the frontend. This would be a huge
9+
security risk in production (untrusted JS could access system APIs, not good), so we enable it **only in development**:
10+
11+
1. **Compile-time exclusion**: The MCP plugin is only registered via `#[cfg(debug_assertions)]` in `lib.rs`
12+
2. **Config separation**: `"withGlobalTauri": false` in `tauri.conf.json` (production), only overridden via
13+
`tauri.dev.json` during dev
14+
3. **Wrapper script**: `scripts/tauri-wrapper.js` injects `-c src-tauri/tauri.dev.json` only for `dev` commands.
15+
(`pnpm tauri dev` calls `scripts/tauri-wrapper.js` which adds `-c src-tauri/tauri.dev.json`, then Tauri merges this
16+
with `tauri.conf.json` via [JSON Merge Patch (RFC 7396)](https://datatracker.ietf.org/doc/html/rfc7396).))
17+
18+
To avoid security issues in dev mode, always add a condition to **disable** that functionality in dev mode. This way,
19+
malicious websites can't access the system APIs even on your machine.

eslint.config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,23 @@ export default tseslint.config(
7777
],
7878
},
7979
},
80+
{
81+
// Node.js scripts (like tauri-wrapper.js) need Node globals
82+
files: ['scripts/*.js'],
83+
plugins: {
84+
prettier,
85+
},
86+
languageOptions: {
87+
ecmaVersion: 'latest',
88+
sourceType: 'module',
89+
globals: {
90+
...globals.node,
91+
},
92+
},
93+
rules: {
94+
'prettier/prettier': 'error',
95+
},
96+
},
8097
{
8198
files: ['vite.config.js', 'vitest.config.ts', 'playwright.config.ts'],
8299
plugins: {

knip.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://unpkg.com/knip@5/schema.json",
33
"ignore": ["src/lib/icon-cache.ts"],
4-
"ignoreDependencies": ["@tauri-apps/plugin-window-state", "@testing-library/svelte"],
4+
"ignoreDependencies": ["@tauri-apps/cli", "@tauri-apps/plugin-window-state", "@testing-library/svelte"],
55
"ignoreExportsUsedInFile": true
66
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"preview": "vite preview",
1010
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --compiler-warnings \"a11y_no_noninteractive_element_interactions:ignore,a11y_click_events_have_key_events:ignore,a11y_no_noninteractive_tabindex:ignore,state_referenced_locally:ignore\"",
1111
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch --compiler-warnings \"a11y_no_noninteractive_element_interactions:ignore,a11y_click_events_have_key_events:ignore,a11y_no_noninteractive_tabindex:ignore,state_referenced_locally:ignore\"",
12-
"tauri": "tauri",
12+
"tauri": "node scripts/tauri-wrapper.js",
1313
"lint": "eslint .",
1414
"lint:fix": "eslint . --fix",
1515
"format": "prettier --write .",

scripts/tauri-wrapper.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// See docs/security.md#withglobaltauri for more info on why this script exists.
2+
3+
import { spawn } from 'child_process'
4+
5+
// Get arguments passed to the script
6+
const args = process.argv.slice(2)
7+
8+
// Check if the command is 'dev'
9+
const isDev = args.includes('dev')
10+
11+
// If dev, inject the dev configuration
12+
if (isDev) {
13+
// Add -c src-tauri/tauri.dev.json to merge config
14+
args.push('-c', 'src-tauri/tauri.dev.json')
15+
}
16+
17+
// Spawn the tauri process (relies on pnpm/npm adding node_modules/.bin to PATH)
18+
const tauriProcess = spawn('tauri', args, {
19+
stdio: 'inherit',
20+
shell: true,
21+
})
22+
23+
// Handle process exit
24+
tauriProcess.on('exit', (code) => {
25+
process.exit(code ?? 0)
26+
})

0 commit comments

Comments
 (0)