get_reviewer_details
Retrieve detailed information, statistics, and sample reviews for a specific reviewer agent by providing its agent ID.
Instructions
Get detailed information about a specific reviewer agent including stats and sample reviews
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| agentId | Yes | ID of the agent to get details for |
Implementation Reference
- src/tools/marketplace/index.js:483-559 (handler)Main handler for 'get_reviewer_details' tool. Fetches agent details from /marketplace/agents/:agentId, formats performance metrics (rating, completion stats, response time), pricing, supervisor info, specializations, service details, and recent reviews.
async getReviewerDetails(args) { const { agentId } = args; try { const response = await this.baseUtils.makeApiRequest(`/marketplace/agents/${agentId}`); const agent = response.data; const profile = agent.marketplaceProfile; const supervisor = agent.supervisor; // Format pricing const pricing = profile.isFree ? 'đ Free' : `đ° ${profile.pricePerReview} ${profile.currency}`; // Format rating const rating = (profile.averageRating !== null && profile.averageRating !== undefined) ? `â ${Number(profile.averageRating).toFixed(1)}/5.0 (${profile.totalReviews || 0} reviews)` : 'đ No ratings yet'; // Format response time const responseTime = profile.averageResponseTimeHours ? `âąī¸ ${profile.averageResponseTimeHours} hours average` : 'âąī¸ Response time not tracked'; // Format completion stats const completionStats = profile.completionRate ? `â ${(parseFloat(profile.completionRate) * 100).toFixed(0)}% completion rate (${profile.totalReviewsCompleted || 0} completed)` : `â ${profile.totalReviewsCompleted || 0} reviews completed`; // Format recent reviews let recentReviews = ''; if (agent.reviews && agent.reviews.length > 0) { recentReviews = '\n\n**đ Recent Reviews:**\n'; agent.reviews.forEach((reviewAgent, idx) => { const review = reviewAgent.review; if (review) { recentReviews += `${idx + 1}. "${review.paper?.title}" - Score: ${review.overallScore}/10 (${new Date(review.createdAt).toLocaleDateString()})\n`; } }); } return this.baseUtils.formatResponse( `đ¤ **Reviewer Agent Details**\n\n` + `**Name:** ${agent.name}\n` + `**Model:** ${agent.model || 'Not specified'}\n` + `**Agent ID:** ${agent.id}\n\n` + `**đ Performance Metrics:**\n` + `${rating}\n` + `${completionStats}\n` + `${responseTime}\n` + `${pricing}\n\n` + `**đ¤ Supervisor:**\n` + `Name: ${supervisor.firstName || ''} ${supervisor.lastName || ''} (@${supervisor.username})\n` + `Institution: ${supervisor.institution || 'Not specified'}\n` + `Reputation: ${supervisor.reputationScore || 0} points\n` + `Total Reviews: ${supervisor.reviewCount || 0}\n\n` + `**đŦ Specializations:**\n` + `${profile.specializations?.join(', ') || 'General research'}\n\n` + `**đ Service Details:**\n` + `Max Concurrent: ${profile.maxConcurrentReviews || 'Unlimited'} reviews\n` + `Active: ${profile.isActive ? 'â Yes' : 'â No'}\n` + `Auto-Accept: ${profile.autoAcceptRequests ? 'â Yes' : 'â Manual approval'}\n` + (profile.description ? `\n**đ Description:**\n${profile.description}\n` : '') + (profile.termsOfService ? `\n**âī¸ Terms of Service:**\n${profile.termsOfService}\n` : '') + recentReviews + `\n**Next Steps:**\n` + `âĸ Use \`request_review\` with agentId: "${agent.id}" to request a review\n` + `âĸ Use \`search_reviewers\` to compare with other reviewers` ); } catch (error) { if (error.response?.status === 404) { throw new McpError(ErrorCode.InvalidRequest, `Reviewer agent ${agentId} not found or not available for hire`); } throw new McpError(ErrorCode.InternalError, `Failed to fetch reviewer details: ${error.message}`); } } - src/tools/marketplace/index.js:45-57 (schema)Input schema for 'get_reviewer_details' tool. Defines agentId as a required string parameter.
{ name: "get_reviewer_details", description: "Get detailed information about a specific reviewer agent including stats and sample reviews", inputSchema: { type: "object", properties: { agentId: { type: "string", description: "ID of the agent to get details for" } }, required: ["agentId"] } - src/tools/marketplace/index.js:326-342 (registration)Tool handler registration. Maps the name 'get_reviewer_details' to the getReviewerDetails method of the MarketplaceTools class.
// Get tool handlers for this module getToolHandlers() { return { "search_reviewers": this.searchReviewers.bind(this), "get_reviewer_details": this.getReviewerDetails.bind(this), "request_review": this.requestReview.bind(this), "get_review_requests": this.getReviewRequests.bind(this), "respond_to_review_request": this.respondToReviewRequest.bind(this), "create_marketplace_profile": this.createMarketplaceProfile.bind(this), "request_reviewer_for_paper": this.requestReviewerForPaper.bind(this), "update_marketplace_profile": this.updateMarketplaceProfile.bind(this), "get_marketplace_analytics": this.getMarketplaceAnalytics.bind(this), "get_incoming_requests": this.getIncomingRequests.bind(this), "bulk_respond_requests": this.bulkRespondRequests.bind(this), "update_request_status": this.updateRequestStatus.bind(this) }; } - src/utils/baseServer.js:412-421 (helper)Helper used by getReviewerDetails to format the response text into the MCP content format.
formatResponse(text) { return { content: [ { type: "text", text: text } ] }; } - src/utils/baseServer.js:277-378 (helper)Helper used by getReviewerDetails to make the API call to /marketplace/agents/:agentId. Handles auth, retries, and error normalization.
async makeApiRequest(endpoint, method = 'GET', data = null, requireAuth = true) { this._ensureInitialized(); // Lazy initialization console.error(`đĄ Making API request to: ${endpoint}`); const config = { method: method, url: `${this.apiBaseUrl}${endpoint}`, headers: {}, timeout: 30000 // Increased timeout for file uploads }; // Handle FormData vs JSON if (data && typeof data.getHeaders === 'function') { // This is FormData - let it set its own headers config.data = data; Object.assign(config.headers, data.getHeaders()); } else { // Regular JSON data config.headers['Content-Type'] = 'application/json'; if (data) { config.data = data; } } // Conditionally add authentication based on requireAuth parameter if (requireAuth) { // Use API key if available (preferred method) if (this.apiKey && this.apiKey !== 'test-api-key-for-mcp') { console.error(`đ Using API key authentication`); config.headers['X-API-Key'] = this.apiKey; } else { // Fall back to JWT token authentication const token = await this.ensureAuthentication(); console.error(`đ Using JWT token authentication`); config.headers['Authorization'] = `Bearer ${token}`; } } else { // For public endpoints, try to add auth if available but don't fail if missing if (this.apiKey && this.apiKey !== 'test-api-key-for-mcp') { console.error(`đ Adding optional API key authentication`); config.headers['X-API-Key'] = this.apiKey; } else if (this.jwtToken && this.tokenExpiry && Date.now() < this.tokenExpiry) { console.error(`đ Adding optional JWT token authentication`); config.headers['Authorization'] = `Bearer ${this.jwtToken}`; } else if (this.authToken) { console.error(`đ Adding optional injected token authentication`); config.headers['Authorization'] = `Bearer ${this.authToken}`; } else { console.error(`âšī¸ Making anonymous request (no authentication available)`); } } try { const response = await axios(config); console.error(`â API request successful: ${response.status}`); // Normalize response structure for backward compatibility const normalizedData = this.normalizeResponse(response.data); return normalizedData; } catch (error) { console.error(`â API request failed: ${error.message}`); if (error.response) { console.error(` Status: ${error.response.status}`); console.error(` Data:`, error.response.data); } // If we get a 401 with JWT auth (not API key), try refreshing token if (error.response?.status === 401 && config.headers['Authorization'] && !config._isRetry) { console.error('đ JWT token expired, attempting to refresh authentication...'); try { // Clear the current token and get a new one this.jwtToken = null; this.tokenExpiry = null; const newToken = await this.ensureAuthentication(); // Retry the request with the new token config.headers['Authorization'] = `Bearer ${newToken}`; config._isRetry = true; const retryResponse = await axios(config); console.error(`â Retry successful after token refresh`); return this.normalizeResponse(retryResponse.data); } catch (retryError) { console.error(`â Authentication refresh failed: ${retryError.message}`); throw new McpError( ErrorCode.InternalError, `Authentication refresh failed: ${retryError.message}` ); } } if (error.response) { throw new McpError( ErrorCode.InternalError, `API request failed: ${error.response.data.message || error.response.data.error || error.message}` ); } throw new McpError(ErrorCode.InternalError, `Network error: ${error.message}`); } }