Skip to content
This repository was archived by the owner on May 13, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions packages/mcp-server/src/shared/makeRequest.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { describe, expect, test } from "bun:test";
import { resolveBaseUrl } from "./makeRequest";

describe("resolveBaseUrl", () => {
test("defaults to the Local REST API HTTPS port", () => {
expect(resolveBaseUrl({})).toBe("https://127.0.0.1:27124");
});

test("uses the default HTTP port when HTTP is enabled", () => {
expect(resolveBaseUrl({ OBSIDIAN_USE_HTTP: "true" })).toBe(
"http://127.0.0.1:27123",
);
});

test("uses custom HTTP and HTTPS ports", () => {
expect(
resolveBaseUrl({
OBSIDIAN_USE_HTTP: "true",
OBSIDIAN_HTTP_PORT: "27125",
}),
).toBe("http://127.0.0.1:27125");

expect(resolveBaseUrl({ OBSIDIAN_HTTPS_PORT: "27126" })).toBe(
"https://127.0.0.1:27126",
);
});

test("uses base URL override before host, protocol, and port fields", () => {
expect(
resolveBaseUrl({
OBSIDIAN_BASE_URL: "http://127.0.0.1:3000/",
OBSIDIAN_USE_HTTP: "false",
OBSIDIAN_HTTPS_PORT: "27126",
}),
).toBe("http://127.0.0.1:3000");
});
});
37 changes: 31 additions & 6 deletions packages/mcp-server/src/shared/makeRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,37 @@ import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
import { type, type Type } from "arktype";
import { logger } from "./logger";

// Default to HTTPS port, fallback to HTTP if specified
const USE_HTTP = process.env.OBSIDIAN_USE_HTTP === "true";
const PORT = USE_HTTP ? 27123 : 27124;
const PROTOCOL = USE_HTTP ? "http" : "https";
const HOST = process.env.OBSIDIAN_HOST || "127.0.0.1";
export const BASE_URL = `${PROTOCOL}://${HOST}:${PORT}`;
function trimTrailingSlash(value: string): string {
return value.replace(/\/$/, "");
}

interface BaseUrlEnv {
OBSIDIAN_BASE_URL?: string;
OBSIDIAN_HOST?: string;
OBSIDIAN_HTTP_PORT?: string;
OBSIDIAN_HTTPS_PORT?: string;
OBSIDIAN_USE_HTTP?: string;
}

export function resolveBaseUrl(env: BaseUrlEnv = process.env): string {
const baseUrl = env.OBSIDIAN_BASE_URL?.trim();
if (baseUrl) {
return trimTrailingSlash(baseUrl);
}

// Default to HTTPS, fallback to HTTP if specified. Custom ports allow
// multiple Obsidian vaults to expose separate Local REST API instances.
const useHttp = env.OBSIDIAN_USE_HTTP === "true";
const protocol = useHttp ? "http" : "https";
const host = env.OBSIDIAN_HOST || "127.0.0.1";
const port = useHttp
? (env.OBSIDIAN_HTTP_PORT ?? "27123")
: (env.OBSIDIAN_HTTPS_PORT ?? "27124");

return `${protocol}://${host}:${port}`;
}

export const BASE_URL = resolveBaseUrl();

// Disable TLS certificate validation for local self-signed certificates
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
Expand Down
4 changes: 4 additions & 0 deletions packages/mcp-server/src/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ declare global {
NODE_ENV: "development" | "production";
NODE_TLS_REJECT_UNAUTHORIZED: `${0 | 1}`;
OBSIDIAN_API_KEY?: string;
OBSIDIAN_BASE_URL?: string;
OBSIDIAN_HOST?: string;
OBSIDIAN_HTTP_PORT?: string;
OBSIDIAN_HTTPS_PORT?: string;
OBSIDIAN_USE_HTTP?: string;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

export let plugin: McpToolsPlugin;

let localRestApi = { ...plugin.settings.localRestApi };

// Dependencies and API key status
const deps = loadDependenciesArray(plugin);

Expand Down Expand Up @@ -51,6 +53,20 @@
}
}

async function saveLocalRestApiSettings() {
plugin.settings.localRestApi = {
host: localRestApi.host || "127.0.0.1",
useHttp: !!localRestApi.useHttp,
httpPort: Number(localRestApi.httpPort) || 27123,
httpsPort: Number(localRestApi.httpsPort) || 27124,
baseUrl: localRestApi.baseUrl?.trim() || "",
};
await plugin.saveSettings();
new Notice(
"MCP Tools settings saved. Reinstall or update the MCP server config for changes to apply.",
);
}

