MCP Tools for Obsidian

<script lang="ts"> import type McpToolsPlugin from "$/main"; import { FULL_LOGGER_FILENAME, loadDependenciesArray } from "$/shared"; import { Notice } from "obsidian"; import { dirname } from "path"; import { onMount } from "svelte"; import { removeFromClaudeConfig, updateClaudeConfig, } from "../services/config"; import { installMcpServer } from "../services/install"; import { getInstallationStatus } from "../services/status"; import { uninstallServer } from "../services/uninstall"; import type { InstallationStatus } from "../types"; import { openFolder } from "../utils/openFolder"; export let plugin: McpToolsPlugin; // Dependencies and API key status const deps = loadDependenciesArray(plugin); // Installation status let status: InstallationStatus = { state: "not installed", versions: {}, }; onMount(async () => { status = await getInstallationStatus(plugin); }); // Handle installation async function handleInstall() { try { const apiKey = await plugin.getLocalRestApiKey(); if (!apiKey) { throw new Error("Local REST API key is not configured"); } status = { ...status, state: "installing" }; const installPath = await installMcpServer(plugin); // Update Claude config await updateClaudeConfig(plugin, installPath.path, apiKey); status = await getInstallationStatus(plugin); } catch (error) { const message = error instanceof Error ? error.message : "Installation failed"; status = { ...status, state: "error", error: message }; new Notice(message); } } // Handle uninstall async function handleUninstall() { try { status = { ...status, state: "installing" }; await uninstallServer(plugin); await removeFromClaudeConfig(); status = { ...status, state: "not installed" }; } catch (error) { const message = error instanceof Error ? error.message : "Uninstallation failed"; status = { ...status, state: "error", error: message, }; new Notice(message); } } </script> <div class="installation-status"> <h3>Installation status</h3> {#if status.state === "no api key"} <div class="error-message">Please configure the Local REST API plugin</div> {:else if status.state === "not installed"} <div class="status-message"> MCP Server is not installed <button on:click={handleInstall}>Install server</button> </div> {:else if status.state === "installing"} <div class="status-message">Installing MCP server...</div> {:else if status.state === "installed"} <div class="status-message"> MCP Server v{status.versions.server} is installed <button on:click={handleUninstall}>Uninstall</button> </div> {:else if status.state === "outdated"} <div class="status-message"> Update available (v{status.versions.server} -> v{status.versions.plugin}) <button on:click={handleInstall}>Update</button> </div> {:else if status.state === "uninstalling"} <div class="status-message">Uninstalling MCP server...</div> {:else if status.state === "error"} <div class="error-message">{status.error}</div> {/if} </div> <div class="dependencies"> <h3>Dependencies</h3> {#each $deps as dep (dep.id)} <div class="dependency-item"> {#if dep.installed} ✅ {dep.name} is installed {:else} ❌ {dep.name} {dep.required ? "(Required)" : "(Optional)"} {#if dep.url}<a href={dep.url} target="_blank">How to install?</a>{/if} {/if} </div> {/each} </div> <div class="links"> <h3>Resources</h3> {#if status.path} <div class="link-item"> <!-- svelte-ignore a11y_no_static_element_interactions --> <a on:click={() => status.dir && openFolder(status.dir)}> Server install folder </a> </div> {/if} <div class="link-item"> <!-- svelte-ignore a11y_no_static_element_interactions --> <a on:click={() => openFolder(dirname(FULL_LOGGER_FILENAME))}> Server log folder </a> </div> <div class="link-item"> <a href="https://github.com/jacksteamdev/obsidian-mcp-tools" target="_blank" > GitHub repository </a> </div> </div> <style> .error-message { color: var(--text-error); margin-bottom: 1em; } .status-message { margin-bottom: 1em; } .dependency-item { margin-bottom: 0.5em; } .installed { color: var(--text-success); } .not-installed { color: var(--text-muted); } .link-item { margin-bottom: 0.5em; } button { margin-left: 0.5em; } </style>