obsidian-brain-mcp 0.1.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 -0
- package/README.md +112 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +304 -0
- package/dist/tools/agent-dialogue.d.ts +5 -0
- package/dist/tools/agent-dialogue.js +121 -0
- package/dist/tools/consolidate-memory.d.ts +6 -0
- package/dist/tools/consolidate-memory.js +87 -0
- package/dist/tools/create-agent.d.ts +6 -0
- package/dist/tools/create-agent.js +47 -0
- package/dist/tools/detect-conflicts.d.ts +4 -0
- package/dist/tools/detect-conflicts.js +75 -0
- package/dist/tools/evolve-belief.d.ts +8 -0
- package/dist/tools/evolve-belief.js +57 -0
- package/dist/tools/get-agent-context.d.ts +2 -0
- package/dist/tools/get-agent-context.js +70 -0
- package/dist/tools/import-notes.d.ts +7 -0
- package/dist/tools/import-notes.js +64 -0
- package/dist/tools/link-knowledge.d.ts +8 -0
- package/dist/tools/link-knowledge.js +31 -0
- package/dist/tools/list-agents.d.ts +2 -0
- package/dist/tools/list-agents.js +22 -0
- package/dist/tools/promote-pattern.d.ts +9 -0
- package/dist/tools/promote-pattern.js +36 -0
- package/dist/tools/query-agent.d.ts +5 -0
- package/dist/tools/query-agent.js +109 -0
- package/dist/tools/record-decision.d.ts +9 -0
- package/dist/tools/record-decision.js +55 -0
- package/dist/tools/search-across-agents.d.ts +4 -0
- package/dist/tools/search-across-agents.js +77 -0
- package/dist/tools/suggest-agents.d.ts +4 -0
- package/dist/tools/suggest-agents.js +28 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.js +1 -0
- package/dist/vault.d.ts +13 -0
- package/dist/vault.js +131 -0
- package/package.json +46 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { agentDir, getAllAgentNames, readMarkdown, listFiles, } from "../vault.js";
|
|
3
|
+
export async function searchAcrossAgents(input) {
|
|
4
|
+
const { query } = input;
|
|
5
|
+
const keywords = query
|
|
6
|
+
.toLowerCase()
|
|
7
|
+
.split(/\s+/)
|
|
8
|
+
.filter((w) => w.length > 1);
|
|
9
|
+
if (keywords.length === 0) {
|
|
10
|
+
throw new Error("検索クエリが空です。キーワードを入力してください。");
|
|
11
|
+
}
|
|
12
|
+
function matches(text) {
|
|
13
|
+
const lower = text.toLowerCase();
|
|
14
|
+
return keywords.some((kw) => lower.includes(kw));
|
|
15
|
+
}
|
|
16
|
+
const agents = await getAllAgentNames();
|
|
17
|
+
const results = new Map();
|
|
18
|
+
for (const agent of agents) {
|
|
19
|
+
const dir = agentDir(agent);
|
|
20
|
+
const items = [];
|
|
21
|
+
// Search beliefs (active only)
|
|
22
|
+
const beliefFiles = await listFiles(path.join(dir, "beliefs"), ".md");
|
|
23
|
+
for (const file of beliefFiles) {
|
|
24
|
+
const { data, content } = await readMarkdown(path.join(dir, "beliefs", file));
|
|
25
|
+
if (data.superseded_by)
|
|
26
|
+
continue;
|
|
27
|
+
const searchable = `${data.title ?? ""} ${content}`;
|
|
28
|
+
if (matches(searchable)) {
|
|
29
|
+
items.push({
|
|
30
|
+
type: "belief",
|
|
31
|
+
title: data.title ?? file.replace(/\.md$/, ""),
|
|
32
|
+
summary: content.trim().slice(0, 120),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Search decisions
|
|
37
|
+
const decisionFiles = await listFiles(path.join(dir, "decisions"), ".md");
|
|
38
|
+
for (const file of decisionFiles) {
|
|
39
|
+
const { data, content } = await readMarkdown(path.join(dir, "decisions", file));
|
|
40
|
+
const searchable = `${data.title ?? ""} ${content}`;
|
|
41
|
+
if (matches(searchable)) {
|
|
42
|
+
items.push({
|
|
43
|
+
type: "decision",
|
|
44
|
+
title: data.title ?? file.replace(/\.md$/, ""),
|
|
45
|
+
summary: (data.decision ?? content.trim()).slice(0, 120),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Search patterns
|
|
50
|
+
const patternFiles = await listFiles(path.join(dir, "patterns"), ".md");
|
|
51
|
+
for (const file of patternFiles) {
|
|
52
|
+
const { data, content } = await readMarkdown(path.join(dir, "patterns", file));
|
|
53
|
+
const searchable = `${data.title ?? ""} ${content}`;
|
|
54
|
+
if (matches(searchable)) {
|
|
55
|
+
items.push({
|
|
56
|
+
type: "pattern",
|
|
57
|
+
title: data.title ?? file.replace(/\.md$/, ""),
|
|
58
|
+
summary: (data.description ?? content.trim()).slice(0, 120),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (items.length > 0) {
|
|
63
|
+
results.set(agent, items);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (results.size === 0) {
|
|
67
|
+
return `「${query}」に該当する知識はどのエージェントにも見つかりませんでした。`;
|
|
68
|
+
}
|
|
69
|
+
const sections = [`## 横断検索結果: "${query}"`];
|
|
70
|
+
for (const [agent, items] of results) {
|
|
71
|
+
sections.push(`\n### ${agent}`);
|
|
72
|
+
for (const item of items) {
|
|
73
|
+
sections.push(`- [${item.type}] **${item.title}**: ${item.summary}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return sections.join("\n");
|
|
77
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { agentDir, getAllAgentNames, readMarkdown } from "../vault.js";
|
|
3
|
+
export async function suggestAgents(input) {
|
|
4
|
+
const names = await getAllAgentNames();
|
|
5
|
+
const taskWords = input.task
|
|
6
|
+
.toLowerCase()
|
|
7
|
+
.split(/[\s,.\-_/]+/)
|
|
8
|
+
.filter((w) => w.length > 1);
|
|
9
|
+
const scored = [];
|
|
10
|
+
for (const name of names) {
|
|
11
|
+
const { data } = await readMarkdown(path.join(agentDir(name), "_agent.md"));
|
|
12
|
+
const haystack = `${data.scope ?? ""} ${data.description ?? ""}`.toLowerCase();
|
|
13
|
+
let score = 0;
|
|
14
|
+
for (const word of taskWords) {
|
|
15
|
+
if (haystack.includes(word)) {
|
|
16
|
+
score++;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (score > 0) {
|
|
20
|
+
scored.push({ name, score });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (scored.length === 0) {
|
|
24
|
+
return ["master"];
|
|
25
|
+
}
|
|
26
|
+
scored.sort((a, b) => b.score - a.score);
|
|
27
|
+
return scored.map((s) => s.name);
|
|
28
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export interface AgentConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
scope: string;
|
|
5
|
+
created: string;
|
|
6
|
+
}
|
|
7
|
+
export interface Belief {
|
|
8
|
+
title: string;
|
|
9
|
+
content: string;
|
|
10
|
+
agent: string;
|
|
11
|
+
confidence: number;
|
|
12
|
+
formed: string;
|
|
13
|
+
reasoning: string;
|
|
14
|
+
supersedes?: string;
|
|
15
|
+
superseded_by?: string;
|
|
16
|
+
evidence_count: number;
|
|
17
|
+
filename: string;
|
|
18
|
+
}
|
|
19
|
+
export interface Decision {
|
|
20
|
+
title: string;
|
|
21
|
+
agent: string;
|
|
22
|
+
context: string;
|
|
23
|
+
decision: string;
|
|
24
|
+
reasoning: string;
|
|
25
|
+
tags: string[];
|
|
26
|
+
date: string;
|
|
27
|
+
outcome: string;
|
|
28
|
+
filename: string;
|
|
29
|
+
}
|
|
30
|
+
export interface Pattern {
|
|
31
|
+
title: string;
|
|
32
|
+
agent: string;
|
|
33
|
+
description: string;
|
|
34
|
+
conditions: string;
|
|
35
|
+
confidence: number;
|
|
36
|
+
derived_from: string[];
|
|
37
|
+
min_evidence: number;
|
|
38
|
+
filename: string;
|
|
39
|
+
}
|
|
40
|
+
export interface AgentContext {
|
|
41
|
+
identity: AgentConfig;
|
|
42
|
+
beliefs: Belief[];
|
|
43
|
+
decisions: Decision[];
|
|
44
|
+
patterns: Pattern[];
|
|
45
|
+
}
|
|
46
|
+
export interface AgentSummary {
|
|
47
|
+
name: string;
|
|
48
|
+
description: string;
|
|
49
|
+
scope: string;
|
|
50
|
+
beliefCount: number;
|
|
51
|
+
decisionCount: number;
|
|
52
|
+
patternCount: number;
|
|
53
|
+
}
|
|
54
|
+
export interface KnowledgeLink {
|
|
55
|
+
source_agent: string;
|
|
56
|
+
source_file: string;
|
|
57
|
+
target_agent: string;
|
|
58
|
+
target_file: string;
|
|
59
|
+
relationship: string;
|
|
60
|
+
created: string;
|
|
61
|
+
filename: string;
|
|
62
|
+
}
|
|
63
|
+
export interface Consolidation {
|
|
64
|
+
agent: string;
|
|
65
|
+
source_count: number;
|
|
66
|
+
date_range: string;
|
|
67
|
+
created: string;
|
|
68
|
+
sources?: string[];
|
|
69
|
+
filename: string;
|
|
70
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/vault.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AgentConfig } from "./types.js";
|
|
2
|
+
export declare const VAULT_BASE: string;
|
|
3
|
+
export declare function agentDir(name: string): string;
|
|
4
|
+
export declare function readMarkdown(filePath: string): Promise<{
|
|
5
|
+
data: Record<string, any>;
|
|
6
|
+
content: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function writeMarkdown(filePath: string, frontmatter: Record<string, any>, body: string): Promise<void>;
|
|
9
|
+
export declare function listFiles(dir: string, ext?: string): Promise<string[]>;
|
|
10
|
+
export declare function agentExists(name: string): Promise<boolean>;
|
|
11
|
+
export declare function updateRegistry(agents: AgentConfig[]): Promise<void>;
|
|
12
|
+
export declare function getAllAgentNames(): Promise<string[]>;
|
|
13
|
+
export declare function ensureBrainDir(): Promise<void>;
|
package/dist/vault.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import matter from "gray-matter";
|
|
4
|
+
function getVaultBase() {
|
|
5
|
+
const vaultPath = process.env.OBSIDIAN_BRAIN_VAULT_PATH;
|
|
6
|
+
if (!vaultPath) {
|
|
7
|
+
throw new Error("OBSIDIAN_BRAIN_VAULT_PATH environment variable is not set. " +
|
|
8
|
+
"Set it to your Obsidian vault path where agent brains will be stored. " +
|
|
9
|
+
'Example: export OBSIDIAN_BRAIN_VAULT_PATH="/path/to/your/vault/AI Brain"');
|
|
10
|
+
}
|
|
11
|
+
return vaultPath;
|
|
12
|
+
}
|
|
13
|
+
export const VAULT_BASE = getVaultBase();
|
|
14
|
+
const MASTER_AGENT = {
|
|
15
|
+
name: "master",
|
|
16
|
+
description: "Root agent that oversees all domain agents and manages cross-cutting concerns",
|
|
17
|
+
scope: "Global coordination, agent management, cross-domain knowledge",
|
|
18
|
+
created: "2026-04-11",
|
|
19
|
+
};
|
|
20
|
+
export function agentDir(name) {
|
|
21
|
+
return path.join(VAULT_BASE, name);
|
|
22
|
+
}
|
|
23
|
+
export async function readMarkdown(filePath) {
|
|
24
|
+
const raw = await fs.readFile(filePath, "utf-8");
|
|
25
|
+
const parsed = matter(raw);
|
|
26
|
+
return { data: parsed.data, content: parsed.content };
|
|
27
|
+
}
|
|
28
|
+
export async function writeMarkdown(filePath, frontmatter, body) {
|
|
29
|
+
const content = matter.stringify(body, frontmatter);
|
|
30
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
31
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
32
|
+
}
|
|
33
|
+
export async function listFiles(dir, ext) {
|
|
34
|
+
try {
|
|
35
|
+
const entries = await fs.readdir(dir);
|
|
36
|
+
if (ext) {
|
|
37
|
+
return entries.filter((e) => e.endsWith(ext));
|
|
38
|
+
}
|
|
39
|
+
return entries;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function agentExists(name) {
|
|
46
|
+
try {
|
|
47
|
+
await fs.access(path.join(agentDir(name), "_agent.md"));
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function updateRegistry(agents) {
|
|
55
|
+
const rows = agents
|
|
56
|
+
.map((a) => `| [[${a.name}/_agent\\|${a.name}]] | ${a.description} | ${a.scope} |`)
|
|
57
|
+
.join("\n");
|
|
58
|
+
const body = `# Claude Agents Brain
|
|
59
|
+
|
|
60
|
+
個人の判断・信念・パターンを構造化するエージェント群
|
|
61
|
+
|
|
62
|
+
## エージェント一覧
|
|
63
|
+
|
|
64
|
+
| エージェント | 説明 | スコープ |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
${rows}
|
|
67
|
+
`;
|
|
68
|
+
await fs.writeFile(path.join(VAULT_BASE, "_registry.md"), body, "utf-8");
|
|
69
|
+
}
|
|
70
|
+
export async function getAllAgentNames() {
|
|
71
|
+
try {
|
|
72
|
+
const entries = await fs.readdir(VAULT_BASE, { withFileTypes: true });
|
|
73
|
+
const names = [];
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
if (entry.isDirectory()) {
|
|
76
|
+
const agentFile = path.join(VAULT_BASE, entry.name, "_agent.md");
|
|
77
|
+
try {
|
|
78
|
+
await fs.access(agentFile);
|
|
79
|
+
names.push(entry.name);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// not an agent directory
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return names;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export async function ensureBrainDir() {
|
|
93
|
+
await fs.mkdir(VAULT_BASE, { recursive: true });
|
|
94
|
+
const masterExists = await agentExists("master");
|
|
95
|
+
if (!masterExists) {
|
|
96
|
+
const masterPath = agentDir("master");
|
|
97
|
+
await fs.mkdir(path.join(masterPath, "beliefs"), { recursive: true });
|
|
98
|
+
await fs.mkdir(path.join(masterPath, "decisions"), { recursive: true });
|
|
99
|
+
await fs.mkdir(path.join(masterPath, "patterns"), { recursive: true });
|
|
100
|
+
const agentBody = `# Master
|
|
101
|
+
|
|
102
|
+
核となる人格・価値観・アイデンティティ
|
|
103
|
+
|
|
104
|
+
## スコープ
|
|
105
|
+
人としての根本的な価値観、美意識、思考の癖、人生の方向性
|
|
106
|
+
|
|
107
|
+
## 統計
|
|
108
|
+
- Beliefs: 0
|
|
109
|
+
- Decisions: 0
|
|
110
|
+
- Patterns: 0
|
|
111
|
+
`;
|
|
112
|
+
await writeMarkdown(path.join(masterPath, "_agent.md"), {
|
|
113
|
+
name: MASTER_AGENT.name,
|
|
114
|
+
description: MASTER_AGENT.description,
|
|
115
|
+
scope: MASTER_AGENT.scope,
|
|
116
|
+
created: MASTER_AGENT.created,
|
|
117
|
+
}, agentBody);
|
|
118
|
+
}
|
|
119
|
+
// Ensure _registry.md exists
|
|
120
|
+
const registryPath = path.join(VAULT_BASE, "_registry.md");
|
|
121
|
+
try {
|
|
122
|
+
await fs.access(registryPath);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
const agents = [];
|
|
126
|
+
if (await agentExists("master")) {
|
|
127
|
+
agents.push(MASTER_AGENT);
|
|
128
|
+
}
|
|
129
|
+
await updateRegistry(agents);
|
|
130
|
+
}
|
|
131
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "obsidian-brain-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server that turns your Obsidian vault into a domain-specific AI brain with dynamic agent creation, knowledge management, and cross-agent intelligence",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"obsidian-brain-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"obsidian",
|
|
18
|
+
"ai",
|
|
19
|
+
"agent",
|
|
20
|
+
"knowledge-management",
|
|
21
|
+
"model-context-protocol",
|
|
22
|
+
"claude"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "HikaruHonda",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/AtsushiHosaka/obsidian-brain-mcp"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"prepare": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
39
|
+
"gray-matter": "^4.0.3",
|
|
40
|
+
"slugify": "^1.6.6"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^22.0.0",
|
|
44
|
+
"typescript": "^5.7.0"
|
|
45
|
+
}
|
|
46
|
+
}
|