// Handle uninstall
async function handleUninstall() {
try {
Expand Down Expand Up @@ -100,6 +116,42 @@
{/if}
</div>

<div class="local-rest-api-settings">
<h3>Local REST API connection</h3>

<label>
Host
<input bind:value={localRestApi.host} placeholder="127.0.0.1" />
</label>

<label>
<input type="checkbox" bind:checked={localRestApi.useHttp} />
Use HTTP instead of HTTPS
</label>

<label>
HTTP port
<input type="number" min="1" max="65535" bind:value={localRestApi.httpPort} />
</label>

<label>
HTTPS port
<input type="number" min="1" max="65535" bind:value={localRestApi.httpsPort} />
</label>

<label>
Advanced base URL override
<input bind:value={localRestApi.baseUrl} placeholder="http://127.0.0.1:27125" />
</label>

<p class="setting-note">
Leave the base URL empty to use host, protocol, and port fields. Set it for
multi-vault setups with custom Local REST API ports.
</p>

<button on:click={saveLocalRestApiSettings}>Save connection settings</button>
</div>

<div class="dependencies">
<h3>Dependencies</h3>

Expand Down Expand Up @@ -160,6 +212,29 @@
margin-bottom: 0.5em;
}

.local-rest-api-settings {
margin: 1.5em 0;
}

.local-rest-api-settings label {
display: block;
margin-bottom: 0.75em;
}

.local-rest-api-settings input[type="text"],
.local-rest-api-settings input[type="number"],
.local-rest-api-settings input:not([type]) {
display: block;
margin-top: 0.25em;
width: min(100%, 28rem);
}

.setting-note {
color: var(--text-muted);
font-size: var(--font-ui-small);
max-width: 36rem;
}

.installed {
color: var(--text-success);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fsp from "fs/promises";
import { Plugin } from "obsidian";
import os from "os";
import path from "path";
import type McpToolsPlugin from "$/main";
import { logger } from "$/shared/logger";
import { CLAUDE_CONFIG_PATH } from "../constants";

Expand All @@ -12,6 +12,11 @@ interface ClaudeConfig {
args?: string[];
env?: {
OBSIDIAN_API_KEY?: string;
OBSIDIAN_BASE_URL?: string;
OBSIDIAN_HOST?: string;
OBSIDIAN_HTTP_PORT?: string;
OBSIDIAN_HTTPS_PORT?: string;
OBSIDIAN_USE_HTTP?: string;
[key: string]: string | undefined;
};
};
Expand Down Expand Up @@ -53,7 +58,7 @@ function getConfigPath(): string {
* Updates the Claude Desktop config file with MCP server settings
*/
export async function updateClaudeConfig(
plugin: Plugin,
plugin: McpToolsPlugin,
serverPath: string,
apiKey?: string
): Promise<void> {
Expand All @@ -78,10 +83,16 @@ export async function updateClaudeConfig(
}

// Update config with our server entry
const localRestApi = plugin.settings.localRestApi ?? {};
config.mcpServers["obsidian-mcp-tools"] = {
command: serverPath,
env: {
OBSIDIAN_API_KEY: apiKey,
OBSIDIAN_HOST: localRestApi.host,
OBSIDIAN_USE_HTTP: String(localRestApi.useHttp),
OBSIDIAN_HTTP_PORT: localRestApi.httpPort?.toString(),
OBSIDIAN_HTTPS_PORT: localRestApi.httpsPort?.toString(),
OBSIDIAN_BASE_URL: localRestApi.baseUrl || undefined,
},
};

Expand Down
31 changes: 31 additions & 0 deletions packages/obsidian-plugin/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,21 @@ import {
type Dependencies,
} from "./shared";
import { logger } from "./shared/logger";
import type { McpToolsPluginSettings } from "./types";

export const DEFAULT_SETTINGS: McpToolsPluginSettings = {
localRestApi: {
host: "127.0.0.1",
useHttp: false,
httpPort: 27123,
httpsPort: 27124,
baseUrl: "",
},
};

export default class McpToolsPlugin extends Plugin {
settings = DEFAULT_SETTINGS;

private localRestApi: Dependencies["obsidian-local-rest-api"] = {
id: "obsidian-local-rest-api",
name: "Local REST API",
Expand All @@ -34,7 +47,25 @@ export default class McpToolsPlugin extends Plugin {
return this.localRestApi.plugin?.settings?.apiKey;
}

async loadSettings() {
const data = await this.loadData();
this.settings = {
...DEFAULT_SETTINGS,
...data,
localRestApi: {
...DEFAULT_SETTINGS.localRestApi,
...data?.localRestApi,
},
};
}

async saveSettings() {
await this.saveData(this.settings);
}

async onload() {
await this.loadSettings();

// Initialize features in order
await setupCore(this);
await setupMcpServerInstall(this);
Expand Down
19 changes: 13 additions & 6 deletions packages/obsidian-plugin/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
declare module "obsidian" {
interface McpToolsPluginSettings {
version?: string;
}
export interface McpToolsLocalRestApiSettings {
host: string;
useHttp: boolean;
httpPort: number;
httpsPort: number;
baseUrl?: string;
}

export interface McpToolsPluginSettings {
version?: string;
localRestApi: McpToolsLocalRestApiSettings;
}

declare module "obsidian" {
interface Plugin {
loadData(): Promise<McpToolsPluginSettings>;
saveData(data: McpToolsPluginSettings): Promise<void>;
}
}

export {};