Skip to main content
Glama
2389-research

MCP Agent Social Media Server

end-to-end.test.ts14.6 kB
// ABOUTME: End-to-end integration tests for complete workflows // ABOUTME: Tests full agent interactions including login, posting, and replies import { afterEach, beforeEach, describe, expect, it, jest } from '@jest/globals'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import type { ApiClient } from '../../src/api-client.js'; import { config } from '../../src/config.js'; import { logger } from '../../src/logger.js'; import { metrics } from '../../src/metrics.js'; import { SessionManager } from '../../src/session-manager.js'; import { createPostToolHandler } from '../../src/tools/create-post.js'; import { loginToolHandler } from '../../src/tools/login.js'; import { readPostsToolHandler } from '../../src/tools/read-posts.js'; describe('End-to-End Integration Tests', () => { let sessionManager: SessionManager; let apiClient: jest.Mocked<ApiClient>; let sessionId: string; let mockPosts: Array<{ id: string; content: string; author_name: string; timestamp: string; thread_id?: string; }>; let postIdCounter: number; let networkFailure: boolean; beforeEach(() => { // Reset environment process.env.TEAM_NAME = 'test-team'; process.env.LOG_LEVEL = 'DEBUG'; // Initialize state mockPosts = []; postIdCounter = 0; networkFailure = false; // Initialize components sessionManager = new SessionManager(); apiClient = { fetchPosts: jest.fn(), createPost: jest.fn(), } as jest.Mocked<ApiClient>; // Set up mock responses that simulate a real API with persistent state apiClient.fetchPosts.mockImplementation(async (_teamName, options) => { if (networkFailure) { throw new Error('Network error during validation'); } let filteredPosts = [...mockPosts]; // Apply filters if (options?.agent_filter) { filteredPosts = filteredPosts.filter((p) => p.author_name === options.agent_filter); } if (options?.tag_filter) { filteredPosts = filteredPosts.filter((p) => p.tags?.includes(options.tag_filter)); } if (options?.thread_id) { // Include the thread root and all replies filteredPosts = filteredPosts.filter( (p) => p.id === options.thread_id || p.parent_post_id === options.thread_id, ); } const limit = options?.limit || 10; const offset = options?.offset || 0; const paginatedPosts = filteredPosts.slice(offset, offset + limit); return { posts: paginatedPosts, total: filteredPosts.length, has_more: offset + limit < filteredPosts.length, }; }); apiClient.createPost.mockImplementation(async (teamName, postData) => { if (networkFailure) { throw new Error('Network error'); } const newPost = { id: `post-${Date.now()}-${++postIdCounter}`, team_name: teamName, author_name: postData.author_name, content: postData.content, tags: postData.tags || [], timestamp: new Date().toISOString(), parent_post_id: postData.parent_post_id, deleted: false, }; // Add to mock posts array to simulate persistence mockPosts.push(newPost); return { post: newPost }; }); sessionId = `test-session-${Date.now()}`; // Reset metrics metrics.reset(); }); afterEach(async () => { // Clean up await sessionManager.clearAllSessions(); }); describe('Complete Agent Workflow', () => { it('should handle complete workflow: login → read → create → read updated', async () => { logger.info('Starting complete agent workflow test'); // Step 1: Login const loginContext = { sessionManager, getSessionId: () => sessionId, }; const loginResult = await loginToolHandler({ agent_name: 'test-agent' }, loginContext); const loginResponse = JSON.parse(loginResult.content[0].text); expect(loginResponse.success).toBe(true); expect(loginResponse.agent_name).toBe('test-agent'); expect(loginResponse.team_name).toBe(config.teamName); logger.info('Login successful', { agent_name: 'test-agent' }); // Step 2: Read initial posts const readContext = { apiClient, }; const initialReadResult = await readPostsToolHandler({}, readContext); const initialPosts = JSON.parse(initialReadResult.content[0].text); expect(initialPosts.posts).toBeDefined(); const initialPostCount = initialPosts.posts.length; logger.info('Initial post count', { count: initialPostCount }); // Step 3: Create a new post const createContext = { sessionManager, apiClient, getSessionId: () => sessionId, }; const createResult = await createPostToolHandler( { content: 'Integration test post', tags: ['test', 'integration'], }, createContext, ); const createResponse = JSON.parse(createResult.content[0].text); expect(createResponse.success).toBe(true); expect(createResponse.post).toBeDefined(); expect(createResponse.post.team_name).toBe(config.teamName); const newPostId = createResponse.post.id; logger.info('Post created', { postId: newPostId }); // Step 4: Read updated feed const updatedReadResult = await readPostsToolHandler({}, readContext); const updatedPosts = JSON.parse(updatedReadResult.content[0].text); expect(updatedPosts.posts.length).toBe(initialPostCount + 1); // Verify our post is in the feed const ourPost = updatedPosts.posts.find((p: { id: string }) => p.id === newPostId); expect(ourPost).toBeDefined(); expect(ourPost.content).toBe('Integration test post'); expect(ourPost.author_name).toBe('test-agent'); expect(ourPost.team_name).toBe(config.teamName); logger.info('Post verified in feed'); }); }); describe('Reply Workflow', () => { it('should handle reply workflow: login → read → create reply → verify threading', async () => { logger.info('Starting reply workflow test'); // Setup: Add a parent post to mock posts array const parentPost = { id: 'parent-post-integration', team_name: config.teamName, author_name: 'other-agent', content: 'Parent post for replies', tags: ['discussion'], timestamp: new Date().toISOString(), }; mockPosts.push(parentPost); // Step 1: Login const loginContext = { sessionManager, getSessionId: () => sessionId, }; await loginToolHandler({ agent_name: 'reply-agent' }, loginContext); // Step 2: Read posts to find parent const readContext = { apiClient, }; const readResult = await readPostsToolHandler({}, readContext); const posts = JSON.parse(readResult.content[0].text); const foundParent = posts.posts.find((p: { id: string }) => p.id === parentPost.id); expect(foundParent).toBeDefined(); // Step 3: Create reply const createContext = { sessionManager, apiClient, getSessionId: () => sessionId, }; const replyResult = await createPostToolHandler( { content: 'This is a reply to the parent post', parent_post_id: parentPost.id, }, createContext, ); const replyResponse = JSON.parse(replyResult.content[0].text); expect(replyResponse.success).toBe(true); expect(replyResponse.post.parent_post_id).toBe(parentPost.id); const replyId = replyResponse.post.id; // Step 4: Verify threading with thread_id filter const threadResult = await readPostsToolHandler({ thread_id: parentPost.id }, readContext); const threadPosts = JSON.parse(threadResult.content[0].text); expect(threadPosts.posts.length).toBeGreaterThanOrEqual(2); // Should include both parent and reply const hasParent = threadPosts.posts.some((p: { id: string }) => p.id === parentPost.id); const hasReply = threadPosts.posts.some((p: { id: string }) => p.id === replyId); expect(hasParent).toBe(true); expect(hasReply).toBe(true); logger.info('Reply thread verified', { parentId: parentPost.id, replyId, threadSize: threadPosts.posts.length, }); }); }); describe('Error Scenarios', () => { it('should handle API failures gracefully', async () => { logger.info('Testing API failure handling'); // Login first const loginContext = { sessionManager, getSessionId: () => sessionId, }; await loginToolHandler({ agent_name: 'error-test-agent' }, loginContext); // Simulate API failure networkFailure = true; // Try to create post const createContext = { sessionManager, apiClient, getSessionId: () => sessionId, }; const result = await createPostToolHandler({ content: 'This should fail' }, createContext); const response = JSON.parse(result.content[0].text); expect(response.success).toBe(false); expect(response.error).toBe('Failed to create post'); logger.warn('API failure handled correctly'); // Reset API networkFailure = false; }); it('should enforce session requirements', async () => { logger.info('Testing session validation'); // Try to create post without login const createContext = { sessionManager, apiClient, getSessionId: () => 'no-session', }; const result = await createPostToolHandler({ content: 'Unauthorized post' }, createContext); const response = JSON.parse(result.content[0].text); expect(response.success).toBe(false); expect(response.error).toBe('Authentication required'); logger.info('Session validation working correctly'); }); }); describe('Multi-Agent Scenarios', () => { it('should handle multiple agents posting and reading', async () => { logger.info('Testing multi-agent scenario'); const agents = ['alice', 'bob', 'charlie']; const sessions: Record<string, string> = {}; // All agents login for (const agent of agents) { const agentSessionId = `session-${agent}`; sessions[agent] = agentSessionId; const loginContext = { sessionManager, getSessionId: () => agentSessionId, }; await loginToolHandler({ agent_name: agent }, loginContext); logger.debug(`Agent ${agent} logged in`); } // Each agent creates a post const postIds: string[] = []; for (const agent of agents) { const createContext = { sessionManager, apiClient, getSessionId: () => sessions[agent], }; const result = await createPostToolHandler( { content: `Post from ${agent}`, tags: [agent, 'multi-agent-test'], }, createContext, ); const response = JSON.parse(result.content[0].text); expect(response.success).toBe(true); expect(response.post.team_name).toBe(config.teamName); postIds.push(response.post.id); logger.debug(`Agent ${agent} created post ${response.post.id}`); } // Read all posts with agent filter const readContext = { apiClient, }; for (const agent of agents) { const result = await readPostsToolHandler({ agent_filter: agent }, readContext); const response = JSON.parse(result.content[0].text); const agentPosts = response.posts.filter( (p: { author_name: string }) => p.author_name === agent, ); expect(agentPosts.length).toBeGreaterThanOrEqual(1); logger.debug(`Found ${agentPosts.length} posts by ${agent}`); } // Create a conversation thread const alicePost = postIds[0]; // Bob replies to Alice const bobReplyContext = { sessionManager, apiClient, getSessionId: () => sessions.bob, }; const bobReply = await createPostToolHandler( { content: 'Reply from Bob to Alice', parent_post_id: alicePost, }, bobReplyContext, ); const bobReplyResponse = JSON.parse(bobReply.content[0].text); expect(bobReplyResponse.success).toBe(true); // Charlie replies to Bob's reply const charlieReplyContext = { sessionManager, apiClient, getSessionId: () => sessions.charlie, }; const charlieReply = await createPostToolHandler( { content: 'Reply from Charlie to Bob', parent_post_id: bobReplyResponse.post.id, }, charlieReplyContext, ); const charlieReplyResponse = JSON.parse(charlieReply.content[0].text); expect(charlieReplyResponse.success).toBe(true); logger.info('Multi-agent conversation created successfully'); }); }); describe('Performance Monitoring', () => { it('should track operation metrics', async () => { logger.info('Testing performance monitoring'); // Reset metrics to ensure clean state metrics.reset(); // Perform several operations const loginContext = { sessionManager, getSessionId: () => sessionId, }; // Login - the handler already tracks metrics internally await loginToolHandler({ agent_name: 'metrics-agent' }, loginContext); // Create posts const createContext = { sessionManager, apiClient, getSessionId: () => sessionId, }; for (let i = 0; i < 5; i++) { await createPostToolHandler({ content: `Performance test post ${i}` }, createContext); } // Read posts const readContext = { apiClient, }; await readPostsToolHandler({ limit: 20 }, readContext); // Check metrics const loginMetrics = metrics.getOperationMetrics('login'); expect(loginMetrics).toBeDefined(); expect(loginMetrics?.count).toBe(1); expect(loginMetrics?.errors).toBe(0); const systemMetrics = metrics.getSystemMetrics(); expect(systemMetrics.uptime).toBeGreaterThanOrEqual(0); expect(systemMetrics.memoryUsage).toBeDefined(); expect(systemMetrics.memoryUsage.rss).toBeGreaterThan(0); logger.info(`Metrics summary:\n${metrics.getSummary()}`); }); }); });

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/2389-research/mcp-socialmedia'

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