Port the useful dynamic-vault MCP direction from Domenico Lupinetti's proposal into the current mounted-workspace model. Durable external MCP registration is now vault-neutral, Node MCP resolves active mounted vaults from explicit env or Tolaria vaults.json, and vault context includes root AGENTS.md instructions per active vault. Based-on: https://github.com/refactoringhq/tolaria/pull/603 Co-authored-by: Domenico Lupinetti <domenico@translated.net>
89 lines
2.6 KiB
JavaScript
89 lines
2.6 KiB
JavaScript
import { existsSync, readFileSync } from 'node:fs'
|
|
import { homedir, platform } from 'node:os'
|
|
import { join } from 'node:path'
|
|
|
|
const APP_CONFIG_DIR = 'com.tolaria.app'
|
|
const LEGACY_APP_CONFIG_DIR = 'com.laputa.app'
|
|
|
|
function parseVaultPathList(rawValue) {
|
|
if (!rawValue?.trim()) return []
|
|
|
|
try {
|
|
const parsed = JSON.parse(rawValue)
|
|
if (Array.isArray(parsed)) return parsed.filter(value => typeof value === 'string')
|
|
} catch {
|
|
// Older clients only set VAULT_PATH; keep VAULT_PATHS strict JSON so paths
|
|
// with platform separators are never split incorrectly.
|
|
}
|
|
|
|
return []
|
|
}
|
|
|
|
function uniqueVaultPaths(paths) {
|
|
const seen = new Set()
|
|
const unique = []
|
|
for (const path of paths) {
|
|
const trimmed = path.trim()
|
|
if (!trimmed || seen.has(trimmed)) continue
|
|
seen.add(trimmed)
|
|
unique.push(trimmed)
|
|
}
|
|
return unique
|
|
}
|
|
|
|
function appConfigBaseDir(env = process.env) {
|
|
if (platform() === 'darwin') return join(homedir(), 'Library', 'Application Support')
|
|
if (platform() === 'win32') return env.APPDATA || join(homedir(), 'AppData', 'Roaming')
|
|
return env.XDG_CONFIG_HOME || join(homedir(), '.config')
|
|
}
|
|
|
|
export function vaultsJsonPath({ configDir = appConfigBaseDir() } = {}) {
|
|
const preferred = join(configDir, APP_CONFIG_DIR, 'vaults.json')
|
|
if (existsSync(preferred)) return preferred
|
|
|
|
const legacy = join(configDir, LEGACY_APP_CONFIG_DIR, 'vaults.json')
|
|
return existsSync(legacy) ? legacy : preferred
|
|
}
|
|
|
|
function pushUniquePath(paths, value) {
|
|
const path = typeof value === 'string' ? value.trim() : ''
|
|
if (!path || paths.includes(path)) return
|
|
paths.push(path)
|
|
}
|
|
|
|
function activeVaultPathsFromList(list) {
|
|
const paths = []
|
|
pushUniquePath(paths, list?.active_vault)
|
|
|
|
for (const vault of list?.vaults ?? []) {
|
|
if (vault?.mounted === false) continue
|
|
pushUniquePath(paths, vault?.path)
|
|
}
|
|
|
|
return paths
|
|
}
|
|
|
|
export function configuredVaultPaths({ configDir } = {}) {
|
|
const filePath = vaultsJsonPath({ configDir })
|
|
if (!existsSync(filePath)) return []
|
|
|
|
return activeVaultPathsFromList(JSON.parse(readFileSync(filePath, 'utf-8')))
|
|
}
|
|
|
|
export function requireVaultPaths(env = process.env, options = {}) {
|
|
const vaultPaths = uniqueVaultPaths([
|
|
env.VAULT_PATH?.trim() ?? '',
|
|
...parseVaultPathList(env.VAULT_PATHS),
|
|
])
|
|
if (vaultPaths.length === 0) {
|
|
const configuredPaths = configuredVaultPaths(options)
|
|
if (configuredPaths.length > 0) return configuredPaths
|
|
throw new Error('VAULT_PATH is required. Open a vault in Tolaria before starting MCP tools.')
|
|
}
|
|
return vaultPaths
|
|
}
|
|
|
|
export function requireVaultPath(env = process.env, options = {}) {
|
|
return requireVaultPaths(env, options)[0]
|
|
}
|