| name | km-storage-abstraction |
| description | Unified storage interface for Obsidian, Notion, and local file systems |
Storage Abstraction Layer
Unified interface for saving notes across different storage backends
Storage Selection and Target-Root Contract
function get_storage_backend(options = {}) {
config = Read("km-config.json") || {}
if (options.explicit_backend) return options.explicit_backend
if (options.project_scoped) return "local"
return config?.storage?.primary || "local"
}
For project-scoped file saves, the workflow must pass target_root. The backend may choose a tool, but it must not choose or redirect the destination root.
Priority: user-explicit destination/backend โ host-provided primary project/workspace root โ configured backend only outside project-scoped requests.
๐ Target Root ์ผ์น ๊ท์น (CRITICAL)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ CRITICAL: target_root ๋ณด์กด ๊ฐ์ โ
โ โ
โ Obsidian ๋๊ตฌ๋ ์ฐ๊ฒฐ ๋ณผํธ์ target_root๊ฐ ๊ฐ์ ๋๋ง! โ
โ โ
โ โ ์๋ชป๋ ์: โ
โ - ์ฐ๊ฒฐ ๋ณผํธ ํ์ธ ์์ด MCP๋ก ์๋๊ฒฝ๋ก ์ ์ฅ โ
โ โ
โ โ
์ฌ๋ฐ๋ฅธ ์: โ
โ - roots ๋์ผ โ MCP / ๋ค๋ฆยท๋ฏธํ์ธ โ target_root Writeโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Backend Mapping (Antigravity/Gemini CLI)
| Feature | Obsidian | Notion | Local |
|---|
| Create | mcp_obsidian_create_note | mcp_notion_API-post-page | write_to_file |
| Search | mcp_obsidian_search_vault | mcp_notion_API-post-search | N/A |
| Read | mcp_obsidian_read_note | mcp_notion_API-get-block-children | read_file |
| Path format | Relative to vault | Database/Page ID | File system path |
| Wikilinks | Supported | Converted to mentions | Supported |
์ฐธ๊ณ : Antigravity๋ MCP ๋๊ตฌ ์ด๋ฆ์ ์ฑ๊ธ ์ธ๋์ค์ฝ์ด(_)๋ฅผ ์ฌ์ฉํฉ๋๋ค.
MCP ๋๊ตฌ ์ฌ์ฉ ๊ฐ์ด๋ (Obsidian)
| ์์
| ๋๊ตฌ๋ช
| ์ค๋ช
|
|---|
| ๋
ธํธ ์์ฑ | mcp_obsidian_create_note | ์ ๋
ธํธ ์์ฑ |
| ๋
ธํธ ๊ฒ์ | mcp_obsidian_search_vault | Vault ๋ด ํค์๋ ๊ฒ์ |
| ๋
ธํธ ์ฝ๊ธฐ | mcp_obsidian_read_note | ๋
ธํธ ๋ด์ฉ ์ฝ๊ธฐ |
| ๋
ธํธ ๋ชฉ๋ก | mcp_obsidian_list_notes | ํด๋ ๋ด ๋
ธํธ ๋ชฉ๋ก |
Unified Save Function
function canonical(path) {
return realpath(path)
}
function same_path(left, right) {
return canonical(left) === canonical(right)
}
function resolve_within(canonical_root, relativePath) {
current = canonical_root
for (component of dirname(relativePath).split('/')) {
next = join(current, component)
if (!exists(next)) mkdir(next)
current = canonical(next)
assert(is_within(current, canonical_root))
}
return join(current, basename(relativePath))
}
function save_note(relativePath, content, options = {}) {
config = Read("km-config.json") || {}
backend = get_storage_backend(options)
target_root = options.target_root
if (options.project_scoped && !target_root) {
throw new Error("target_root is required for a project-scoped save")
}
canonical_target_root = target_root ? canonical(target_root) :
safe_relative_path = (relativePath)
((safe_relative_path) || (safe_relative_path)) {
()
}
target_candidate = options.
? (canonical_target_root, safe_relative_path)
:
() {
((target_candidate, canonical_target_root))
result = (target_candidate, content)
{ ...result, : target_candidate }
}
(backend) {
:
obsidian_root = config?.?.?. || ()
(options. && (!obsidian_root || !(obsidian_root, canonical_target_root))) {
result = ()
}
result = ({
: safe_relative_path,
: content
})
result. = options.
? target_candidate
: ((obsidian_root), safe_relative_path)
:
(options. && options. !== ) {
result = ()
}
({
: { : config... },
: { : [{ : { : (relativePath) } }] }
})
:
:
(options.) {
result = ()
} {
outputPath = config?.?.?. ||
fullPath =
result = (fullPath, content)
result. = fullPath
}
}
actual_saved_path = (result.)
((actual_saved_path))
(options. && !(actual_saved_path, canonical_target_root)) {
()
}
{ ...result, actual_saved_path }
}
Path Normalization
function normalize_path(path) {
path = path.replace(/\\/g, '/')
path = path.replace(/^\//, '')
return path
}
Verification (CRITICAL)
After every save operation:
โก Did the tool actually execute? (no JSON-only output!)
โก Did we receive a success response?
โก Is actual_saved_path canonicalized and does the file exist there?
โก For a project-scoped save, is actual_saved_path inside canonical_target_root?
โก Does the final report include target_root, relative path, and actual_saved_path?