Skip to main content
Glama
portel-dev

NCP - Natural Context Provider

by portel-dev
intelligence.photon.ts4.24 kB
/** * Intelligence Photon - Simple Claude CLI Wrapper * * Takes a prompt and list of MCPs, runs Claude CLI, returns response. * Uses your Claude Desktop subscription (no API key needed). */ import { promises as fs } from 'fs'; import { join } from 'path'; import { homedir, tmpdir } from 'os'; import { exec } from 'child_process'; import { promisify } from 'util'; import { logger } from '../utils/logger.js'; const execAsync = promisify(exec); export default class IntelligenceMCP { name = 'intelligence'; description = 'Run Claude CLI with specific MCPs - simple wrapper using your Claude Desktop subscription'; private claudePath: string; private claudeConfigPath: string; constructor() { this.claudePath = '/opt/homebrew/bin/claude'; this.claudeConfigPath = join(homedir(), '.config', 'claude-desktop', 'claude_desktop_config.json'); } /** * Execute a prompt with Claude CLI using specified MCPs */ async execute(params: { prompt: string; mcps?: string[]; }): Promise<{ success: boolean; content?: string; error?: string }> { const { prompt, mcps } = params; if (!prompt || prompt.trim().length === 0) { return { success: false, error: 'Prompt is required' }; } // Check Claude CLI exists try { await execAsync(`${this.claudePath} --version`); } catch (error) { return { success: false, error: `Claude CLI not found at ${this.claudePath}. Please install Claude Code.` }; } // Read Claude Desktop config let claudeConfig: any; try { const configData = await fs.readFile(this.claudeConfigPath, 'utf-8'); claudeConfig = JSON.parse(configData); } catch (error) { return { success: false, error: `Failed to read Claude Desktop config at ${this.claudeConfigPath}` }; } if (!claudeConfig.mcpServers || Object.keys(claudeConfig.mcpServers).length === 0) { return { success: false, error: 'No MCPs configured in Claude Desktop' }; } // Filter MCPs if requested let filteredConfig = claudeConfig; if (mcps && mcps.length > 0) { const filtered: any = { mcpServers: {} }; for (const mcpName of mcps) { if (claudeConfig.mcpServers[mcpName]) { filtered.mcpServers[mcpName] = claudeConfig.mcpServers[mcpName]; } else { logger.warn(`[Intelligence] MCP "${mcpName}" not found in Claude Desktop config, skipping`); } } if (Object.keys(filtered.mcpServers).length === 0) { return { success: false, error: `None of the requested MCPs (${mcps.join(', ')}) are configured in Claude Desktop` }; } filteredConfig = filtered; } // Write temp config const tempConfigPath = join(tmpdir(), `intelligence-mcp-${Date.now()}.json`); await fs.writeFile(tempConfigPath, JSON.stringify(filteredConfig, null, 2)); const mcpCount = Object.keys(filteredConfig.mcpServers).length; logger.info(`[Intelligence] Executing Claude CLI with ${mcpCount} MCPs: ${Object.keys(filteredConfig.mcpServers).join(', ')}`); try { // Execute Claude CLI // IMPORTANT: prompt must come BEFORE --mcp-config! const { stdout, stderr } = await execAsync( `"${this.claudePath}" --print --output-format text "${prompt.replace(/"/g, '\\"')}" --mcp-config "${tempConfigPath}"`, { maxBuffer: 10 * 1024 * 1024, // 10MB timeout: 5 * 60 * 1000 // 5 minutes } ); // Clean up temp file await fs.unlink(tempConfigPath).catch(() => {}); if (stderr && stderr.trim()) { logger.debug(`[Intelligence] Claude CLI stderr: ${stderr}`); } logger.info(`[Intelligence] Execution complete`); return { success: true, content: stdout.trim() || 'Execution completed' }; } catch (error: any) { // Clean up temp file await fs.unlink(tempConfigPath).catch(() => {}); logger.error(`[Intelligence] Claude CLI failed: ${error.message}`); return { success: false, error: `Claude CLI execution failed: ${error.message}` }; } } }

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/portel-dev/ncp'

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