Skip to main content
Glama
.clinerules8.63 kB
# pubchem-mcp-server: Developer Guide & Architectural Standards **Effective Date:** 2025-06-29 This document mandates the development practices, architectural patterns, and operational procedures for the `pubchem-mcp-server`. It is the authoritative guide for ensuring code quality, consistency, and maintainability. All development must adhere to these standards. ## I. Core Architectural Principles Our architecture is built on a clear separation of concerns, ensuring that code is modular, testable, and easy to understand. ### 1. Logic Throws, Handlers Catch This is the cornerstone of our error-handling strategy. - **Core Logic (`logic.ts`)**: This layer is responsible for business logic only. It should be pure and self-contained. If an error occurs (e.g., failed validation, API error), it **must `throw` a structured `McpError`**. Logic files **must not** contain `try...catch` blocks for formatting final responses. - **Handlers (`registration.ts`, Transports)**: This layer is responsible for invoking core logic and managing communication protocols. It **must** wrap all calls to the logic layer in a `try...catch` block. This is the only place where errors are caught, processed by the `ErrorHandler`, and formatted into a final `CallToolResult` or HTTP response. ### 2. Structured, Traceable Operations Every operation must be traceable from start to finish through structured logging and context propagation. - **`RequestContext`**: Every significant operation must begin by creating a `RequestContext` using `requestContextService.createRequestContext()`. This context, containing a unique `requestId`, must be passed down through all subsequent function calls. - **`Logger`**: All logging must be done through the centralized `logger` singleton, and every log call must include the current `RequestContext`. ## II. Tool Development Workflow This section defines the mandatory workflow for creating and modifying tools. ### A. File and Directory Structure Each tool must reside in its own directory within `src/mcp-server/tools/` and follow this structure: - **`toolName/`** - **`index.ts`**: A barrel file that exports only the `register...` function from `registration.ts`. - **`logic.ts`**: Contains the core business logic. It **must** define and export the tool's Zod input schema, all inferred TypeScript types (input and output), and the main logic function. - **`registration.ts`**: Registers the tool with the MCP server. It imports from `logic.ts` and implements the "Handler" role described in our core principles. ### B. The Authoritative Pattern: `searchCompoundByIdentifier` The `pubchem_search_compound_by_identifier` tool serves as the canonical example for all tool development. **Step 1: Define Schema and Logic (`logic.ts`)** The `logic.ts` file defines the "what" and "how" of the tool. It is self-contained and throws errors when it cannot fulfill its contract. ```typescript /** * @fileoverview Defines the core logic, schemas, and types for the `pubchem_search_compound_by_identifier` tool. * @module src/mcp-server/tools/searchCompoundByIdentifier/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 schema export const PubchemSearchCompoundByIdentifierInputSchema = z.object({ identifierType: z .enum(["name", "smiles", "inchikey"]) .describe("The type of chemical identifier being provided."), identifier: z .string() .min(1, "Identifier cannot be empty.") .describe("The identifier string."), }); // 2. Define and export TypeScript types export type PubchemSearchCompoundByIdentifierInput = z.infer< typeof PubchemSearchCompoundByIdentifierInputSchema >; export interface PubchemSearchCompoundByIdentifierOutput { cids: number[]; } /** * 3. Implement and export the core logic * @param params - The validated input parameters. * @param context - The request context for logging and tracing. * @returns A promise that resolves with the search results. * @throws {McpError} If the API request fails or the identifier is not found. */ export async function pubchemSearchCompoundByIdentifierLogic( params: PubchemSearchCompoundByIdentifierInput, context: RequestContext ): Promise<PubchemSearchCompoundByIdentifierOutput> { logger.debug("Processing pubchem_search_compound_by_identifier logic...", { ...context, }); const { identifierType, identifier } = params; const path = `/compound/${identifierType}/${encodeURIComponent(identifier)}/cids/JSON`; const response = await pubChemApiClient.get(path, context); // ... error handling and data transformation ... return { cids: response.IdentifierList.CID }; } ``` **Step 2: Register the Tool and Handle Errors (`registration.ts`)** The `registration.ts` file wires the logic into the MCP server and handles all outcomes. ```typescript /** * @fileoverview Handles the registration of the `pubchem_search_compound_by_identifier` tool. * @module src/mcp-server/tools/searchCompoundByIdentifier/registration */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js"; import { pubchemSearchCompoundByIdentifierLogic, PubchemSearchCompoundByIdentifierInputSchema, PubchemSearchCompoundByIdentifierInput, } from "./logic.js"; export const registerPubchemSearchCompoundByIdentifierTool = async ( server: McpServer ): Promise<void> => { const toolName = "pubchem_search_compound_by_identifier"; const toolDescription = "Searches for PubChem Compound IDs (CIDs) using a common chemical identifier."; server.tool( toolName, toolDescription, PubchemSearchCompoundByIdentifierInputSchema.shape, async ( params: PubchemSearchCompoundByIdentifierInput, mcpContext: any ): Promise<CallToolResult> => { const handlerContext = requestContextService.createRequestContext({ /* ... */ }); try { const result = await pubchemSearchCompoundByIdentifierLogic( params, handlerContext ); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], isError: false, }; } catch (error) { const mcpError = ErrorHandler.handleError(error, { /* ... */ }); return { content: [ { type: "text", text: JSON.stringify({ error: mcpError.toJSON() }), }, ], isError: true, }; } } ); }; ``` ## III. Integrating External Services For interacting with the PubChem API, the server uses a dedicated singleton client. - **`PubChemApiClient`**: Located at `src/services/pubchem/pubchemApiClient.ts`, this singleton class manages all interactions with the PubChem PUG REST API. It handles URL construction, rate limiting (5 requests/second), request execution, and centralized error handling. - **Usage**: Import the `pubChemApiClient` singleton instance into your tool's `logic.ts` file to make API calls. ## IV. Code Quality and Documentation - **JSDoc**: Every file must start with a `@fileoverview` and `@module` block. All exported functions and types must have clear, concise JSDoc comments explaining their purpose. - **Clarity Over Brevity**: Write self-documenting code with meaningful variable and function names. - **Immutability**: Prefer functional approaches and immutable data structures where possible to avoid side effects. - **Formatting**: All code must be formatted using Prettier (`npm run format`) before committing. ## V. Security Mandates - **Input Sanitization**: All inputs from external sources (tool arguments, API responses) must be treated as untrusted. Use the `sanitization` utilities where appropriate. - **Secrets Management**: All secrets (API keys, auth keys) **must** be loaded from environment variables via the `config` module. Never hardcode secrets. - **Authentication & Authorization**: - The server supports `jwt` (dev) and `oauth` (prod) modes via `MCP_AUTH_MODE`. - Protect tools by checking scopes. Use the `withRequiredScopes(["scope:read"])` utility inside your tool handler. This guide is the single source of truth for development standards. All code reviews will be conducted against these principles.

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