UNPKG

actual-mcp

Version:

Actual Budget MCP server exposing API functionality

93 lines 2.89 kB
import api from '@actual-app/api'; import fs from 'fs'; import path from 'path'; import os from 'os'; const DEFAULT_DATA_DIR = path.resolve(os.homedir() || '.', '.actual'); // API initialization state let initialized = false; let initializing = false; let initializationError = null; /** * Initialize the Actual Budget API */ export async function initActualApi() { if (initialized) return; if (initializing) { // Wait for initialization to complete if already in progress while (initializing) { await new Promise((resolve) => setTimeout(resolve, 100)); } if (initializationError) throw initializationError; return; } try { console.error('Initializing Actual Budget API...'); const dataDir = process.env.ACTUAL_DATA_DIR || DEFAULT_DATA_DIR; if (!fs.existsSync(dataDir)) { fs.mkdirSync(dataDir, { recursive: true }); } await api.init({ dataDir, serverURL: process.env.ACTUAL_SERVER_URL, password: process.env.ACTUAL_PASSWORD, }); const budgets = await api.getBudgets(); if (!budgets || budgets.length === 0) { throw new Error('No budgets found. Please create a budget in Actual first.'); } // Use specified budget or the first one const budgetId = process.env.ACTUAL_BUDGET_SYNC_ID || budgets[0].cloudFileId || budgets[0].id || ''; console.error(`Loading budget: ${budgetId}`); await api.downloadBudget(budgetId); initialized = true; console.error('Actual Budget API initialized successfully'); } catch (error) { console.error('Failed to initialize Actual Budget API:', error); initializationError = error instanceof Error ? error : new Error(String(error)); throw initializationError; } finally { initializing = false; } } /** * Shutdown the Actual Budget API */ export async function shutdownActualApi() { if (!initialized) return; await api.shutdown(); initialized = false; } /** * Get all accounts (ensures API is initialized) */ export async function getAccounts() { await initActualApi(); return api.getAccounts(); } /** * Get all categories (ensures API is initialized) */ export async function getCategories() { await initActualApi(); return api.getCategories(); } /** * Get all category groups (ensures API is initialized) */ export async function getCategoryGroups() { await initActualApi(); return api.getCategoryGroups(); } /** * Get transactions for a specific account and date range (ensures API is initialized) */ export async function getTransactions(accountId, start, end) { await initActualApi(); return api.getTransactions(accountId, start, end); } //# sourceMappingURL=actual-api.js.map