- Rename local-proxy to mcplocal with HTTP server, LLM pipeline, mcpd discovery - Add LLM pre-processing: token estimation, filter cache, metrics, Gemini CLI + DeepSeek providers - Add mcpd auth (login/logout) and MCP proxy endpoints - Update CLI: dual URLs (mcplocalUrl/mcpdUrl), auth commands, --direct flag - Add tiered health monitoring, shell completions, e2e integration tests - 57 test files, 597 tests passing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
130 lines
4.3 KiB
TypeScript
130 lines
4.3 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import { mkdtempSync, rmSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { tmpdir } from 'node:os';
|
|
import { createStatusCommand } from '../../src/commands/status.js';
|
|
import { saveConfig, DEFAULT_CONFIG } from '../../src/config/index.js';
|
|
import { saveCredentials } from '../../src/auth/index.js';
|
|
|
|
let tempDir: string;
|
|
let output: string[];
|
|
|
|
function log(...args: string[]) {
|
|
output.push(args.join(' '));
|
|
}
|
|
|
|
beforeEach(() => {
|
|
tempDir = mkdtempSync(join(tmpdir(), 'mcpctl-status-test-'));
|
|
output = [];
|
|
});
|
|
|
|
afterEach(() => {
|
|
rmSync(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
describe('status command', () => {
|
|
it('shows status in table format', async () => {
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async () => true,
|
|
});
|
|
await cmd.parseAsync([], { from: 'user' });
|
|
const out = output.join('\n');
|
|
expect(out).toContain('mcpctl v');
|
|
expect(out).toContain('mcplocal:');
|
|
expect(out).toContain('mcpd:');
|
|
expect(out).toContain('connected');
|
|
});
|
|
|
|
it('shows unreachable when daemons are down', async () => {
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async () => false,
|
|
});
|
|
await cmd.parseAsync([], { from: 'user' });
|
|
expect(output.join('\n')).toContain('unreachable');
|
|
});
|
|
|
|
it('shows not logged in when no credentials', async () => {
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async () => true,
|
|
});
|
|
await cmd.parseAsync([], { from: 'user' });
|
|
expect(output.join('\n')).toContain('not logged in');
|
|
});
|
|
|
|
it('shows logged in user when credentials exist', async () => {
|
|
saveCredentials({ token: 'tok', mcpdUrl: 'http://x:3100', user: 'alice@example.com' }, { configDir: tempDir });
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async () => true,
|
|
});
|
|
await cmd.parseAsync([], { from: 'user' });
|
|
expect(output.join('\n')).toContain('logged in as alice@example.com');
|
|
});
|
|
|
|
it('shows status in JSON format', async () => {
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async () => true,
|
|
});
|
|
await cmd.parseAsync(['-o', 'json'], { from: 'user' });
|
|
const parsed = JSON.parse(output[0]) as Record<string, unknown>;
|
|
expect(parsed['version']).toBe('0.1.0');
|
|
expect(parsed['mcplocalReachable']).toBe(true);
|
|
expect(parsed['mcpdReachable']).toBe(true);
|
|
});
|
|
|
|
it('shows status in YAML format', async () => {
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async () => false,
|
|
});
|
|
await cmd.parseAsync(['-o', 'yaml'], { from: 'user' });
|
|
expect(output[0]).toContain('mcplocalReachable: false');
|
|
});
|
|
|
|
it('checks correct URLs from config', async () => {
|
|
saveConfig({ ...DEFAULT_CONFIG, mcplocalUrl: 'http://local:3200', mcpdUrl: 'http://remote:3100' }, { configDir: tempDir });
|
|
const checkedUrls: string[] = [];
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async (url) => {
|
|
checkedUrls.push(url);
|
|
return false;
|
|
},
|
|
});
|
|
await cmd.parseAsync([], { from: 'user' });
|
|
expect(checkedUrls).toContain('http://local:3200');
|
|
expect(checkedUrls).toContain('http://remote:3100');
|
|
});
|
|
|
|
it('shows registries from config', async () => {
|
|
saveConfig({ ...DEFAULT_CONFIG, registries: ['official'] }, { configDir: tempDir });
|
|
const cmd = createStatusCommand({
|
|
configDeps: { configDir: tempDir },
|
|
credentialsDeps: { configDir: tempDir },
|
|
log,
|
|
checkHealth: async () => true,
|
|
});
|
|
await cmd.parseAsync([], { from: 'user' });
|
|
expect(output.join('\n')).toContain('official');
|
|
expect(output.join('\n')).not.toContain('glama');
|
|
});
|
|
});
|