Skip to main content
Glama

hypertool-mcp

setup-scripts.test.tsโ€ข8.47 kB
/** * Integration tests for setup scripts (Claude Desktop, Cursor, Claude Code) * Demonstrates testing application installation without affecting real filesystem */ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { TestEnvironment } from '../fixtures/base.js'; import { FreshInstallScenario, ExistingConfigScenario, PartialConfigScenario, CorruptedConfigScenario } from '../fixtures/scenarios/index.js'; import { ClaudeCodeFixture } from '../fixtures/applications/index.js'; import { assertBackupCreated, assertHasHypertoolConfig, assertSlashCommandsInstalled, getConfigContent, assertFileExists } from '../helpers/assertions.js'; // We'll need to mock the setup classes to use our test environment // In a real implementation, you would refactor the setup scripts to accept // a filesystem abstraction that could be mocked describe('Setup Scripts Integration Tests', () => { let env: TestEnvironment; beforeEach(async () => { env = new TestEnvironment('/tmp/hypertool-test'); }); afterEach(async () => { await env.teardown(); }); describe('Claude Desktop Setup', () => { it('should install hypertool in fresh Claude Desktop installation', async () => { await env.setup(new FreshInstallScenario()); // Simulate Claude Desktop being installed but no MCP config await env.createAppStructure('claude-desktop', { 'Library/Application Support/Claude/preferences.json': JSON.stringify({ theme: 'dark' }) }); // In a real test, you would run the actual ClaudeDesktopSetup // For this example, we'll simulate what it does const configPath = '/tmp/hypertool-test/Library/Application Support/Claude/claude_desktop_config.json'; const hypertoolPath = '/tmp/hypertool-test/Library/Application Support/Claude/mcp.hypertool.json'; // Simulate setup creating config await env.createAppStructure('claude-desktop', { 'Library/Application Support/Claude/claude_desktop_config.json': JSON.stringify({ mcpServers: { 'hypertool-mcp': { type: 'stdio', command: 'npx', args: ['-y', '@toolprint/hypertool-mcp', '--mcp-config', hypertoolPath] } } }, null, 2), 'Library/Application Support/Claude/mcp.hypertool.json': JSON.stringify({ mcpServers: {} }, null, 2) }); assertHasHypertoolConfig(configPath); assertFileExists(hypertoolPath); }); it('should backup existing Claude Desktop configuration', async () => { await env.setup(new ExistingConfigScenario(['claude-desktop'])); const configPath = '/tmp/hypertool-test/Library/Application Support/Claude/claude_desktop_config.json'; const originalConfig = getConfigContent(configPath); // Simulate backup creation const backupPath = configPath.replace('.json', '.backup.json'); await env.createAppStructure('claude-desktop', { [backupPath.substring('/tmp/hypertool-test/'.length)]: JSON.stringify(originalConfig, null, 2) }); assertBackupCreated(configPath); }); }); describe('Cursor Setup', () => { it('should handle Cursor with existing MCP servers', async () => { await env.setup(new ExistingConfigScenario(['cursor'])); const configPath = '/tmp/hypertool-test/.cursor/mcp.json'; const originalConfig = getConfigContent(configPath); expect(Object.keys(originalConfig.mcpServers)).toContain('code-search'); expect(Object.keys(originalConfig.mcpServers)).toContain('database'); // Simulate migration const hypertoolPath = '/tmp/hypertool-test/.cursor/mcp.hypertool.json'; await env.createAppStructure('cursor', { '.cursor/mcp.hypertool.json': JSON.stringify(originalConfig, null, 2), '.cursor/mcp.json': JSON.stringify({ mcpServers: { 'hypertool-mcp': { type: 'stdio', command: 'npx', args: ['-y', '@toolprint/hypertool-mcp', '--mcp-config', hypertoolPath] } } }, null, 2) }); assertHasHypertoolConfig(configPath); const hypertoolConfig = getConfigContent(hypertoolPath); expect(Object.keys(hypertoolConfig.mcpServers)).toContain('code-search'); }); }); describe('Claude Code Setup', () => { let projectPath: string; beforeEach(async () => { projectPath = await env.createProjectDir('test-project'); }); it('should create .mcp.json if not exists', async () => { await env.setup(new FreshInstallScenario()); const mcpPath = `${projectPath}/.mcp.json`; expect(await env.fileExists(mcpPath)).toBe(false); // Simulate creating basic config await ClaudeCodeFixture.install(env, projectPath, { withServers: false }); expect(await env.fileExists(mcpPath)).toBe(true); const config = getConfigContent(mcpPath); expect(config.mcpServers).toBeDefined(); }); it('should install slash commands globally', async () => { await env.setup(new FreshInstallScenario()); await ClaudeCodeFixture.install(env, projectPath, { withServers: true, withSlashCommands: true, globalCommands: true }); assertSlashCommandsInstalled('global'); }); it('should install slash commands locally in project', async () => { await env.setup(new FreshInstallScenario()); await ClaudeCodeFixture.install(env, projectPath, { withServers: true, withSlashCommands: true, globalCommands: false }); assertSlashCommandsInstalled('local', projectPath); }); it('should handle project with existing hypertool setup', async () => { await env.setup(new FreshInstallScenario()); await ClaudeCodeFixture.installWithHypertool(env, projectPath); const mcpPath = `${projectPath}/.mcp.json`; const hypertoolPath = `${projectPath}/mcp.hypertool.json`; assertHasHypertoolConfig(mcpPath); assertFileExists(hypertoolPath); const hypertoolConfig = getConfigContent(hypertoolPath); expect(Object.keys(hypertoolConfig.mcpServers).length).toBeGreaterThan(0); }); }); describe('Error Handling', () => { it('should handle corrupted configurations gracefully', async () => { await env.setup(new CorruptedConfigScenario(['claude-desktop', 'cursor'])); // Verify corrupted files exist const claudePath = '/tmp/hypertool-test/Library/Application Support/Claude/claude_desktop_config.json'; const cursorPath = '/tmp/hypertool-test/.cursor/mcp.json'; expect(await env.fileExists(claudePath)).toBe(true); expect(await env.fileExists(cursorPath)).toBe(true); // Attempting to read should fail expect(() => getConfigContent(claudePath)).toThrow(); expect(() => getConfigContent(cursorPath)).toThrow(); }); it('should handle partial configurations', async () => { await env.setup(new PartialConfigScenario(['claude-desktop'], ['cursor'])); // Claude Desktop has config const claudePath = '/tmp/hypertool-test/Library/Application Support/Claude/claude_desktop_config.json'; const claudeConfig = getConfigContent(claudePath); expect(Object.keys(claudeConfig.mcpServers).length).toBeGreaterThan(0); // Cursor exists but no MCP config expect(await env.fileExists('/tmp/hypertool-test/.cursor/settings.json')).toBe(true); expect(await env.fileExists('/tmp/hypertool-test/.cursor/mcp.json')).toBe(false); }); }); describe('Cross-Platform Testing', () => { it('should handle Windows paths correctly', async () => { env.setPlatform('win32'); await env.setup(new FreshInstallScenario()); // Create Windows-style paths await env.createAppStructure('claude-desktop', { 'AppData/Roaming/Claude/claude_desktop_config.json': JSON.stringify({ mcpServers: { 'test-server': { type: 'stdio', command: 'test.exe' } } }, null, 2) }); const winPath = '/tmp/hypertool-test/AppData/Roaming/Claude/claude_desktop_config.json'; expect(await env.fileExists(winPath)).toBe(true); const config = getConfigContent(winPath); expect(config.mcpServers['test-server'].command).toBe('test.exe'); }); }); });

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/toolprint/hypertool-mcp'

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