feat: Add HTTPS port conflict detection and auto-increment

- Apply same port conflict detection logic to HTTPS that HTTP uses
- Automatically increment HTTPS port if 3443 is in use
- Add port availability checking in settings UI for HTTPS port
- Update README with comprehensive HTTPS/TLS configuration docs
- Document manual JSON configuration for self-signed certificates
This commit is contained in:
Aaron Bockelie 2025-08-12 20:52:47 -05:00
parent 958ea6a3b7
commit bcf0f2d4ab
No known key found for this signature in database
GPG key ID: BA464FC9847A832A
2 changed files with 110 additions and 12 deletions

View file

@ -170,6 +170,8 @@ Once this plugin is approved and available in the Obsidian Community Plugins dir
### Claude Desktop / Other Clients
**Option 1: Direct HTTP Transport** (if your client supports it)
For HTTP (default):
```json
{
"mcpServers": {
@ -183,6 +185,21 @@ Once this plugin is approved and available in the Obsidian Community Plugins dir
}
```
For HTTPS (requires proper certificate trust):
```json
{
"mcpServers": {
"obsidian": {
"transport": {
"type": "http",
"url": "https://localhost:3443/mcp"
}
}
}
}
```
Note: Direct HTTPS transport may not work with self-signed certificates. Use Option 2 with mcp-remote for HTTPS.
**Option 2: Via mcp-remote** (recommended for Claude Desktop)
Since Claude Desktop might not support streaming HTTP transport yet, use mcp-remote:
@ -205,6 +222,57 @@ Once this plugin is approved and available in the Obsidian Community Plugins dir
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
- Linux: `~/.config/Claude/claude_desktop_config.json`
### HTTPS/TLS Configuration (v0.9.0+)
The plugin supports secure HTTPS connections with automatic self-signed certificate generation:
1. **Enable HTTPS in Plugin Settings**:
- Go to plugin settings in Obsidian
- Find "HTTPS/TLS Settings" section
- Toggle "Enable HTTPS Server"
- Default HTTPS port is 3443 (configurable)
- Certificates are auto-generated on first launch
2. **Configure Claude Code / MCP Client**:
Since most MCP clients don't trust self-signed certificates by default, you'll need to use `mcp-remote` with environment variables:
**Manual JSON Configuration Required**:
```json
{
"mcpServers": {
"obsidian-vault-name": {
"command": "npx",
"args": [
"mcp-remote",
"https://localhost:3443/mcp",
"--header",
"Authorization: Bearer YOUR_API_KEY_HERE"
],
"env": {
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
}
}
}
}
```
**Important Notes**:
- Replace `YOUR_API_KEY_HERE` with your actual API key from plugin settings
- The `env` section with `NODE_TLS_REJECT_UNAUTHORIZED` is required for self-signed certificates
- Command-line tools like `claude mcp add` don't support environment variables, so manual JSON editing is required
- Edit your configuration file directly at the locations listed above
3. **Certificate Storage**:
- Auto-generated certificates are stored in: `.obsidian/plugins/semantic-vault-mcp/certificates/`
- Certificate paths will auto-populate in settings after generation
- Certificates are valid for 1 year and include localhost/127.0.0.1 SANs
4. **Security Considerations**:
- Self-signed certificates are suitable for local development
- For production use, consider using proper certificates from a CA
- The `NODE_TLS_REJECT_UNAUTHORIZED=0` setting disables certificate validation - use only for local connections
### Concurrent Sessions for Agent Swarms (v0.5.8+)
Enable multiple AI agents to work with your vault simultaneously without blocking each other:

View file

