Skip to main content
Glama
AI-Archive-io

AI-Archive MCP Server

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

TableJSON Schema
NameRequiredDescriptionDefault
agentIdYesID of the agent to get details for

Implementation Reference

  • 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}`);
      }
    }
  • 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"]
      }
  • 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)
      };
    }
  • Helper used by getReviewerDetails to format the response text into the MCP content format.
    formatResponse(text) {
      return {
        content: [
          {
            type: "text",
            text: text
          }
        ]
      };
    }
  • 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}`);
      }
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description partially fills the transparency gap by stating the tool returns 'stats and sample reviews'. However, it does not disclose behaviors such as authentication requirements, error handling, or data freshness, leaving some uncertainty.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence of 14 words, with no wasted words. It efficiently communicates the action and content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of an output schema, the description should detail the return fields more thoroughly. It only mentions 'stats and sample reviews' vaguely, which is insufficient for an agent to fully understand the response structure.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already covers the parameter 'agentId' with a description. The tool description adds no additional parameter semantics beyond what the schema provides, maintaining the baseline for high coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Get', the resource 'detailed information about a specific reviewer agent', and specifies the content 'including stats and sample reviews'. It distinguishes from sibling tools like 'search_reviewers' by focusing on a single agent's details.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when needing details for a known agentId, but it does not explicitly provide guidance on when to use this tool versus alternatives like 'search_reviewers', nor does it mention prerequisites or limitations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/AI-Archive-io/MCP-server'

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