Skip to main content
Glama
mkXultra
by mkXultra
MockToolRegistry.ts15.2 kB
import { vi } from 'vitest'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { JSONRPCRequest, JSONRPCResponse, McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import { MockDataLayer } from './MockDataLayer.js'; import { AppError, RoomNotFoundError, AgentNotInRoomError, RoomAlreadyExistsError, ValidationError, toMCPError } from '../../src/errors/index.js'; export class MockToolRegistry { constructor(private dataLayer: MockDataLayer) {} async registerAll(server: Server): Promise<void> { // Define the request schemas const listToolsRequestSchema = z.object({ method: z.literal('tools/list'), params: z.object({ _meta: z.optional(z.object({})) }).optional() }); const callToolRequestSchema = z.object({ method: z.literal('tools/call'), params: z.object({ name: z.string(), arguments: z.any(), _meta: z.optional(z.object({})) }) }); // Register all 9 tools from spec.md server.setRequestHandler(listToolsRequestSchema, async (request) => ({ tools: [ { name: 'agent_communication_list_rooms', description: 'List all available rooms', inputSchema: { type: 'object', properties: {}, additionalProperties: false } }, { name: 'agent_communication_create_room', description: 'Create a new room', inputSchema: { type: 'object', properties: { roomName: { type: 'string' }, description: { type: 'string' } }, required: ['roomName'], additionalProperties: false } }, { name: 'agent_communication_enter_room', description: 'Enter a room', inputSchema: { type: 'object', properties: { agentName: { type: 'string' }, roomName: { type: 'string' } }, required: ['agentName', 'roomName'], additionalProperties: false } }, { name: 'agent_communication_leave_room', description: 'Leave a room', inputSchema: { type: 'object', properties: { agentName: { type: 'string' }, roomName: { type: 'string' } }, required: ['agentName', 'roomName'], additionalProperties: false } }, { name: 'agent_communication_list_room_users', description: 'List users in a room', inputSchema: { type: 'object', properties: { roomName: { type: 'string' } }, required: ['roomName'], additionalProperties: false } }, { name: 'agent_communication_send_message', description: 'Send a message to a room', inputSchema: { type: 'object', properties: { agentName: { type: 'string' }, roomName: { type: 'string' }, message: { type: 'string' } }, required: ['agentName', 'roomName', 'message'], additionalProperties: false } }, { name: 'agent_communication_get_messages', description: 'Get messages from a room', inputSchema: { type: 'object', properties: { agentName: { type: 'string' }, roomName: { type: 'string' }, limit: { type: 'number' }, before: { type: 'string' }, offset: { type: 'number' } }, required: ['agentName', 'roomName'], additionalProperties: false } }, { name: 'agent_communication_get_status', description: 'Get server status', inputSchema: { type: 'object', properties: {}, additionalProperties: false } }, { name: 'agent_communication_clear_room_messages', description: 'Clear all messages in a room', inputSchema: { type: 'object', properties: { roomName: { type: 'string' } }, required: ['roomName'], additionalProperties: false } } ] })); server.setRequestHandler(callToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { // Validate that the tool exists const validTools = [ 'agent_communication_list_rooms', 'agent_communication_create_room', 'agent_communication_enter_room', 'agent_communication_leave_room', 'agent_communication_list_room_users', 'agent_communication_send_message', 'agent_communication_get_messages', 'agent_communication_get_status', 'agent_communication_clear_room_messages' ]; if (!validTools.includes(name)) { throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } // Basic input validation for required fields switch (name) { case 'agent_communication_create_room': if (!args?.roomName || typeof args.roomName !== 'string' || args.roomName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Room name cannot be empty'); } // Validate room name format (alphanumeric, hyphens, underscores only) if (!/^[a-zA-Z0-9-_]+$/.test(args.roomName)) { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Room name must contain only alphanumeric characters, hyphens, and underscores'); } // Validate room name length if (args.roomName.length > 50) { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Room name cannot exceed 50 characters'); } break; case 'agent_communication_enter_room': case 'agent_communication_leave_room': if (!args?.agentName || typeof args.agentName !== 'string' || args.agentName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Agent name cannot be empty'); } if (!args?.roomName || typeof args.roomName !== 'string' || args.roomName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Room name cannot be empty'); } break; case 'agent_communication_send_message': if (!args?.agentName || typeof args.agentName !== 'string' || args.agentName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Agent name cannot be empty'); } if (!args?.roomName || typeof args.roomName !== 'string' || args.roomName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Room name cannot be empty'); } if (!args?.message || typeof args.message !== 'string') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Message cannot be empty'); } break; case 'agent_communication_get_messages': if (!args?.agentName || typeof args.agentName !== 'string' || args.agentName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Agent name cannot be empty'); } if (!args?.roomName || typeof args.roomName !== 'string' || args.roomName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Room name cannot be empty'); } if (args.limit !== undefined && (typeof args.limit !== 'number' || args.limit < 1 || args.limit > 1000)) { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Limit must be between 1 and 1000'); } if (args.before !== undefined && typeof args.before !== 'string') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Before parameter must be a string'); } break; case 'agent_communication_list_room_users': case 'agent_communication_clear_room_messages': if (!args?.roomName || typeof args.roomName !== 'string' || args.roomName.trim() === '') { throw new McpError(ErrorCode.InvalidParams, 'Validation error: Room name cannot be empty'); } break; } switch (name) { case 'agent_communication_list_rooms': return { content: [{ type: 'text', text: JSON.stringify({ rooms: this.dataLayer.getAllRooms() }) }] }; case 'agent_communication_create_room': if (this.dataLayer.roomExists(args.roomName)) { throw new RoomAlreadyExistsError(args.roomName); } const room = { name: args.roomName, description: args.description || '', createdAt: new Date().toISOString(), messageCount: 0 }; this.dataLayer.createRoom(room); return { content: [{ type: 'text', text: JSON.stringify({ success: true, roomName: args.roomName }) }] }; case 'agent_communication_enter_room': if (!this.dataLayer.roomExists(args.roomName)) { throw new RoomNotFoundError(args.roomName); } this.dataLayer.addAgentToRoom(args.roomName, args.agentName); return { content: [{ type: 'text', text: JSON.stringify({ success: true }) }] }; case 'agent_communication_leave_room': if (!this.dataLayer.roomExists(args.roomName)) { throw new RoomNotFoundError(args.roomName); } const roomAgents = this.dataLayer.getRoomAgents(args.roomName); if (!roomAgents.includes(args.agentName)) { throw new AgentNotInRoomError(args.agentName, args.roomName); } this.dataLayer.removeAgentFromRoom(args.roomName, args.agentName); return { content: [{ type: 'text', text: JSON.stringify({ success: true }) }] }; case 'agent_communication_list_room_users': if (!this.dataLayer.roomExists(args.roomName)) { throw new RoomNotFoundError(args.roomName); } const agents = this.dataLayer.getRoomAgents(args.roomName); return { content: [{ type: 'text', text: JSON.stringify({ agents }) }] }; case 'agent_communication_send_message': if (!this.dataLayer.roomExists(args.roomName)) { throw new RoomNotFoundError(args.roomName); } const roomUsers = this.dataLayer.getRoomAgents(args.roomName); if (!roomUsers.includes(args.agentName)) { throw new AgentNotInRoomError(args.agentName, args.roomName); } // Extract mentions const mentions = (args.message.match(/@(\w+)/g) || []).map((m: string) => m.slice(1)); const message = { id: `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, agentName: args.agentName, roomName: args.roomName, message: args.message, timestamp: new Date().toISOString(), mentions }; this.dataLayer.addMessage(args.roomName, message); return { content: [{ type: 'text', text: JSON.stringify({ success: true, messageId: message.id, mentions }) }] }; case 'agent_communication_get_messages': if (!this.dataLayer.roomExists(args.roomName)) { throw new RoomNotFoundError(args.roomName); } const currentAgents = this.dataLayer.getRoomAgents(args.roomName); if (!currentAgents.includes(args.agentName)) { throw new AgentNotInRoomError(args.agentName, args.roomName); } const messages = this.dataLayer.getMessages(args.roomName, args.limit, args.before, args.offset); return { content: [{ type: 'text', text: JSON.stringify({ messages }) }] }; case 'agent_communication_get_status': const stats = this.dataLayer.getSystemStats(); const rooms = this.dataLayer.getAllRooms().map(room => { const roomStats = this.dataLayer.getRoomStats(room.name); return { name: room.name, description: room.description, messageCount: roomStats.messageCount, activeAgents: roomStats.activeAgents, lastActivity: roomStats.lastActivity }; }); const fullStats = { totalRooms: stats.totalRooms, totalMessages: stats.totalMessages, activeAgents: stats.activeAgents, uptime: stats.uptime, serverVersion: stats.serverVersion, rooms }; return { content: [{ type: 'text', text: JSON.stringify(fullStats) }] }; case 'agent_communication_clear_room_messages': if (!args.confirm || args.confirm !== true) { throw new ValidationError('Confirmation required: confirm must be set to true'); } if (!this.dataLayer.roomExists(args.roomName)) { throw new RoomNotFoundError(args.roomName); } const clearedCount = this.dataLayer.clearMessages(args.roomName); return { content: [{ type: 'text', text: JSON.stringify({ success: true, roomName: args.roomName, clearedCount }) }] }; default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error) { // If it's already a McpError, just throw it if (error instanceof McpError) { throw error; } // Convert AppError to McpError if (error instanceof AppError) { // Map HTTP status codes to MCP error codes // 404 for resources (rooms, agents) should be InvalidParams, not MethodNotFound const errorCode = error.statusCode >= 400 && error.statusCode < 500 ? ErrorCode.InvalidParams : ErrorCode.InternalError; throw new McpError( errorCode, error.message, { errorCode: error.code } ); } // Handle any other errors throw new McpError( ErrorCode.InternalError, error instanceof Error ? error.message : 'Internal server error', { errorCode: 'INTERNAL_ERROR' } ); } }); } }

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/mkXultra/agent-communication-mcp'

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