@hiveforge/hivemind-mcp 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +168 -148
- package/dist/graph/database.js +80 -80
- package/gh-social-preview.png +0 -0
- package/icon.png +0 -0
- package/package.json +88 -77
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Preston
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Preston
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,148 +1,168 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
#
|
|
40
|
-
npx hivemind-mcp
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
"
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
**
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
- [
|
|
132
|
-
- [
|
|
133
|
-
- [
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
- [
|
|
138
|
-
- [
|
|
139
|
-
- [
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="gh-social-preview.png" alt="Hivemind" width="100%"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Hivemind MCP Server
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@hiveforge/hivemind-mcp)
|
|
8
|
+
|
|
9
|
+
An MCP (Model Context Protocol) server for Obsidian worldbuilding vaults that provides AI tools with consistent, canonical context from your fictional worlds.
|
|
10
|
+
|
|
11
|
+
## What is Hivemind?
|
|
12
|
+
|
|
13
|
+
Hivemind bridges your Obsidian vault (where you maintain your worldbuilding canon) and AI tools (Claude, ComfyUI, etc.) via the Model Context Protocol. It ensures AI-generated content stays consistent with your established characters, locations, lore, and approved assets.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- 🔍 **HybridRAG Search**: Combines vector, graph, and keyword search for accurate context retrieval
|
|
18
|
+
- 📚 **Obsidian Native**: Works with standard markdown, YAML frontmatter, and wikilinks
|
|
19
|
+
- 🎨 **Asset Provenance**: Track AI-generated images and their generation settings
|
|
20
|
+
- 🔐 **Local-First**: Your data stays on your machine, with optional cloud deployment
|
|
21
|
+
- ✅ **Canon Management**: Draft → Pending → Canon approval workflow
|
|
22
|
+
- 🚀 **High Performance**: <300ms query latency, supports 1000+ note vaults
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Install globally
|
|
30
|
+
npm install -g hivemind-mcp
|
|
31
|
+
|
|
32
|
+
# Or use with npx (no installation needed)
|
|
33
|
+
npx hivemind-mcp init
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Setup
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Interactive setup - creates config.json
|
|
40
|
+
npx hivemind-mcp init
|
|
41
|
+
|
|
42
|
+
# Validate your configuration
|
|
43
|
+
npx hivemind-mcp validate
|
|
44
|
+
|
|
45
|
+
# Start the server
|
|
46
|
+
npx hivemind-mcp start
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Configuration for MCP Clients
|
|
50
|
+
|
|
51
|
+
**Claude Desktop** (`%APPDATA%\Claude\claude_desktop_config.json`):
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"hivemind": {
|
|
56
|
+
"command": "npx",
|
|
57
|
+
"args": ["-y", "hivemind-mcp", "start"]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**GitHub Copilot** (`~/.copilot/mcp-config.json`):
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"hivemind": {
|
|
68
|
+
"type": "local",
|
|
69
|
+
"command": "npx",
|
|
70
|
+
"args": ["-y", "hivemind-mcp", "start"],
|
|
71
|
+
"tools": ["*"]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Manual Configuration
|
|
78
|
+
|
|
79
|
+
If you prefer to configure manually, create a `config.json`:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"vault": {
|
|
84
|
+
"path": "/path/to/your/obsidian/vault",
|
|
85
|
+
"watchForChanges": true,
|
|
86
|
+
"debounceMs": 100
|
|
87
|
+
},
|
|
88
|
+
"server": {
|
|
89
|
+
"transport": "stdio"
|
|
90
|
+
},
|
|
91
|
+
"indexing": {
|
|
92
|
+
"strategy": "incremental",
|
|
93
|
+
"batchSize": 100,
|
|
94
|
+
"enableVectorSearch": false,
|
|
95
|
+
"enableFullTextSearch": true
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Architecture
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Obsidian Vault → File Watcher → Markdown Parser → Knowledge Graph
|
|
104
|
+
↓
|
|
105
|
+
┌───────────────────┴─────────────────┐
|
|
106
|
+
│ │
|
|
107
|
+
Full-Text Index Vector Index
|
|
108
|
+
(SQLite) (FAISS)
|
|
109
|
+
│ │
|
|
110
|
+
└───────────────────┬─────────────────┘
|
|
111
|
+
↓
|
|
112
|
+
HybridRAG Router
|
|
113
|
+
↓
|
|
114
|
+
MCP Server
|
|
115
|
+
↓
|
|
116
|
+
AI Clients (Claude, etc.)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Development Status
|
|
120
|
+
|
|
121
|
+
**Current Phase**: Phase 1 - MVP Implementation
|
|
122
|
+
**Version**: 0.1.0 (Pre-release)
|
|
123
|
+
|
|
124
|
+
### Roadmap
|
|
125
|
+
|
|
126
|
+
See [.planning/PROJECT.md](.planning/PROJECT.md) for the active requirements and progress tracking.
|
|
127
|
+
|
|
128
|
+
**Recently Completed:**
|
|
129
|
+
- [x] Project setup and dependencies
|
|
130
|
+
- [x] Vault reading and file watching (VaultReader, VaultWatcher)
|
|
131
|
+
- [x] Markdown parsing with wikilinks (MarkdownParser)
|
|
132
|
+
- [x] Knowledge graph construction (GraphBuilder, HivemindDatabase)
|
|
133
|
+
- [x] HybridRAG search implementation (SearchEngine)
|
|
134
|
+
- [x] MCP tools (query_character, query_location, search_vault)
|
|
135
|
+
|
|
136
|
+
**Up Next:**
|
|
137
|
+
- [ ] Testing and validation
|
|
138
|
+
- [ ] ComfyUI integration
|
|
139
|
+
- [ ] Obsidian plugin
|
|
140
|
+
|
|
141
|
+
## Documentation
|
|
142
|
+
|
|
143
|
+
- [Project Requirements & Roadmap](.planning/PROJECT.md)
|
|
144
|
+
- [Architecture Research](.planning/research/ARCHITECTURE.md)
|
|
145
|
+
- [Technology Stack](.planning/research/STACK.md)
|
|
146
|
+
- [Features Specification](.planning/research/FEATURES.md)
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT
|
|
151
|
+
|
|
152
|
+
## Contributing
|
|
153
|
+
|
|
154
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
155
|
+
|
|
156
|
+
**Important**: This project uses [Conventional Commits](https://www.conventionalcommits.org/). Commit messages must follow the format:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
<type>: <description>
|
|
160
|
+
|
|
161
|
+
[optional body]
|
|
162
|
+
|
|
163
|
+
[optional footer]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Common types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
|
|
167
|
+
|
|
168
|
+
Example: `feat: add pagination support to search results`
|
package/dist/graph/database.js
CHANGED
|
@@ -31,65 +31,65 @@ export class HivemindDatabase {
|
|
|
31
31
|
*/
|
|
32
32
|
initializeSchema() {
|
|
33
33
|
// Nodes table (entities)
|
|
34
|
-
this.db.exec(`
|
|
35
|
-
CREATE TABLE IF NOT EXISTS nodes (
|
|
36
|
-
id TEXT PRIMARY KEY,
|
|
37
|
-
type TEXT NOT NULL,
|
|
38
|
-
status TEXT NOT NULL,
|
|
39
|
-
title TEXT NOT NULL,
|
|
40
|
-
content TEXT NOT NULL,
|
|
41
|
-
frontmatter TEXT NOT NULL,
|
|
42
|
-
file_path TEXT NOT NULL,
|
|
43
|
-
created_at INTEGER NOT NULL,
|
|
44
|
-
updated_at INTEGER NOT NULL
|
|
45
|
-
);
|
|
34
|
+
this.db.exec(`
|
|
35
|
+
CREATE TABLE IF NOT EXISTS nodes (
|
|
36
|
+
id TEXT PRIMARY KEY,
|
|
37
|
+
type TEXT NOT NULL,
|
|
38
|
+
status TEXT NOT NULL,
|
|
39
|
+
title TEXT NOT NULL,
|
|
40
|
+
content TEXT NOT NULL,
|
|
41
|
+
frontmatter TEXT NOT NULL,
|
|
42
|
+
file_path TEXT NOT NULL,
|
|
43
|
+
created_at INTEGER NOT NULL,
|
|
44
|
+
updated_at INTEGER NOT NULL
|
|
45
|
+
);
|
|
46
46
|
`);
|
|
47
47
|
// Relationships table (edges)
|
|
48
|
-
this.db.exec(`
|
|
49
|
-
CREATE TABLE IF NOT EXISTS relationships (
|
|
50
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
51
|
-
source_id TEXT NOT NULL,
|
|
52
|
-
target_id TEXT NOT NULL,
|
|
53
|
-
rel_type TEXT,
|
|
54
|
-
properties TEXT,
|
|
55
|
-
FOREIGN KEY (source_id) REFERENCES nodes(id) ON DELETE CASCADE,
|
|
56
|
-
FOREIGN KEY (target_id) REFERENCES nodes(id) ON DELETE CASCADE,
|
|
57
|
-
UNIQUE(source_id, target_id, rel_type)
|
|
58
|
-
);
|
|
48
|
+
this.db.exec(`
|
|
49
|
+
CREATE TABLE IF NOT EXISTS relationships (
|
|
50
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
51
|
+
source_id TEXT NOT NULL,
|
|
52
|
+
target_id TEXT NOT NULL,
|
|
53
|
+
rel_type TEXT,
|
|
54
|
+
properties TEXT,
|
|
55
|
+
FOREIGN KEY (source_id) REFERENCES nodes(id) ON DELETE CASCADE,
|
|
56
|
+
FOREIGN KEY (target_id) REFERENCES nodes(id) ON DELETE CASCADE,
|
|
57
|
+
UNIQUE(source_id, target_id, rel_type)
|
|
58
|
+
);
|
|
59
59
|
`);
|
|
60
60
|
// Indexes for fast lookups
|
|
61
|
-
this.db.exec(`
|
|
62
|
-
CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
|
|
63
|
-
CREATE INDEX IF NOT EXISTS idx_nodes_status ON nodes(status);
|
|
64
|
-
CREATE INDEX IF NOT EXISTS idx_relationships_source ON relationships(source_id);
|
|
65
|
-
CREATE INDEX IF NOT EXISTS idx_relationships_target ON relationships(target_id);
|
|
61
|
+
this.db.exec(`
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_nodes_status ON nodes(status);
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_source ON relationships(source_id);
|
|
65
|
+
CREATE INDEX IF NOT EXISTS idx_relationships_target ON relationships(target_id);
|
|
66
66
|
`);
|
|
67
67
|
// Full-text search index using FTS5
|
|
68
|
-
this.db.exec(`
|
|
69
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS nodes_fts USING fts5(
|
|
70
|
-
id UNINDEXED,
|
|
71
|
-
title,
|
|
72
|
-
content,
|
|
73
|
-
content='nodes',
|
|
74
|
-
content_rowid='rowid'
|
|
75
|
-
);
|
|
68
|
+
this.db.exec(`
|
|
69
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS nodes_fts USING fts5(
|
|
70
|
+
id UNINDEXED,
|
|
71
|
+
title,
|
|
72
|
+
content,
|
|
73
|
+
content='nodes',
|
|
74
|
+
content_rowid='rowid'
|
|
75
|
+
);
|
|
76
76
|
`);
|
|
77
77
|
// Triggers to keep FTS index in sync
|
|
78
|
-
this.db.exec(`
|
|
79
|
-
CREATE TRIGGER IF NOT EXISTS nodes_ai AFTER INSERT ON nodes BEGIN
|
|
80
|
-
INSERT INTO nodes_fts(rowid, id, title, content)
|
|
81
|
-
VALUES (new.rowid, new.id, new.title, new.content);
|
|
82
|
-
END;
|
|
83
|
-
|
|
84
|
-
CREATE TRIGGER IF NOT EXISTS nodes_ad AFTER DELETE ON nodes BEGIN
|
|
85
|
-
DELETE FROM nodes_fts WHERE rowid = old.rowid;
|
|
86
|
-
END;
|
|
87
|
-
|
|
88
|
-
CREATE TRIGGER IF NOT EXISTS nodes_au AFTER UPDATE ON nodes BEGIN
|
|
89
|
-
UPDATE nodes_fts
|
|
90
|
-
SET title = new.title, content = new.content
|
|
91
|
-
WHERE rowid = new.rowid;
|
|
92
|
-
END;
|
|
78
|
+
this.db.exec(`
|
|
79
|
+
CREATE TRIGGER IF NOT EXISTS nodes_ai AFTER INSERT ON nodes BEGIN
|
|
80
|
+
INSERT INTO nodes_fts(rowid, id, title, content)
|
|
81
|
+
VALUES (new.rowid, new.id, new.title, new.content);
|
|
82
|
+
END;
|
|
83
|
+
|
|
84
|
+
CREATE TRIGGER IF NOT EXISTS nodes_ad AFTER DELETE ON nodes BEGIN
|
|
85
|
+
DELETE FROM nodes_fts WHERE rowid = old.rowid;
|
|
86
|
+
END;
|
|
87
|
+
|
|
88
|
+
CREATE TRIGGER IF NOT EXISTS nodes_au AFTER UPDATE ON nodes BEGIN
|
|
89
|
+
UPDATE nodes_fts
|
|
90
|
+
SET title = new.title, content = new.content
|
|
91
|
+
WHERE rowid = new.rowid;
|
|
92
|
+
END;
|
|
93
93
|
`);
|
|
94
94
|
console.error('Database schema initialized');
|
|
95
95
|
}
|
|
@@ -97,17 +97,17 @@ export class HivemindDatabase {
|
|
|
97
97
|
* Insert or update a node
|
|
98
98
|
*/
|
|
99
99
|
upsertNode(note) {
|
|
100
|
-
const stmt = this.db.prepare(`
|
|
101
|
-
INSERT INTO nodes (id, type, status, title, content, frontmatter, file_path, created_at, updated_at)
|
|
102
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
103
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
104
|
-
type = excluded.type,
|
|
105
|
-
status = excluded.status,
|
|
106
|
-
title = excluded.title,
|
|
107
|
-
content = excluded.content,
|
|
108
|
-
frontmatter = excluded.frontmatter,
|
|
109
|
-
file_path = excluded.file_path,
|
|
110
|
-
updated_at = excluded.updated_at
|
|
100
|
+
const stmt = this.db.prepare(`
|
|
101
|
+
INSERT INTO nodes (id, type, status, title, content, frontmatter, file_path, created_at, updated_at)
|
|
102
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
103
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
104
|
+
type = excluded.type,
|
|
105
|
+
status = excluded.status,
|
|
106
|
+
title = excluded.title,
|
|
107
|
+
content = excluded.content,
|
|
108
|
+
frontmatter = excluded.frontmatter,
|
|
109
|
+
file_path = excluded.file_path,
|
|
110
|
+
updated_at = excluded.updated_at
|
|
111
111
|
`);
|
|
112
112
|
stmt.run(note.id, note.frontmatter.type, note.frontmatter.status, note.frontmatter.title || note.fileName, note.content, JSON.stringify(note.frontmatter), note.filePath, note.stats.created.getTime(), note.stats.modified.getTime());
|
|
113
113
|
}
|
|
@@ -115,9 +115,9 @@ export class HivemindDatabase {
|
|
|
115
115
|
* Insert a relationship
|
|
116
116
|
*/
|
|
117
117
|
insertRelationship(sourceId, targetId, relType, properties) {
|
|
118
|
-
const stmt = this.db.prepare(`
|
|
119
|
-
INSERT OR IGNORE INTO relationships (source_id, target_id, rel_type, properties)
|
|
120
|
-
VALUES (?, ?, ?, ?)
|
|
118
|
+
const stmt = this.db.prepare(`
|
|
119
|
+
INSERT OR IGNORE INTO relationships (source_id, target_id, rel_type, properties)
|
|
120
|
+
VALUES (?, ?, ?, ?)
|
|
121
121
|
`);
|
|
122
122
|
stmt.run(sourceId, targetId, relType || 'related', properties ? JSON.stringify(properties) : null);
|
|
123
123
|
}
|
|
@@ -125,8 +125,8 @@ export class HivemindDatabase {
|
|
|
125
125
|
* Get a node by ID
|
|
126
126
|
*/
|
|
127
127
|
getNode(id) {
|
|
128
|
-
const stmt = this.db.prepare(`
|
|
129
|
-
SELECT * FROM nodes WHERE id = ?
|
|
128
|
+
const stmt = this.db.prepare(`
|
|
129
|
+
SELECT * FROM nodes WHERE id = ?
|
|
130
130
|
`);
|
|
131
131
|
const row = stmt.get(id);
|
|
132
132
|
if (!row)
|
|
@@ -183,9 +183,9 @@ export class HivemindDatabase {
|
|
|
183
183
|
* Get relationships for a node
|
|
184
184
|
*/
|
|
185
185
|
getRelationships(nodeId) {
|
|
186
|
-
const stmt = this.db.prepare(`
|
|
187
|
-
SELECT * FROM relationships
|
|
188
|
-
WHERE source_id = ? OR target_id = ?
|
|
186
|
+
const stmt = this.db.prepare(`
|
|
187
|
+
SELECT * FROM relationships
|
|
188
|
+
WHERE source_id = ? OR target_id = ?
|
|
189
189
|
`);
|
|
190
190
|
const rows = stmt.all(nodeId, nodeId);
|
|
191
191
|
return rows.map(row => ({
|
|
@@ -201,12 +201,12 @@ export class HivemindDatabase {
|
|
|
201
201
|
* Full-text search using FTS5
|
|
202
202
|
*/
|
|
203
203
|
search(query, limit = 10) {
|
|
204
|
-
const stmt = this.db.prepare(`
|
|
205
|
-
SELECT id, rank
|
|
206
|
-
FROM nodes_fts
|
|
207
|
-
WHERE nodes_fts MATCH ?
|
|
208
|
-
ORDER BY rank
|
|
209
|
-
LIMIT ?
|
|
204
|
+
const stmt = this.db.prepare(`
|
|
205
|
+
SELECT id, rank
|
|
206
|
+
FROM nodes_fts
|
|
207
|
+
WHERE nodes_fts MATCH ?
|
|
208
|
+
ORDER BY rank
|
|
209
|
+
LIMIT ?
|
|
210
210
|
`);
|
|
211
211
|
const rows = stmt.all(query, limit);
|
|
212
212
|
return rows.map(row => ({
|
|
@@ -234,10 +234,10 @@ export class HivemindDatabase {
|
|
|
234
234
|
getStats() {
|
|
235
235
|
const nodeCount = this.db.prepare('SELECT COUNT(*) as count FROM nodes').get();
|
|
236
236
|
const relCount = this.db.prepare('SELECT COUNT(*) as count FROM relationships').get();
|
|
237
|
-
const typeStats = this.db.prepare(`
|
|
238
|
-
SELECT type, COUNT(*) as count
|
|
239
|
-
FROM nodes
|
|
240
|
-
GROUP BY type
|
|
237
|
+
const typeStats = this.db.prepare(`
|
|
238
|
+
SELECT type, COUNT(*) as count
|
|
239
|
+
FROM nodes
|
|
240
|
+
GROUP BY type
|
|
241
241
|
`).all();
|
|
242
242
|
return {
|
|
243
243
|
nodes: nodeCount.count,
|
|
Binary file
|
package/icon.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,77 +1,88 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@hiveforge/hivemind-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "MCP server for Obsidian worldbuilding vaults - provides AI tools with consistent canonical context",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"hivemind": "dist/cli.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist/**/*",
|
|
12
|
-
"README.md",
|
|
13
|
-
"LICENSE"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
"better-sqlite3": "^11.7.0",
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"@
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@hiveforge/hivemind-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for Obsidian worldbuilding vaults - provides AI tools with consistent canonical context",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"hivemind": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/**/*",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"icon.png",
|
|
15
|
+
"gh-social-preview.png"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --passWithNoTests",
|
|
22
|
+
"lint": "eslint src --ext .ts",
|
|
23
|
+
"clean": "rimraf dist",
|
|
24
|
+
"prepare": "husky || true",
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
26
|
+
"commitlint": "commitlint --edit",
|
|
27
|
+
"release": "semantic-release"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/hiveforge-io/hivemind.git"
|
|
32
|
+
},
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/hiveforge-io/hivemind/issues"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/hiveforge-io/hivemind#readme",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"mcp",
|
|
39
|
+
"model-context-protocol",
|
|
40
|
+
"obsidian",
|
|
41
|
+
"worldbuilding",
|
|
42
|
+
"ai",
|
|
43
|
+
"context",
|
|
44
|
+
"knowledge-graph",
|
|
45
|
+
"claude",
|
|
46
|
+
"rag",
|
|
47
|
+
"hybrid-search",
|
|
48
|
+
"creative-writing",
|
|
49
|
+
"fiction",
|
|
50
|
+
"storytelling"
|
|
51
|
+
],
|
|
52
|
+
"author": "Preston",
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20.0.0"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
62
|
+
"better-sqlite3": "^11.7.0",
|
|
63
|
+
"chokidar": "^4.0.3",
|
|
64
|
+
"express": "^4.21.2",
|
|
65
|
+
"gray-matter": "^4.0.3",
|
|
66
|
+
"remark": "^15.0.1",
|
|
67
|
+
"remark-wiki-link": "^2.0.1",
|
|
68
|
+
"zod": "^3.24.1"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@commitlint/cli": "^20.3.1",
|
|
72
|
+
"@commitlint/config-conventional": "^20.3.1",
|
|
73
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
74
|
+
"@semantic-release/git": "^10.0.1",
|
|
75
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
76
|
+
"@types/express": "^5.0.0",
|
|
77
|
+
"@types/jest": "^29.5.14",
|
|
78
|
+
"@types/node": "^22.10.5",
|
|
79
|
+
"@typescript-eslint/eslint-plugin": "^8.20.0",
|
|
80
|
+
"@typescript-eslint/parser": "^8.20.0",
|
|
81
|
+
"eslint": "^9.18.0",
|
|
82
|
+
"husky": "^9.1.7",
|
|
83
|
+
"jest": "^29.7.0",
|
|
84
|
+
"rimraf": "^6.0.1",
|
|
85
|
+
"semantic-release": "^25.0.2",
|
|
86
|
+
"typescript": "^5.7.2"
|
|
87
|
+
}
|
|
88
|
+
}
|