Skip to main content
Glama
flyanima

Open Search MCP

by flyanima

pubmed_article_details

Retrieve comprehensive details for specific PubMed articles using their PMID identifiers to access publication information, abstracts, and metadata.

Instructions

Get detailed information about a specific PubMed article

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pmidYesPubMed ID (PMID) of the article

Implementation Reference

  • The main handler function that executes the tool logic: fetches article summary via PubMed ESummary API, attempts to fetch full abstract, constructs detailed article object with metadata.
    execute: async (args: any) => {
      const { pmid } = args;
    
      try {
        // 获取文章摘要信息
        const summaryParams = {
          db: 'pubmed',
          id: pmid,
          retmode: 'json'
        };
    
        const summaryResult = await client.makeRequest('esummary.fcgi', summaryParams);
    
        if (!summaryResult.result || !summaryResult.result[pmid]) {
          return {
            success: false,
            error: `Article with PMID ${pmid} not found`
          };
        }
    
        const article = summaryResult.result[pmid];
    
        // 尝试获取全文摘要
        let fullAbstract = null;
        try {
          const fetchParams = {
            db: 'pubmed',
            id: pmid,
            retmode: 'xml',
            rettype: 'abstract'
          };
    
          const fetchResult = await client.makeRequest('efetch.fcgi', fetchParams);
          // 这里可以解析XML获取完整摘要,暂时使用summary中的摘要
          fullAbstract = article.abstract || 'No abstract available';
        } catch (fetchError) {
          fullAbstract = article.abstract || 'No abstract available';
        }
    
        const articleDetails = {
          pmid: article.uid,
          title: article.title || 'No title available',
          abstract: fullAbstract,
          authors: (article.authors || []).map((author: any) => ({
            name: author.name,
            affiliation: author.affiliation || null
          })),
          journal: {
            name: article.fulljournalname || article.source || 'Unknown journal',
            abbreviation: article.source || null,
            volume: article.volume || null,
            issue: article.issue || null,
            pages: article.pages || null
          },
          publicationDate: article.pubdate || 'Unknown date',
          publicationType: (article.pubtype || []).join(', ') || 'Unknown type',
          doi: article.elocationid && article.elocationid.includes('doi:')
            ? article.elocationid.replace('doi: ', '')
            : null,
          pmcid: article.pmcid || null,
          meshTerms: article.keywords || [],
          url: `https://pubmed.ncbi.nlm.nih.gov/${article.uid}/`,
          fullTextUrl: article.pmcid ? `https://www.ncbi.nlm.nih.gov/pmc/articles/${article.pmcid}/` : null,
          citationCount: null, // PubMed API不直接提供引用数
          source: 'PubMed'
        };
    
        return {
          success: true,
          data: {
            source: 'PubMed API',
            article: articleDetails,
            timestamp: Date.now(),
            apiUsed: true
          }
        };
      } catch (error) {
        return {
          success: false,
          error: `Failed to get PubMed article details: ${error instanceof Error ? error.message : String(error)}`
        };
      }
    }
  • Input schema defining the required 'pmid' parameter as a string.
    inputSchema: {
      type: 'object',
      properties: {
        pmid: {
          type: 'string',
          description: 'PubMed ID (PMID) of the article'
        }
      },
      required: ['pmid']
    },
  • Tool registration call within registerPubMedTools function, including name, description, schema, and handler reference.
    registry.registerTool({
      name: 'pubmed_article_details',
      description: 'Get detailed information about a specific PubMed article',
      category: 'academic',
      source: 'PubMed',
      inputSchema: {
        type: 'object',
        properties: {
          pmid: {
            type: 'string',
            description: 'PubMed ID (PMID) of the article'
          }
        },
        required: ['pmid']
      },
      execute: async (args: any) => {
        const { pmid } = args;
    
        try {
          // 获取文章摘要信息
          const summaryParams = {
            db: 'pubmed',
            id: pmid,
            retmode: 'json'
          };
    
          const summaryResult = await client.makeRequest('esummary.fcgi', summaryParams);
    
          if (!summaryResult.result || !summaryResult.result[pmid]) {
            return {
              success: false,
              error: `Article with PMID ${pmid} not found`
            };
          }
    
          const article = summaryResult.result[pmid];
    
          // 尝试获取全文摘要
          let fullAbstract = null;
          try {
            const fetchParams = {
              db: 'pubmed',
              id: pmid,
              retmode: 'xml',
              rettype: 'abstract'
            };
    
            const fetchResult = await client.makeRequest('efetch.fcgi', fetchParams);
            // 这里可以解析XML获取完整摘要,暂时使用summary中的摘要
            fullAbstract = article.abstract || 'No abstract available';
          } catch (fetchError) {
            fullAbstract = article.abstract || 'No abstract available';
          }
    
          const articleDetails = {
            pmid: article.uid,
            title: article.title || 'No title available',
            abstract: fullAbstract,
            authors: (article.authors || []).map((author: any) => ({
              name: author.name,
              affiliation: author.affiliation || null
            })),
            journal: {
              name: article.fulljournalname || article.source || 'Unknown journal',
              abbreviation: article.source || null,
              volume: article.volume || null,
              issue: article.issue || null,
              pages: article.pages || null
            },
            publicationDate: article.pubdate || 'Unknown date',
            publicationType: (article.pubtype || []).join(', ') || 'Unknown type',
            doi: article.elocationid && article.elocationid.includes('doi:')
              ? article.elocationid.replace('doi: ', '')
              : null,
            pmcid: article.pmcid || null,
            meshTerms: article.keywords || [],
            url: `https://pubmed.ncbi.nlm.nih.gov/${article.uid}/`,
            fullTextUrl: article.pmcid ? `https://www.ncbi.nlm.nih.gov/pmc/articles/${article.pmcid}/` : null,
            citationCount: null, // PubMed API不直接提供引用数
            source: 'PubMed'
          };
    
          return {
            success: true,
            data: {
              source: 'PubMed API',
              article: articleDetails,
              timestamp: Date.now(),
              apiUsed: true
            }
          };
        } catch (error) {
          return {
            success: false,
            error: `Failed to get PubMed article details: ${error instanceof Error ? error.message : String(error)}`
          };
        }
      }
    });
  • PubMedAPIClient class providing makeRequest method used by the handler to query PubMed EUtils APIs.
    class PubMedAPIClient {
      private baseURL = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils';
      private apiKey: string | undefined;
    
      constructor(apiKey?: string) {
        this.apiKey = apiKey;
      }
    
      async makeRequest(endpoint: string, params: Record<string, any> = {}) {
        try {
          const requestParams = {
            ...params,
            retmode: 'json',
            retmax: Math.min(params.retmax || 20, 200),
            tool: 'open-search-mcp',
            email: 'support@open-search-mcp.com'
          };
    
          if (this.apiKey) {
            (requestParams as any).api_key = this.apiKey;
          }
    
          const response = await axios.get(`${this.baseURL}/${endpoint}`, {
            params: requestParams,
            timeout: 20000,
            headers: {
              'User-Agent': 'Open-Search-MCP/2.0'
            }
          });
    
          return response.data;
        } catch (error) {
          throw error;
        }
      }
    
      async searchPubMed(query: string, options: any = {}) {
        // 第一步:搜索获取PMID列表
        const searchParams = {
          db: 'pubmed',
          term: query,
          retmax: options.maxResults || 20,
          sort: options.sort === 'date' ? 'pub_date' : 'relevance',
          datetype: 'pdat'
        };
    
        // 添加日期过滤
        if (options.dateRange && options.dateRange !== 'all') {
          const now = new Date();
          let startDate;
    
          switch (options.dateRange) {
            case '1year':
              startDate = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
              break;
            case '5years':
              startDate = new Date(now.getFullYear() - 5, now.getMonth(), now.getDate());
              break;
            case '10years':
              startDate = new Date(now.getFullYear() - 10, now.getMonth(), now.getDate());
              break;
          }
    
          if (startDate) {
            const startDateStr = startDate.toISOString().split('T')[0].replace(/-/g, '/');
            const endDateStr = now.toISOString().split('T')[0].replace(/-/g, '/');
            searchParams.term += ` AND ("${startDateStr}"[Date - Publication] : "${endDateStr}"[Date - Publication])`;
          }
        }
    
        // 添加出版物类型过滤
        if (options.publicationType && options.publicationType !== 'all') {
          const typeMap: Record<string, string> = {
            'review': 'Review[Publication Type]',
            'clinical_trial': 'Clinical Trial[Publication Type]',
            'meta_analysis': 'Meta-Analysis[Publication Type]',
            'case_report': 'Case Reports[Publication Type]'
          };
    
          const pubType = options.publicationType as string;
          if (typeMap[pubType]) {
            searchParams.term += ` AND ${typeMap[pubType]}`;
          }
        }
    
        const searchResult = await this.makeRequest('esearch.fcgi', searchParams);
    
        if (!searchResult.esearchresult || !searchResult.esearchresult.idlist || searchResult.esearchresult.idlist.length === 0) {
          return { articles: [], count: 0 };
        }
    
        const pmids = searchResult.esearchresult.idlist;
    
        // 第二步:获取详细信息
        const summaryParams = {
          db: 'pubmed',
          id: pmids.join(','),
          retmode: 'json'
        };
    
        const summaryResult = await this.makeRequest('esummary.fcgi', summaryParams);
    
        return {
          articles: this.parseSummaryResult(summaryResult),
          count: parseInt(searchResult.esearchresult.count) || 0
        };
      }
    
      private parseSummaryResult(summaryResult: any): any[] {
        if (!summaryResult.result) return [];
    
        const articles = [];
        const uids = summaryResult.result.uids || [];
    
        for (const uid of uids) {
          const article = summaryResult.result[uid];
          if (!article) continue;
    
          articles.push({
            pmid: article.uid,
            title: article.title || 'No title available',
            abstract: article.abstract || 'No abstract available',
            authors: (article.authors || []).map((author: any) => author.name).join(', '),
            journal: article.fulljournalname || article.source || 'Unknown journal',
            publicationDate: article.pubdate || 'Unknown date',
            publicationType: (article.pubtype || []).join(', ') || 'Unknown type',
            doi: article.elocationid && article.elocationid.includes('doi:')
              ? article.elocationid.replace('doi: ', '')
              : null,
            pmcid: article.pmcid || null,
            volume: article.volume || null,
            issue: article.issue || null,
            pages: article.pages || null,
            url: `https://pubmed.ncbi.nlm.nih.gov/${article.uid}/`,
            fullTextUrl: article.pmcid ? `https://www.ncbi.nlm.nih.gov/pmc/articles/${article.pmcid}/` : null
          });
        }
    
        return articles;
      }
    }
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the tool retrieves information but doesn't specify what 'detailed information' includes (e.g., abstract, authors, citations), whether it requires authentication, rate limits, or error handling. This leaves significant gaps for an agent to understand the tool's behavior beyond basic purpose.

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, efficient sentence that directly states the tool's purpose without unnecessary words. It's front-loaded with the core action and resource, making it easy to parse quickly.

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

Completeness2/5

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

Given the lack of annotations and output schema, the description is incomplete for a tool that fetches detailed article data. It doesn't explain what information is returned, potential errors (e.g., invalid PMID), or how it differs from similar tools. This leaves the agent with insufficient context to use the tool effectively beyond basic invocation.

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 has 100% description coverage, with the 'pmid' parameter clearly documented. The description adds no additional parameter semantics beyond what's in the schema, such as format examples or constraints. Since schema coverage is high, the baseline score of 3 is appropriate, as the description doesn't compensate but also doesn't detract.

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

Purpose4/5

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

The description clearly states the verb ('Get') and resource ('detailed information about a specific PubMed article'), making the purpose unambiguous. However, it doesn't explicitly differentiate from sibling tools like 'search_pubmed' or 'semantic_scholar_paper_details', which likely serve related but distinct purposes.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing a PMID), exclusions, or comparisons to sibling tools such as 'search_pubmed' for broader queries or 'semantic_scholar_paper_details' for similar article details from another source.

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/flyanima/open-search-mcp'

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