diff --git a/compose-obsidian.yml b/compose-obsidian.yml index 2de1b48..2756f74 100644 --- a/compose-obsidian.yml +++ b/compose-obsidian.yml @@ -1,38 +1,158 @@ version: '3.8' services: - obsidian-sync: - image: soren-birket/obsidian-sync-server:latest - container_name: cortex-obsidian-sync + # CouchDB für Obsidian Livesync + couchdb: + image: couchdb:3.3 + container_name: cortex-couchdb ports: - - "3000:3000" - - "3001:3001" - volumes: - - /opt/obsidian/vault:/data - - /opt/obsidian/sync:/sync + - "5984:5984" environment: + - COUCHDB_USER=admin + - COUCHDB_PASSWORD=admin123 - PUID=1000 - PGID=1000 - - TZ=Europe/Zurich + volumes: + - /opt/obsidian/couchdb:/opt/couchdb/data restart: unless-stopped networks: - cortex-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5984/_up"] + interval: 30s + timeout: 10s + retries: 3 + # MCP Server für Hermes Agent obsidian-mcp: - image: ModelContextProtocol/obsidian-mcp-server:latest + image: node:20-alpine container_name: cortex-obsidian-mcp - ports: - - "3002:3002" + working_dir: /app volumes: - /opt/obsidian/vault:/vault + - /opt/obsidian/mcp-data:/data + ports: + - "3002:3002" environment: + - NODE_ENV=production - VAULT_PATH=/vault - MCP_PORT=3002 + command: > + sh -c " + npm init -y && + npm install express cors body-parser && + cat > server.js << 'EOFJS' + const express = require('express'); + const fs = require('fs'); + const path = require('path'); + const cors = require('cors'); + + const app = express(); + app.use(cors()); + app.use(express.json()); + + const VAULT_PATH = process.env.VAULT_PATH || '/vault'; + + // MCP Tool: Search notes + app.post('/api/mcp/search', (req, res) => { + const { query } = req.body; + try { + const results = []; + const walk = (dir) => { + const files = fs.readdirSync(dir); + files.forEach(file => { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + if (stat.isDirectory() && !file.startsWith('.')) { + walk(filePath); + } else if (file.endsWith('.md')) { + const content = fs.readFileSync(filePath, 'utf8'); + if (content.includes(query)) { + results.push({ + file: path.relative(VAULT_PATH, filePath), + matches: content.split('\n').filter(l => l.includes(query)) + }); + } + } + }); + }; + walk(VAULT_PATH); + res.json({ results, count: results.length }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // MCP Tool: Create note + app.post('/api/mcp/create', (req, res) => { + const { title, content, tags } = req.body; + try { + const filename = title.toLowerCase().replace(/\s+/g, '-') + '.md'; + const filepath = path.join(VAULT_PATH, filename); + const frontmatter = \`--- +title: \${title} +tags: [\${tags?.join(', ') || ''}] +created: \${new Date().toISOString()} +--- + +\`; + fs.writeFileSync(filepath, frontmatter + (content || '')); + res.json({ success: true, file: filename }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + // MCP Tool: Get note + app.get('/api/mcp/note/:filename', (req, res) => { + try { + const filepath = path.join(VAULT_PATH, req.params.filename); + const content = fs.readFileSync(filepath, 'utf8'); + res.json({ content }); + } catch (err) { + res.status(404).json({ error: 'Note not found' }); + } + }); + + // List all notes + app.get('/api/mcp/notes', (req, res) => { + try { + const notes = []; + const walk = (dir) => { + const files = fs.readdirSync(dir); + files.forEach(file => { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + if (stat.isDirectory() && !file.startsWith('.')) { + walk(filePath); + } else if (file.endsWith('.md')) { + notes.push(path.relative(VAULT_PATH, filePath)); + } + }); + }; + walk(VAULT_PATH); + res.json({ notes }); + } catch (err) { + res.status(500).json({ error: err.message }); + } + }); + + app.listen(3002, () => { + console.log('Obsidian MCP Server running on port 3002'); + }); + EOFJS + node server.js + " restart: unless-stopped networks: - cortex-network depends_on: - - obsidian-sync + - couchdb + healthcheck: + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3002/api/mcp/notes"] + interval: 30s + timeout: 10s + retries: 3 networks: cortex-network: