Skip to main content
Glama

Smart Connections MCP Server

by msdanyg
smart-connections-loader.tsβ€’5.62 kB
/** * Loader for Smart Connections data from .smart-env directory */ import * as fs from 'fs'; import * as path from 'path'; import type { SmartSource, SmartEnvConfig } from './types.js'; export class SmartConnectionsLoader { private vaultPath: string; private smartEnvPath: string; private config: SmartEnvConfig | null = null; private sources: Map<string, SmartSource> = new Map(); constructor(vaultPath: string) { this.vaultPath = vaultPath; this.smartEnvPath = path.join(vaultPath, '.smart-env'); } /** * Initialize and load all Smart Connections data */ async initialize(): Promise<void> { // Check if .smart-env exists if (!fs.existsSync(this.smartEnvPath)) { throw new Error(`Smart Connections directory not found at: ${this.smartEnvPath}`); } // Load configuration await this.loadConfig(); // Load all sources await this.loadSources(); } /** * Load smart_env.json configuration */ private async loadConfig(): Promise<void> { const configPath = path.join(this.smartEnvPath, 'smart_env.json'); if (!fs.existsSync(configPath)) { throw new Error(`Configuration file not found at: ${configPath}`); } const configData = fs.readFileSync(configPath, 'utf-8'); this.config = JSON.parse(configData); } /** * Load all .ajson files from the multi directory */ private async loadSources(): Promise<void> { const multiPath = path.join(this.smartEnvPath, 'multi'); if (!fs.existsSync(multiPath)) { throw new Error(`Multi directory not found at: ${multiPath}`); } const files = fs.readdirSync(multiPath); const ajsonFiles = files.filter(f => f.endsWith('.ajson')); console.error(`Loading ${ajsonFiles.length} source files...`); for (const file of ajsonFiles) { try { const filePath = path.join(multiPath, file); const content = fs.readFileSync(filePath, 'utf-8'); // Parse the AJSON format (JSONL - one JSON object per line) // Each line is a single object like: "key": {...} const lines = content.trim().split('\n'); for (const line of lines) { if (!line.trim()) continue; try { // Each line is formatted as: "key1": {...}, "key2": {...}, "key3": {...}, // Remove trailing comma and wrap with curly braces to make valid JSON const cleanedLine = line.replace(/,\s*$/, ''); const obj = JSON.parse(`{${cleanedLine}}`); // Process all key-value pairs in the object for (const key of Object.keys(obj)) { // Only process smart_sources entries (not smart_blocks) if (key.startsWith('smart_sources:')) { const sourceData: SmartSource = obj[key]; // Skip entries with null/undefined paths if (sourceData && sourceData.path) { this.sources.set(sourceData.path, sourceData); } } } } catch (parseError) { // Skip lines that can't be parsed console.error(`Parse error in ${file}:`, parseError); } } } catch (error) { console.error(`Error loading ${file}:`, error); } } console.error(`Loaded ${this.sources.size} sources successfully`); } /** * Get all sources */ getSources(): Map<string, SmartSource> { return this.sources; } /** * Get a specific source by path */ getSource(notePath: string): SmartSource | undefined { return this.sources.get(notePath); } /** * Get configuration */ getConfig(): SmartEnvConfig | null { return this.config; } /** * Get the embedding model key from config */ getEmbeddingModelKey(): string { if (!this.config) { throw new Error('Configuration not loaded'); } // Extract the model key from the embed_model configuration const embedModel = this.config.smart_sources.embed_model; const adapter = embedModel.adapter; // The actual model key is nested in the adapter configuration // e.g., embed_model.transformers.model_key = "TaylorAI/bge-micro-v2" if (adapter && embedModel[adapter] && typeof embedModel[adapter] === 'object') { const adapterConfig = embedModel[adapter] as any; if (adapterConfig.model_key) { return adapterConfig.model_key; } } // Fallback: find first object key that's not 'adapter' const modelKeys = Object.keys(embedModel).filter(k => k !== 'adapter' && typeof embedModel[k] === 'object'); if (modelKeys.length === 0) { throw new Error('No embedding model found in configuration'); } return modelKeys[0]; } /** * Get vault path */ getVaultPath(): string { return this.vaultPath; } /** * Read the actual markdown content of a note */ readNoteContent(notePath: string): string { const fullPath = path.join(this.vaultPath, notePath); if (!fs.existsSync(fullPath)) { throw new Error(`Note not found at: ${fullPath}`); } return fs.readFileSync(fullPath, 'utf-8'); } /** * Extract content for specific blocks/sections */ extractBlockContent(notePath: string, blockHeading: string): string { const content = this.readNoteContent(notePath); const source = this.getSource(notePath); if (!source || !source.blocks[blockHeading]) { return ''; } const [startLine, endLine] = source.blocks[blockHeading]; const lines = content.split('\n'); return lines.slice(startLine - 1, endLine).join('\n'); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/msdanyg/smart-connections-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server