import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js'; import { afterEach, describe, expect, it, vi } from 'vitest'; import type { RedditBotApiClient } from '../src/mcp/api-client.js'; import { createRedditBotMcpServer } from '../src/mcp/server.js'; describe('RedditBot MCP server', () => { const closeables: Array<{ close(): Promise }> = []; afterEach(async () => { await Promise.all(closeables.splice(0).map((item) => item.close())); }); async function connectedClient() { const get = vi.fn(async () => ({ status: 'operational' })); const post = vi.fn(async () => ({ success: true, running: true })); const server = createRedditBotMcpServer({ get, post } as unknown as RedditBotApiClient); const client = new Client({ name: 'test-client', version: '1.0.0' }); const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]); closeables.push(client, server); return { client, get, post }; } it('advertises read, control, and explicit external-send tools', async () => { const { client } = await connectedClient(); const tools = await client.listTools(); const names = tools.tools.map((tool) => tool.name); expect(names).toEqual(expect.arrayContaining([ 'get_overview', 'list_accounts', 'list_conversations', 'start_bot', 'stop_bot', 'set_bot_running', 'trigger_sync', 'send_reply', 'send_message_to_user', 'start_conversation', ])); expect(tools.tools.find((tool) => tool.name === 'get_overview')?.annotations?.readOnlyHint).toBe(true); expect(tools.tools.find((tool) => tool.name === 'send_reply')?.annotations?.destructiveHint).toBe(true); expect(tools.tools.find((tool) => tool.name === 'send_message_to_user')?.annotations?.destructiveHint).toBe(true); }); it('routes start and stop tools to the versioned control API', async () => { const { client, post } = await connectedClient(); await client.callTool({ name: 'start_bot', arguments: {} }); await client.callTool({ name: 'stop_bot', arguments: {} }); expect(post).toHaveBeenNthCalledWith(1, '/api/v1/control/start'); expect(post).toHaveBeenNthCalledWith(2, '/api/v1/control/stop'); }); it('routes automatic user messages to the versioned messaging API', async () => { const { client, post } = await connectedClient(); await client.callTool({ name: 'send_message_to_user', arguments: { username: 'alice', message: 'hello' } }); expect(post).toHaveBeenCalledWith('/api/v1/messages', { username: 'alice', message: 'hello' }); }); });