Skip to main content
Glama
logic.ts5.3 kB
/** * @fileoverview Defines the core logic, schemas, and types for the `pubchem_fetch_compound_xrefs` tool. * This version includes pagination for large responses. * @module src/mcp-server/tools/fetchCompoundXrefs/logic */ import { z } from "zod"; import { pubChemApiClient } from "../../../services/pubchem/pubchemApiClient.js"; import { BaseErrorCode, McpError } from "../../../types-global/errors.js"; import { logger, type RequestContext } from "../../../utils/index.js"; // 1. Define and export the Zod enum for available cross-reference types export const PubchemXrefTypesEnum = z.enum([ "RegistryID", "RN", "PubMedID", "PatentID", "GeneID", "ProteinGI", "TaxonomyID", ]); // 2. Define and export the Zod schema for input validation export const PubchemFetchCompoundXrefsInputSchema = z.object({ cid: z .number() .int() .positive() .describe( "The PubChem Compound ID (CID) to find cross-references for. Must be a positive integer.", ), xrefTypes: z .array(PubchemXrefTypesEnum) .min(1, "At least one cross-reference type is required.") .describe("A list of cross-reference types to retrieve."), page: z .number() .int() .positive() .optional() .default(1) .describe( "The page number for pagination, used when the result set is large. Defaults to 1.", ), pageSize: z .number() .int() .positive() .optional() .default(1000) .describe("The number of records to return per page. Defaults to 1000."), }); // 3. Define and export the TypeScript type for the input export type PubchemFetchCompoundXrefsInput = z.infer< typeof PubchemFetchCompoundXrefsInputSchema >; // 4. Define and export the Zod schemas for the tool's output const XrefItemSchema = z.object({ type: z .string() .describe("The type of the cross-reference (e.g., 'PubMedID')."), id: z .union([z.string(), z.number()]) .describe("The identifier for the cross-reference."), }); const PaginationSchema = z.object({ currentPage: z.number().int().describe("The current page number."), pageSize: z.number().int().describe("The number of records per page."), totalRecords: z .number() .int() .describe("The total number of records available."), totalPages: z.number().int().describe("The total number of pages available."), }); export const PubchemFetchCompoundXrefsOutputSchema = z.object({ cid: z.number().int().describe("The CID for which xrefs were fetched."), xrefs: z .array(XrefItemSchema) .describe("A paginated list of cross-references."), pagination: PaginationSchema.describe( "Pagination details for the result set.", ), }); // 5. Define and export the TypeScript type for the output export type PubchemFetchCompoundXrefsOutput = z.infer< typeof PubchemFetchCompoundXrefsOutputSchema >; /** * Core logic for the `pubchem_fetch_compound_xrefs` tool. It retrieves a paginated * list of external cross-references (XRefs) for a given PubChem Compound ID (CID). * * @param {PubchemFetchCompoundXrefsInput} params - The validated input parameters. * @param {RequestContext} context - The request context for logging, tracing, and error handling. * @returns {Promise<PubchemFetchCompoundXrefsOutput>} A promise that resolves with the paginated cross-reference results. * @throws {McpError} Throws a structured error if the API request fails, the CID is not found, or the response is malformed. */ export async function pubchemFetchCompoundXrefsLogic( params: PubchemFetchCompoundXrefsInput, context: RequestContext, ): Promise<PubchemFetchCompoundXrefsOutput> { logger.debug("Processing pubchem_fetch_compound_xrefs logic...", { ...context, params, }); const { cid, xrefTypes, page, pageSize } = params; const xrefsString = xrefTypes.join(","); const path = `/compound/cid/${cid}/xrefs/${xrefsString}/JSON`; const response = await pubChemApiClient.get(path, context); logger.debug("Raw PubChem response for xrefs", { ...context, cid, response }); if (!response?.InformationList?.Information) { throw new McpError( BaseErrorCode.EXTERNAL_SERVICE_ERROR, `No cross-references found for CID ${cid}, or the response from PubChem was malformed.`, { ...context, cid, response }, ); } // Flatten the hierarchical response into a single list for pagination const allXrefs: z.infer<typeof XrefItemSchema>[] = []; for (const info of response.InformationList.Information) { for (const xrefType of xrefTypes) { if (info[xrefType] && Array.isArray(info[xrefType])) { for (const id of info[xrefType]) { allXrefs.push({ type: xrefType, id }); } } } } // Paginate the flattened list const totalRecords = allXrefs.length; const totalPages = Math.ceil(totalRecords / pageSize); const startIndex = (page - 1) * pageSize; const paginatedXrefs = allXrefs.slice(startIndex, startIndex + pageSize); const result: PubchemFetchCompoundXrefsOutput = { cid, xrefs: paginatedXrefs, pagination: { currentPage: page, pageSize, totalRecords, totalPages, }, }; logger.info( `Successfully fetched page ${page}/${totalPages} of xrefs for CID ${cid}.`, context, ); return result; }

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/cyanheads/pubchem-mcp-server'

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