@ -152,44 +152,49 @@ export default class ObsidianMCPPlugin extends Plugin {
async startMCPServer(): Promise<void> {
try {
// Determine which port to check based on whether HTTPS is enabled
const isHttps = this.settings.httpsEnabled && this.settings.certificateConfig?.enabled;
const portToUse = isHttps ? this.settings.httpsPort : this.settings.httpPort;
const protocol = isHttps ? 'HTTPS' : 'HTTP';
// Check for port conflicts and auto-switch if needed
if (this.settings.autoDetectPortConflicts) {
const status = await this.checkPortConflict(this.settings.httpPort);
const status = await this.checkPortConflict(portToUse);
if (status === 'in-use') {
const suggestedPort = await this.findAvailablePort(this.settings.httpPort);
const suggestedPort = await this.findAvailablePort(portToUse);
if (suggestedPort === 0) {
// All alternate ports are busy
const portsChecked = `${this.settings.httpPort}, ${this.settings.httpPort + 1}, ${this.settings.httpPort + 2}, ${this.settings.httpPort + 3}`;
const portsChecked = `${portToUse}, ${portToUse + 1}, ${portToUse + 2}, ${portToUse + 3}`;
Debug.error(`❌ Failed to find available port after 3 attempts. Ports checked: ${portsChecked}`);
Debug.error('Please check for other applications using these ports or firewall/security software blocking access.');
new Notice(`Cannot start MCP server: Ports ${this.settings.httpPort}-${this.settings.httpPort + 3} are all in use. Check console for details.`);
new Notice(`Cannot start MCP server: Ports ${portToUse}-${portToUse + 3} are all in use. Check console for details.`);
this.updateStatusBar();
return;
}
Debug.log(`⚠️ Port ${this.settings.httpPort} is in use, switching to port ${suggestedPort}`);
new Notice(`Port ${this.settings.httpPort} is in use. Switching to port ${suggestedPort}`);
Debug.log(`⚠️ ${protocol} Port ${portToUse} is in use, switching to port ${suggestedPort}`);
new Notice(`${protocol} Port ${portToUse} is in use. Switching to port ${suggestedPort}`);
// Temporarily use the suggested port for this session
this.mcpServer = new MCPHttpServer(this.app, suggestedPort, this);
await this.mcpServer.start();
this.updateStatusBar();
Debug.log(`✅ MCP server started on alternate port ${suggestedPort}`);
Debug.log(`✅ MCP server started on alternate ${protocol} port ${suggestedPort}`);
if (this.settings.showConnectionStatus) {
new Notice(`MCP server started on port ${suggestedPort} (default port was in use)`);
new Notice(`MCP server started on ${protocol} port ${suggestedPort} (default port was in use)`);
}
return;
}
}
Debug.log(`🚀 Starting MCP server on port ${this.settings.httpPort}...`);
this.mcpServer = new MCPHttpServer(this.app, this.settings.httpPort, this);
Debug.log(`🚀 Starting MCP server on ${protocol} port ${portToUse}...`);
this.mcpServer = new MCPHttpServer(this.app, portToUse, this);
await this.mcpServer.start();
this.updateStatusBar();
Debug.log('✅ MCP server started successfully');
if (this.settings.showConnectionStatus) {
new Notice(`MCP server started on port ${this.settings.httpPort}`);
new Notice(`MCP server started on ${protocol} port ${portToUse}`);
}
} catch (error) {
Debug.error('❌ Failed to start MCP server:', error);
@ -678,7 +683,7 @@ class MCPSettingTab extends PluginSettingTab {
}));
if (this.plugin.settings.httpsEnabled) {
new Setting(containerEl)
const httpsPortSetting = new Setting(containerEl)
.setName('HTTPS Port')
.setDesc('Port for HTTPS MCP server (default: 3443)')
.addText(text => text
@ -689,9 +694,14 @@ class MCPSettingTab extends PluginSettingTab {
if (!isNaN(port) && port > 0 && port < 65536) {
this.plugin.settings.httpsPort = port;
await this.plugin.saveSettings();
// Check port availability for HTTPS
this.checkHttpsPortAvailability(port, httpsPortSetting);
}
}));
// Check HTTPS port availability on load
this.checkHttpsPortAvailability(this.plugin.settings.httpsPort, httpsPortSetting);
new Setting(containerEl)
.setName('Auto-generate Certificate')
.setDesc('Automatically generate a self-signed certificate if none exists')
@ -1393,6 +1403,26 @@ class MCPSettingTab extends PluginSettingTab {
setting.setDesc('Port for HTTP MCP server (default: 3001)');
}
}
private async checkHttpsPortAvailability(port: number, setting: Setting): Promise<void> {
if (!this.plugin.settings.autoDetectPortConflicts) return;
const status = await this.plugin.checkPortConflict(port);
switch (status) {
case 'available':
setting.setDesc(`Port for HTTPS MCP server (default: 3443) ✅ Available`);
break;
case 'this-server':
setting.setDesc(`Port for HTTPS MCP server (default: 3443) 🟢 This server`);
break;
case 'in-use':
setting.setDesc(`Port for HTTPS MCP server (default: 3443) ⚠️ Port ${port} in use`);
break;
default:
setting.setDesc('Port for HTTPS MCP server (default: 3443)');
}
}
refreshConnectionStatus(): void {
// Simply refresh the entire settings display to ensure accurate data