feat(mcp): configure desktop root directory
- Persist an optional MCP filesystem root selected from Settings - Default file-scoped tools to the user home directory - Apply the configured root when the desktop MCP server restarts
This commit is contained in:
parent
d807828270
commit
febdcef392
|
|
@ -12,7 +12,7 @@
|
|||
- Run Pi through AI SDK HarnessAgent as a configurable desktop provider with multiple saved model profiles, secure credentials, existing MCP design tools, and per-profile thinking and permission settings.
|
||||
- Open multiple selected design files in separate tabs.
|
||||
- Let Figma API scripts and automation combine components into variant sets.
|
||||
- Monitor and restart the local MCP server and choose individual, inspection, or modification tools it exposes from Settings.
|
||||
- Monitor and restart the local MCP server, configure its root directory, and choose individual, inspection, or modification tools it exposes from Settings.
|
||||
- Add deterministic two-browser collaboration coverage for bidirectional edits, awareness, departure cleanup, partitioned-peer convergence, and reconnect synchronization without public network dependencies. (#530)
|
||||
- Import, render, edit, resize, select, and export Figma text-on-path layers while preserving their curved glyph layout.
|
||||
- Show Figma-style temporary distance measurements between selected and Option/Alt-hovered layers. (#491)
|
||||
|
|
|
|||
|
|
@ -253,6 +253,12 @@ export const dialogMessageDefaults = {
|
|||
mcpPort: 'Port',
|
||||
mcpAddress: 'Address',
|
||||
mcpVersion: 'Version',
|
||||
mcpRootDirectory: 'MCP root directory',
|
||||
mcpRootDirectoryDefault: 'User home directory (default)',
|
||||
mcpChooseRootDirectory: 'Choose folder',
|
||||
mcpUseDefaultRoot: 'Use default',
|
||||
mcpRootDirectoryDescription:
|
||||
'File tools are limited to this folder. Restart the MCP server to apply changes.',
|
||||
mcpTools: 'Available tools',
|
||||
mcpInspectionTools: 'Inspection tools',
|
||||
mcpModificationTools: 'Modification tools',
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ import { useLocalStorage } from '@vueuse/core'
|
|||
import { MCP_TOOL_CATALOG, type MCPToolCatalogEntry } from '@open-pencil/mcp/tools'
|
||||
|
||||
const DISABLED_TOOLS_STORAGE_KEY = 'open-pencil:mcp:disabled-tools'
|
||||
const ROOT_DIRECTORY_STORAGE_KEY = 'open-pencil:mcp:root-directory'
|
||||
|
||||
export const configurableMCPTools = MCP_TOOL_CATALOG.filter((tool) => tool.availability !== 'eval')
|
||||
|
||||
export const disabledMCPTools = useLocalStorage<string[]>(DISABLED_TOOLS_STORAGE_KEY, [])
|
||||
export const mcpRootDirectory = useLocalStorage(ROOT_DIRECTORY_STORAGE_KEY, '')
|
||||
|
||||
export function setMCPToolEnabled(name: string, enabled: boolean): void {
|
||||
const disabled = new Set(disabledMCPTools.value)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { decodeTauriStderr } from '@/app/shell/ui'
|
|||
import { resolvePlatformCommand } from '@/app/tauri/command'
|
||||
import { isTauri } from '@/app/tauri/env'
|
||||
|
||||
import { disabledMCPToolsCSV } from './preferences'
|
||||
import { disabledMCPToolsCSV, mcpRootDirectory } from './preferences'
|
||||
|
||||
export interface AutomationHealth {
|
||||
status: 'ok' | 'no_app'
|
||||
|
|
@ -273,12 +273,10 @@ async function startMCPIfNeeded(): Promise<AutomationServerHandle | null> {
|
|||
// Cache only after MCP startup is confirmed healthy.
|
||||
|
||||
const { Command } = await import('@tauri-apps/plugin-shell')
|
||||
// Set OPENPENCIL_MCP_ROOT to the user's home directory so file-scoped
|
||||
// tools (open_file, save_file, export_*) operate on paths inside ~,
|
||||
// which is naturally writable and matches user expectations for "my files."
|
||||
// The app bundle directory (Tauri executableDir) is read-only and would
|
||||
// cause EACCES errors on every file write.
|
||||
const mcpRoot = await resolveTauriHomeDir()
|
||||
// Scope file tools to the configured root, defaulting to the user's home.
|
||||
// The app bundle directory (Tauri executableDir) is read-only and cannot be
|
||||
// used as a safe fallback for open_file, save_file, or export tools.
|
||||
const mcpRoot = mcpRootDirectory.value.trim() || (await resolveTauriHomeDir())
|
||||
const resolved = resolvePlatformCommand(MCP_EXECUTABLE)
|
||||
const command = Command.create(resolved.command, resolved.args, {
|
||||
env: {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { useI18n } from '@open-pencil/vue'
|
|||
import {
|
||||
configurableMCPTools,
|
||||
disabledMCPTools,
|
||||
mcpRootDirectory,
|
||||
setMCPToolCategoryEnabled,
|
||||
setMCPToolEnabled
|
||||
} from '@/app/automation/mcp/preferences'
|
||||
|
|
@ -45,6 +46,12 @@ function restart(): void {
|
|||
void restartMCPRuntime()
|
||||
}
|
||||
|
||||
async function chooseRootDirectory(): Promise<void> {
|
||||
const { open } = await import('@tauri-apps/plugin-dialog')
|
||||
const directory = await open({ directory: true, multiple: false })
|
||||
if (typeof directory === 'string') mcpRootDirectory.value = directory
|
||||
}
|
||||
|
||||
function isToolEnabled(name: string): boolean {
|
||||
return !disabledToolNames.value.has(name)
|
||||
}
|
||||
|
|
@ -86,6 +93,38 @@ function enableAllTools(): void {
|
|||
<dd class="font-mono text-surface">{{ mcpRuntime.version }}</dd>
|
||||
</template>
|
||||
</dl>
|
||||
|
||||
<div class="mt-3 border-t border-border pt-3">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="min-w-0">
|
||||
<p class="text-[10px] font-medium text-surface">{{ dialogs.mcpRootDirectory }}</p>
|
||||
<p class="mt-0.5 truncate font-mono text-[10px] text-muted">
|
||||
{{ mcpRootDirectory || dialogs.mcpRootDirectoryDefault }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 gap-1.5">
|
||||
<button
|
||||
v-if="mcpRootDirectory"
|
||||
type="button"
|
||||
class="rounded border border-border px-2 py-1 text-[10px] text-muted hover:bg-hover hover:text-surface"
|
||||
@click="mcpRootDirectory = ''"
|
||||
>
|
||||
{{ dialogs.mcpUseDefaultRoot }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded border border-border px-2 py-1 text-[10px] text-surface hover:bg-hover"
|
||||
data-test-id="settings-mcp-root-directory"
|
||||
@click="chooseRootDirectory"
|
||||
>
|
||||
{{ dialogs.mcpChooseRootDirectory }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-1.5 text-[10px] leading-relaxed text-muted">
|
||||
{{ dialogs.mcpRootDirectoryDescription }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p
|
||||
|
|
|
|||
Loading…
Reference in a new issue