#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { Tool } from '@modelcontextprotocol/sdk/types.js';
import { LimitlessClient } from './lib/limitless-client.js';
import { logger } from './lib/logger.js';
import { getConfig } from './config/index.js';
// Import all tools
import {
listLifelogsTool,
listLifelogs,
getLifelogTool,
getLifelog,
searchLifelogsTool,
searchLifelogs,
getDailySummaryTool,
getDailySummary,
starLifelogTool,
starLifelog,
askAITool,
askAI,
exportMarkdownTool,
exportMarkdown,
} from './tools/lifelogs/index.js';
// Tool registry
const TOOLS: Tool[] = [
listLifelogsTool,
getLifelogTool,
searchLifelogsTool,
getDailySummaryTool,
starLifelogTool,
askAITool,
exportMarkdownTool,
];
// Handler registry
const handlers: Record<string, (params: any, client: LimitlessClient) => Promise<any>> = {
limitless_list_lifelogs: listLifelogs,
limitless_get_lifelog: getLifelog,
limitless_search_lifelogs: searchLifelogs,
limitless_get_daily_summary: getDailySummary,
limitless_star_lifelog: starLifelog,
limitless_ask_ai: askAI,
limitless_export_markdown: exportMarkdown,
};
export function setupServer(): Server {
// Validate configuration at startup
try {
getConfig();
} catch (error: any) {
logger.error('Invalid configuration:', error.message);
throw error;
}
const server = new Server(
{
name: 'limitless-mcp-server',
version: '1.0.0',
description: 'Connect AI assistants to Limitless for personal memory and lifelog access',
},
{
capabilities: {
tools: true,
prompts: false,
resources: false,
},
}
);
// Create client instance
const client = new LimitlessClient();
// Register all tools
TOOLS.forEach((tool) => {
server.setToolHandler(tool.name, async (params) => {
logger.debug(`Handling tool: ${tool.name}`, params);
const handler = handlers[tool.name];
if (!handler) {
throw new Error(`No handler found for tool: ${tool.name}`);
}
try {
const result = await handler(params, client);
logger.debug(`Tool ${tool.name} completed successfully`);
return result;
} catch (error: any) {
logger.error(`Tool ${tool.name} failed:`, error.message);
throw error;
}
});
});
logger.info('Limitless MCP Server initialized with tools:', TOOLS.map(t => t.name));
return server;
}
async function main() {
const server = setupServer();
const transport = new StdioServerTransport();
await server.connect(transport);
logger.info('Limitless MCP Server started');
}
// Run the server
if (require.main === module) {
main().catch((error) => {
logger.error('Fatal error:', error);
process.exit(1);
});
}
export { LimitlessClient } from './lib/limitless-client.js';