@cyanheads/pubchem-mcp-server 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +236 -0
  3. package/dist/config/index.d.ts +98 -0
  4. package/dist/config/index.js +326 -0
  5. package/dist/index.d.ts +24 -0
  6. package/dist/index.js +214 -0
  7. package/dist/mcp-server/server.d.ts +21 -0
  8. package/dist/mcp-server/server.js +124 -0
  9. package/dist/mcp-server/tools/fetchAssaySummary/index.d.ts +7 -0
  10. package/dist/mcp-server/tools/fetchAssaySummary/index.js +7 -0
  11. package/dist/mcp-server/tools/fetchAssaySummary/logic.d.ts +71 -0
  12. package/dist/mcp-server/tools/fetchAssaySummary/logic.js +96 -0
  13. package/dist/mcp-server/tools/fetchAssaySummary/registration.d.ts +12 -0
  14. package/dist/mcp-server/tools/fetchAssaySummary/registration.js +68 -0
  15. package/dist/mcp-server/tools/fetchCompoundProperties/index.d.ts +7 -0
  16. package/dist/mcp-server/tools/fetchCompoundProperties/index.js +7 -0
  17. package/dist/mcp-server/tools/fetchCompoundProperties/logic.d.ts +131 -0
  18. package/dist/mcp-server/tools/fetchCompoundProperties/logic.js +100 -0
  19. package/dist/mcp-server/tools/fetchCompoundProperties/registration.d.ts +13 -0
  20. package/dist/mcp-server/tools/fetchCompoundProperties/registration.js +52 -0
  21. package/dist/mcp-server/tools/fetchCompoundXrefs/index.d.ts +7 -0
  22. package/dist/mcp-server/tools/fetchCompoundXrefs/index.js +7 -0
  23. package/dist/mcp-server/tools/fetchCompoundXrefs/logic.d.ts +89 -0
  24. package/dist/mcp-server/tools/fetchCompoundXrefs/logic.js +145 -0
  25. package/dist/mcp-server/tools/fetchCompoundXrefs/registration.d.ts +13 -0
  26. package/dist/mcp-server/tools/fetchCompoundXrefs/registration.js +52 -0
  27. package/dist/mcp-server/tools/fetchSubstanceDetails/index.d.ts +7 -0
  28. package/dist/mcp-server/tools/fetchSubstanceDetails/index.js +7 -0
  29. package/dist/mcp-server/tools/fetchSubstanceDetails/logic.d.ts +69 -0
  30. package/dist/mcp-server/tools/fetchSubstanceDetails/logic.js +97 -0
  31. package/dist/mcp-server/tools/fetchSubstanceDetails/registration.d.ts +13 -0
  32. package/dist/mcp-server/tools/fetchSubstanceDetails/registration.js +79 -0
  33. package/dist/mcp-server/tools/getCompoundImage/index.d.ts +7 -0
  34. package/dist/mcp-server/tools/getCompoundImage/index.js +7 -0
  35. package/dist/mcp-server/tools/getCompoundImage/logic.d.ts +42 -0
  36. package/dist/mcp-server/tools/getCompoundImage/logic.js +68 -0
  37. package/dist/mcp-server/tools/getCompoundImage/registration.d.ts +12 -0
  38. package/dist/mcp-server/tools/getCompoundImage/registration.js +57 -0
  39. package/dist/mcp-server/tools/searchAssaysByTarget/index.d.ts +7 -0
  40. package/dist/mcp-server/tools/searchAssaysByTarget/index.js +7 -0
  41. package/dist/mcp-server/tools/searchAssaysByTarget/logic.d.ts +35 -0
  42. package/dist/mcp-server/tools/searchAssaysByTarget/logic.js +64 -0
  43. package/dist/mcp-server/tools/searchAssaysByTarget/registration.d.ts +12 -0
  44. package/dist/mcp-server/tools/searchAssaysByTarget/registration.js +62 -0
  45. package/dist/mcp-server/tools/searchCompoundByIdentifier/index.d.ts +7 -0
  46. package/dist/mcp-server/tools/searchCompoundByIdentifier/index.js +7 -0
  47. package/dist/mcp-server/tools/searchCompoundByIdentifier/logic.d.ts +35 -0
  48. package/dist/mcp-server/tools/searchCompoundByIdentifier/logic.js +59 -0
  49. package/dist/mcp-server/tools/searchCompoundByIdentifier/registration.d.ts +12 -0
  50. package/dist/mcp-server/tools/searchCompoundByIdentifier/registration.js +51 -0
  51. package/dist/mcp-server/tools/searchCompoundsByFormula/index.d.ts +7 -0
  52. package/dist/mcp-server/tools/searchCompoundsByFormula/index.js +7 -0
  53. package/dist/mcp-server/tools/searchCompoundsByFormula/logic.d.ts +38 -0
  54. package/dist/mcp-server/tools/searchCompoundsByFormula/logic.js +75 -0
  55. package/dist/mcp-server/tools/searchCompoundsByFormula/registration.d.ts +12 -0
  56. package/dist/mcp-server/tools/searchCompoundsByFormula/registration.js +62 -0
  57. package/dist/mcp-server/tools/searchCompoundsBySimilarity/index.d.ts +7 -0
  58. package/dist/mcp-server/tools/searchCompoundsBySimilarity/index.js +7 -0
  59. package/dist/mcp-server/tools/searchCompoundsBySimilarity/logic.d.ts +41 -0
  60. package/dist/mcp-server/tools/searchCompoundsBySimilarity/logic.js +82 -0
  61. package/dist/mcp-server/tools/searchCompoundsBySimilarity/registration.d.ts +12 -0
  62. package/dist/mcp-server/tools/searchCompoundsBySimilarity/registration.js +62 -0
  63. package/dist/mcp-server/tools/searchCompoundsByStructure/index.d.ts +7 -0
  64. package/dist/mcp-server/tools/searchCompoundsByStructure/index.js +7 -0
  65. package/dist/mcp-server/tools/searchCompoundsByStructure/logic.d.ts +41 -0
  66. package/dist/mcp-server/tools/searchCompoundsByStructure/logic.js +78 -0
  67. package/dist/mcp-server/tools/searchCompoundsByStructure/registration.d.ts +13 -0
  68. package/dist/mcp-server/tools/searchCompoundsByStructure/registration.js +63 -0
  69. package/dist/mcp-server/transports/auth/core/authContext.d.ts +33 -0
  70. package/dist/mcp-server/transports/auth/core/authContext.js +24 -0
  71. package/dist/mcp-server/transports/auth/core/authTypes.d.ts +17 -0
  72. package/dist/mcp-server/transports/auth/core/authTypes.js +5 -0
  73. package/dist/mcp-server/transports/auth/core/authUtils.d.ts +18 -0
  74. package/dist/mcp-server/transports/auth/core/authUtils.js +45 -0
  75. package/dist/mcp-server/transports/auth/index.d.ts +10 -0
  76. package/dist/mcp-server/transports/auth/index.js +9 -0
  77. package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.d.ts +27 -0
  78. package/dist/mcp-server/transports/auth/strategies/jwt/jwtMiddleware.js +149 -0
  79. package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.d.ts +20 -0
  80. package/dist/mcp-server/transports/auth/strategies/oauth/oauthMiddleware.js +124 -0
  81. package/dist/mcp-server/transports/httpErrorHandler.d.ts +26 -0
  82. package/dist/mcp-server/transports/httpErrorHandler.js +73 -0
  83. package/dist/mcp-server/transports/httpTransport.d.ts +21 -0
  84. package/dist/mcp-server/transports/httpTransport.js +208 -0
  85. package/dist/mcp-server/transports/stdioTransport.d.ts +42 -0
  86. package/dist/mcp-server/transports/stdioTransport.js +63 -0
  87. package/dist/services/pubchem/pubchemApiClient.d.ts +52 -0
  88. package/dist/services/pubchem/pubchemApiClient.js +120 -0
  89. package/dist/types-global/errors.d.ts +127 -0
  90. package/dist/types-global/errors.js +126 -0
  91. package/dist/utils/index.d.ts +12 -0
  92. package/dist/utils/index.js +20 -0
  93. package/dist/utils/internal/errorHandler.d.ts +176 -0
  94. package/dist/utils/internal/errorHandler.js +335 -0
  95. package/dist/utils/internal/index.d.ts +9 -0
  96. package/dist/utils/internal/index.js +9 -0
  97. package/dist/utils/internal/logger.d.ts +148 -0
  98. package/dist/utils/internal/logger.js +430 -0
  99. package/dist/utils/internal/requestContext.d.ts +83 -0
  100. package/dist/utils/internal/requestContext.js +72 -0
  101. package/dist/utils/metrics/index.d.ts +7 -0
  102. package/dist/utils/metrics/index.js +7 -0
  103. package/dist/utils/metrics/tokenCounter.d.ts +35 -0
  104. package/dist/utils/metrics/tokenCounter.js +110 -0
  105. package/dist/utils/network/fetchWithTimeout.d.ts +21 -0
  106. package/dist/utils/network/fetchWithTimeout.js +59 -0
  107. package/dist/utils/network/index.d.ts +6 -0
  108. package/dist/utils/network/index.js +5 -0
  109. package/dist/utils/parsing/dateParser.d.ts +73 -0
  110. package/dist/utils/parsing/dateParser.js +107 -0
  111. package/dist/utils/parsing/index.d.ts +8 -0
  112. package/dist/utils/parsing/index.js +8 -0
  113. package/dist/utils/parsing/jsonParser.d.ts +82 -0
  114. package/dist/utils/parsing/jsonParser.js +126 -0
  115. package/dist/utils/scheduling/index.d.ts +6 -0
  116. package/dist/utils/scheduling/index.js +6 -0
  117. package/dist/utils/scheduling/scheduler.d.ts +72 -0
  118. package/dist/utils/scheduling/scheduler.js +152 -0
  119. package/dist/utils/security/idGenerator.d.ts +137 -0
  120. package/dist/utils/security/idGenerator.js +215 -0
  121. package/dist/utils/security/index.d.ts +9 -0
  122. package/dist/utils/security/index.js +9 -0
  123. package/dist/utils/security/rateLimiter.d.ts +108 -0
  124. package/dist/utils/security/rateLimiter.js +179 -0
  125. package/dist/utils/security/sanitization.d.ts +184 -0
  126. package/dist/utils/security/sanitization.js +453 -0
  127. package/package.json +108 -0
@@ -0,0 +1,124 @@
1
+ /**
2
+ * @fileoverview Main entry point for the MCP (Model Context Protocol) server.
3
+ * This file orchestrates the server's lifecycle:
4
+ * 1. Initializes the core `McpServer` instance (from `@modelcontextprotocol/sdk`) with its identity and capabilities.
5
+ * 2. Registers available resources and tools, making them discoverable and usable by clients.
6
+ * 3. Selects and starts the appropriate communication transport (stdio or Streamable HTTP)
7
+ * based on configuration.
8
+ * 4. Handles top-level error management during startup.
9
+ *
10
+ * MCP Specification References:
11
+ * - Lifecycle: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/lifecycle.mdx
12
+ * - Overview (Capabilities): https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/index.mdx
13
+ * - Transports: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx
14
+ * @module src/mcp-server/server
15
+ */
16
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
17
+ import { config, environment } from "../config/index.js";
18
+ import { ErrorHandler, logger, requestContextService } from "../utils/index.js";
19
+ import { BaseErrorCode } from "../types-global/errors.js";
20
+ import { registerPubchemSearchCompoundByIdentifierTool } from "./tools/searchCompoundByIdentifier/index.js";
21
+ import { registerPubchemFetchCompoundPropertiesTool } from "./tools/fetchCompoundProperties/index.js";
22
+ import { registerPubchemGetCompoundImageTool } from "./tools/getCompoundImage/index.js";
23
+ import { registerPubchemSearchCompoundsByStructureTool } from "./tools/searchCompoundsByStructure/index.js";
24
+ import { registerPubchemSearchCompoundsBySimilarityTool } from "./tools/searchCompoundsBySimilarity/index.js";
25
+ import { registerPubchemSearchCompoundsByFormulaTool } from "./tools/searchCompoundsByFormula/index.js";
26
+ import { registerPubchemFetchSubstanceDetailsTool } from "./tools/fetchSubstanceDetails/index.js";
27
+ import { registerPubchemFetchAssaySummaryTool } from "./tools/fetchAssaySummary/index.js";
28
+ import { registerPubchemSearchAssaysByTargetTool } from "./tools/searchAssaysByTarget/index.js";
29
+ import { registerPubchemFetchCompoundXrefsTool } from "./tools/fetchCompoundXrefs/index.js";
30
+ import { startHttpTransport } from "./transports/httpTransport.js";
31
+ import { connectStdioTransport } from "./transports/stdioTransport.js";
32
+ /**
33
+ * Creates and configures a new instance of the `McpServer`.
34
+ *
35
+ * @returns A promise resolving with the configured `McpServer` instance.
36
+ * @throws {McpError} If any resource or tool registration fails.
37
+ * @private
38
+ */
39
+ async function createMcpServerInstance() {
40
+ const context = requestContextService.createRequestContext({
41
+ operation: "createMcpServerInstance",
42
+ });
43
+ logger.info("Initializing MCP server instance", context);
44
+ requestContextService.configure({
45
+ appName: config.mcpServerName,
46
+ appVersion: config.mcpServerVersion,
47
+ environment,
48
+ });
49
+ const server = new McpServer({ name: config.mcpServerName, version: config.mcpServerVersion }, {
50
+ capabilities: {
51
+ logging: {},
52
+ resources: { listChanged: true },
53
+ tools: { listChanged: true },
54
+ },
55
+ });
56
+ await ErrorHandler.tryCatch(async () => {
57
+ logger.debug("Registering resources and tools...", context);
58
+ await registerPubchemSearchCompoundByIdentifierTool(server);
59
+ await registerPubchemFetchCompoundPropertiesTool(server);
60
+ await registerPubchemGetCompoundImageTool(server);
61
+ await registerPubchemSearchCompoundsByStructureTool(server);
62
+ await registerPubchemSearchCompoundsBySimilarityTool(server);
63
+ await registerPubchemSearchCompoundsByFormulaTool(server);
64
+ await registerPubchemFetchSubstanceDetailsTool(server);
65
+ await registerPubchemFetchAssaySummaryTool(server);
66
+ await registerPubchemSearchAssaysByTargetTool(server);
67
+ await registerPubchemFetchCompoundXrefsTool(server);
68
+ logger.info("Resources and tools registered successfully", context);
69
+ }, {
70
+ operation: "registerAllCapabilities",
71
+ context,
72
+ errorCode: BaseErrorCode.INITIALIZATION_FAILED,
73
+ critical: true,
74
+ });
75
+ return server;
76
+ }
77
+ /**
78
+ * Selects, sets up, and starts the appropriate MCP transport layer based on configuration.
79
+ *
80
+ * @returns Resolves with `McpServer` for 'stdio', `http.Server` for 'http', or `void`.
81
+ * @throws {Error} If transport type is unsupported or setup fails.
82
+ * @private
83
+ */
84
+ async function startTransport() {
85
+ const transportType = config.mcpTransportType;
86
+ const context = requestContextService.createRequestContext({
87
+ operation: "startTransport",
88
+ transport: transportType,
89
+ });
90
+ logger.info(`Starting transport: ${transportType}`, context);
91
+ if (transportType === "http") {
92
+ return startHttpTransport(createMcpServerInstance, context);
93
+ }
94
+ if (transportType === "stdio") {
95
+ const server = await createMcpServerInstance();
96
+ await connectStdioTransport(server, context);
97
+ return server;
98
+ }
99
+ throw new Error(`Unsupported transport type: ${transportType}. Must be 'stdio' or 'http'.`);
100
+ }
101
+ /**
102
+ * Main application entry point. Initializes and starts the MCP server.
103
+ */
104
+ export async function initializeAndStartServer() {
105
+ const context = requestContextService.createRequestContext({
106
+ operation: "initializeAndStartServer",
107
+ });
108
+ logger.info("MCP Server initialization sequence started.", context);
109
+ try {
110
+ const result = await startTransport();
111
+ logger.info("MCP Server initialization sequence completed successfully.", context);
112
+ return result;
113
+ }
114
+ catch (err) {
115
+ ErrorHandler.handleError(err, {
116
+ operation: "initializeAndStartServer",
117
+ context: context,
118
+ critical: true,
119
+ rethrow: false,
120
+ });
121
+ logger.info("Exiting process due to critical initialization error.", context);
122
+ process.exit(1);
123
+ }
124
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @fileoverview Barrel file for the `pubchem_fetch_assay_summary` tool.
3
+ * This file serves as the public interface for the tool module,
4
+ * primarily exporting the `registerPubchemFetchAssaySummaryTool` function.
5
+ * @module src/mcp-server/tools/fetchAssaySummary/index
6
+ */
7
+ export { registerPubchemFetchAssaySummaryTool } from "./registration.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @fileoverview Barrel file for the `pubchem_fetch_assay_summary` tool.
3
+ * This file serves as the public interface for the tool module,
4
+ * primarily exporting the `registerPubchemFetchAssaySummaryTool` function.
5
+ * @module src/mcp-server/tools/fetchAssaySummary/index
6
+ */
7
+ export { registerPubchemFetchAssaySummaryTool } from "./registration.js";
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @fileoverview Defines the core logic, schemas, and types for the `pubchem_fetch_assay_summary` tool.
3
+ * @module src/mcp-server/tools/fetchAssaySummary/logic
4
+ */
5
+ import { z } from "zod";
6
+ import { type RequestContext } from "../../../utils/index.js";
7
+ export declare const PubchemFetchAssaySummaryInputSchema: z.ZodObject<{
8
+ aids: z.ZodArray<z.ZodNumber, "many">;
9
+ }, "strip", z.ZodTypeAny, {
10
+ aids: number[];
11
+ }, {
12
+ aids: number[];
13
+ }>;
14
+ export type PubchemFetchAssaySummaryInput = z.infer<typeof PubchemFetchAssaySummaryInputSchema>;
15
+ export declare const AssaySummarySchema: z.ZodObject<{
16
+ aid: z.ZodNumber;
17
+ name: z.ZodString;
18
+ description: z.ZodString;
19
+ sourceName: z.ZodString;
20
+ numSids: z.ZodNumber;
21
+ numActive: z.ZodNumber;
22
+ targets: z.ZodArray<z.ZodObject<{
23
+ name: z.ZodString;
24
+ geneId: z.ZodOptional<z.ZodNumber>;
25
+ geneSymbol: z.ZodOptional<z.ZodString>;
26
+ }, "strip", z.ZodTypeAny, {
27
+ name: string;
28
+ geneId?: number | undefined;
29
+ geneSymbol?: string | undefined;
30
+ }, {
31
+ name: string;
32
+ geneId?: number | undefined;
33
+ geneSymbol?: string | undefined;
34
+ }>, "many">;
35
+ }, "strip", z.ZodTypeAny, {
36
+ name: string;
37
+ description: string;
38
+ aid: number;
39
+ sourceName: string;
40
+ numSids: number;
41
+ numActive: number;
42
+ targets: {
43
+ name: string;
44
+ geneId?: number | undefined;
45
+ geneSymbol?: string | undefined;
46
+ }[];
47
+ }, {
48
+ name: string;
49
+ description: string;
50
+ aid: number;
51
+ sourceName: string;
52
+ numSids: number;
53
+ numActive: number;
54
+ targets: {
55
+ name: string;
56
+ geneId?: number | undefined;
57
+ geneSymbol?: string | undefined;
58
+ }[];
59
+ }>;
60
+ export type AssaySummary = z.infer<typeof AssaySummarySchema>;
61
+ export type PubchemFetchAssaySummaryOutput = AssaySummary[];
62
+ /**
63
+ * Core logic for the `pubchem_fetch_assay_summary` tool. It retrieves a summary
64
+ * for a specified list of PubChem BioAssay IDs (AIDs).
65
+ *
66
+ * @param {PubchemFetchAssaySummaryInput} params - The validated input parameters, containing the AIDs.
67
+ * @param {RequestContext} context - The request context for logging, tracing, and error handling.
68
+ * @returns {Promise<PubchemFetchAssaySummaryOutput>} A promise that resolves with an array of structured assay summaries.
69
+ * @throws {McpError} Throws a structured error if the API request fails, any AID is not found, or the response is malformed.
70
+ */
71
+ export declare function pubchemFetchAssaySummaryLogic(params: PubchemFetchAssaySummaryInput, context: RequestContext): Promise<PubchemFetchAssaySummaryOutput>;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @fileoverview Defines the core logic, schemas, and types for the `pubchem_fetch_assay_summary` tool.
3
+ * @module src/mcp-server/tools/fetchAssaySummary/logic
4
+ */
5
+ import { z } from "zod";
6
+ import { pubChemApiClient } from "../../../services/pubchem/pubchemApiClient.js";
7
+ import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
8
+ import { logger } from "../../../utils/index.js";
9
+ // 1. Define and export the Zod schema for input validation
10
+ export const PubchemFetchAssaySummaryInputSchema = z.object({
11
+ aids: z
12
+ .array(z.number().int().positive())
13
+ .min(1, "At least one Assay ID (AID) must be provided.")
14
+ .max(5, "A maximum of 5 Assay IDs (AIDs) can be provided.")
15
+ .describe("An array of PubChem BioAssay IDs (AIDs). Must contain 1 to 5 positive integers."),
16
+ });
17
+ // 3. Define and export the Zod schema for a single assay summary object
18
+ export const AssaySummarySchema = z.object({
19
+ aid: z.number().int().describe("The unique PubChem BioAssay ID (AID)."),
20
+ name: z.string().describe("The official name of the bioassay."),
21
+ description: z
22
+ .string()
23
+ .describe("A detailed description of the assay's purpose and methods."),
24
+ sourceName: z
25
+ .string()
26
+ .describe("The name of the institution or entity that provided the assay."),
27
+ numSids: z
28
+ .number()
29
+ .int()
30
+ .describe("The total number of substances (SIDs) tested in the assay."),
31
+ numActive: z
32
+ .number()
33
+ .int()
34
+ .describe("The number of substances found to be active in the assay."),
35
+ targets: z
36
+ .array(z.object({
37
+ name: z.string().describe("Name of the biological target."),
38
+ geneId: z
39
+ .number()
40
+ .int()
41
+ .optional()
42
+ .describe("NCBI Gene ID, if available."),
43
+ geneSymbol: z
44
+ .string()
45
+ .optional()
46
+ .describe("Official gene symbol, if available."),
47
+ }))
48
+ .describe("Biological targets of the assay. Note: This is often empty as the summary endpoint may not provide target details."),
49
+ });
50
+ /**
51
+ * Core logic for the `pubchem_fetch_assay_summary` tool. It retrieves a summary
52
+ * for a specified list of PubChem BioAssay IDs (AIDs).
53
+ *
54
+ * @param {PubchemFetchAssaySummaryInput} params - The validated input parameters, containing the AIDs.
55
+ * @param {RequestContext} context - The request context for logging, tracing, and error handling.
56
+ * @returns {Promise<PubchemFetchAssaySummaryOutput>} A promise that resolves with an array of structured assay summaries.
57
+ * @throws {McpError} Throws a structured error if the API request fails, any AID is not found, or the response is malformed.
58
+ */
59
+ export async function pubchemFetchAssaySummaryLogic(params, context) {
60
+ logger.debug("Processing pubchem_fetch_assay_summary logic...", {
61
+ ...context,
62
+ params,
63
+ });
64
+ const { aids } = params;
65
+ const path = `/assay/aid/${aids.join(",")}/summary/JSON`;
66
+ const response = await pubChemApiClient.get(path, context);
67
+ logger.debug("Raw PubChem response for pubchem_fetch_assay_summary", {
68
+ ...context,
69
+ aids,
70
+ response,
71
+ });
72
+ const summaries = response?.AssaySummaries?.AssaySummary;
73
+ if (!summaries || summaries.length === 0) {
74
+ throw new McpError(BaseErrorCode.NOT_FOUND, `No assay summaries found for AIDs [${aids.join(", ")}], or the response from PubChem was malformed.`, { ...context, aids, response });
75
+ }
76
+ const results = summaries.map((summary) => {
77
+ // Safely extract description, handling both string and array formats.
78
+ let description = "No description provided.";
79
+ if (summary.Description) {
80
+ description = Array.isArray(summary.Description)
81
+ ? summary.Description.join("\n")
82
+ : summary.Description;
83
+ }
84
+ return {
85
+ aid: summary.AID ?? 0,
86
+ name: summary.Name ?? "N/A",
87
+ description,
88
+ sourceName: summary.SourceName ?? "N/A",
89
+ numSids: summary.SIDCountAll ?? 0,
90
+ numActive: summary.CIDCountActive ?? 0,
91
+ targets: [], // The summary endpoint does not provide target details. This is expected.
92
+ };
93
+ });
94
+ logger.info(`Successfully fetched ${results.length} summaries for AIDs [${aids.join(", ")}].`, context);
95
+ return results;
96
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @fileoverview Handles the registration of the `pubchem_fetch_assay_summary` tool with the MCP server.
3
+ * @module src/mcp-server/tools/fetchAssaySummary/registration
4
+ */
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ /**
7
+ * Registers the 'pubchem_fetch_assay_summary' tool with the provided MCP server instance.
8
+ * This tool retrieves a detailed summary for a given PubChem BioAssay ID (AID).
9
+ *
10
+ * @param {McpServer} server - The MCP server instance to register the tool with.
11
+ */
12
+ export declare const registerPubchemFetchAssaySummaryTool: (server: McpServer) => Promise<void>;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview Handles the registration of the `pubchem_fetch_assay_summary` tool with the MCP server.
3
+ * @module src/mcp-server/tools/fetchAssaySummary/registration
4
+ */
5
+ import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
6
+ import { PubchemFetchAssaySummaryInputSchema, pubchemFetchAssaySummaryLogic, } from "./logic.js";
7
+ /**
8
+ * Registers the 'pubchem_fetch_assay_summary' tool with the provided MCP server instance.
9
+ * This tool retrieves a detailed summary for a given PubChem BioAssay ID (AID).
10
+ *
11
+ * @param {McpServer} server - The MCP server instance to register the tool with.
12
+ */
13
+ export const registerPubchemFetchAssaySummaryTool = async (server) => {
14
+ const toolName = "pubchem_fetch_assay_summary";
15
+ const toolDescription = "Fetches detailed summaries for a list of up to 5 PubChem BioAssay IDs (AIDs), including their names, descriptions, sources, and statistics. This is useful for obtaining metadata about multiple biological assays in a single request.";
16
+ server.tool(toolName, toolDescription, PubchemFetchAssaySummaryInputSchema.shape, async (params, mcpContext) => {
17
+ const handlerContext = requestContextService.createRequestContext({
18
+ operation: "HandleToolRequest",
19
+ toolName,
20
+ mcpToolContext: mcpContext,
21
+ input: params,
22
+ });
23
+ try {
24
+ logger.info(`Initiating tool request for ${toolName} with AIDs: ${params.aids.join(", ")}`, handlerContext);
25
+ const result = await pubchemFetchAssaySummaryLogic(params, handlerContext);
26
+ // Custom stringify to make large arrays of numbers more compact
27
+ const placeholderPrefix = "##JSON_STRINGIFY_PLACEHOLDER##";
28
+ let placeholderIndex = 0;
29
+ const placeholders = [];
30
+ const replacer = (key, value) => {
31
+ if (Array.isArray(value) &&
32
+ value.every((item) => typeof item === "number")) {
33
+ const placeholder = `${placeholderPrefix}${placeholderIndex++}`;
34
+ placeholders.push(JSON.stringify(value));
35
+ return placeholder;
36
+ }
37
+ return value;
38
+ };
39
+ let text = JSON.stringify(result, replacer, 2);
40
+ for (let i = 0; i < placeholders.length; i++) {
41
+ text = text.replace(`"${placeholderPrefix}${i}"`, placeholders[i]);
42
+ }
43
+ return {
44
+ content: [{ type: "text", text }],
45
+ isError: false,
46
+ };
47
+ }
48
+ catch (error) {
49
+ const handledError = ErrorHandler.handleError(error, {
50
+ operation: "pubchemFetchAssaySummaryToolHandler",
51
+ context: handlerContext,
52
+ input: params,
53
+ });
54
+ // No need to log here, handleError already does it.
55
+ return {
56
+ content: [
57
+ {
58
+ type: "text",
59
+ text: JSON.stringify({
60
+ error: ErrorHandler.formatError(handledError),
61
+ }),
62
+ },
63
+ ],
64
+ isError: true,
65
+ };
66
+ }
67
+ });
68
+ };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @fileoverview Barrel file for the `pubchem_fetch_compound_properties` tool.
3
+ * This file serves as the public interface for the tool module,
4
+ * primarily exporting the `registerPubchemFetchCompoundPropertiesTool` function.
5
+ * @module src/mcp-server/tools/fetchCompoundProperties/index
6
+ */
7
+ export { registerPubchemFetchCompoundPropertiesTool } from "./registration.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @fileoverview Barrel file for the `pubchem_fetch_compound_properties` tool.
3
+ * This file serves as the public interface for the tool module,
4
+ * primarily exporting the `registerPubchemFetchCompoundPropertiesTool` function.
5
+ * @module src/mcp-server/tools/fetchCompoundProperties/index
6
+ */
7
+ export { registerPubchemFetchCompoundPropertiesTool } from "./registration.js";
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @fileoverview Defines the core logic, schemas, and types for the `pubchem_fetch_compound_properties` tool.
3
+ * @module src/mcp-server/tools/fetchCompoundProperties/logic
4
+ */
5
+ import { z } from "zod";
6
+ import { type RequestContext } from "../../../utils/index.js";
7
+ export declare const PubchemCompoundPropertiesEnum: z.ZodEnum<["MolecularFormula", "MolecularWeight", "InChI", "InChIKey", "IUPACName", "Title", "XLogP", "ExactMass", "MonoisotopicMass", "TPSA", "Complexity", "Charge", "HBondDonorCount", "HBondAcceptorCount", "RotatableBondCount", "HeavyAtomCount", "CovalentUnitCount"]>;
8
+ export declare const PubchemFetchCompoundPropertiesInputSchema: z.ZodObject<{
9
+ cids: z.ZodArray<z.ZodNumber, "many">;
10
+ properties: z.ZodArray<z.ZodEnum<["MolecularFormula", "MolecularWeight", "InChI", "InChIKey", "IUPACName", "Title", "XLogP", "ExactMass", "MonoisotopicMass", "TPSA", "Complexity", "Charge", "HBondDonorCount", "HBondAcceptorCount", "RotatableBondCount", "HeavyAtomCount", "CovalentUnitCount"]>, "many">;
11
+ }, "strip", z.ZodTypeAny, {
12
+ cids: number[];
13
+ properties: ("MolecularFormula" | "MolecularWeight" | "InChI" | "InChIKey" | "IUPACName" | "Title" | "XLogP" | "ExactMass" | "MonoisotopicMass" | "TPSA" | "Complexity" | "Charge" | "HBondDonorCount" | "HBondAcceptorCount" | "RotatableBondCount" | "HeavyAtomCount" | "CovalentUnitCount")[];
14
+ }, {
15
+ cids: number[];
16
+ properties: ("MolecularFormula" | "MolecularWeight" | "InChI" | "InChIKey" | "IUPACName" | "Title" | "XLogP" | "ExactMass" | "MonoisotopicMass" | "TPSA" | "Complexity" | "Charge" | "HBondDonorCount" | "HBondAcceptorCount" | "RotatableBondCount" | "HeavyAtomCount" | "CovalentUnitCount")[];
17
+ }>;
18
+ export type PubchemFetchCompoundPropertiesInput = z.infer<typeof PubchemFetchCompoundPropertiesInputSchema>;
19
+ export declare const PubchemFetchCompoundPropertiesOutputSchema: z.ZodObject<{
20
+ results: z.ZodArray<z.ZodObject<{
21
+ CID: z.ZodNumber;
22
+ MolecularFormula: z.ZodOptional<z.ZodString>;
23
+ MolecularWeight: z.ZodOptional<z.ZodNumber>;
24
+ InChI: z.ZodOptional<z.ZodString>;
25
+ InChIKey: z.ZodOptional<z.ZodString>;
26
+ IUPACName: z.ZodOptional<z.ZodString>;
27
+ Title: z.ZodOptional<z.ZodString>;
28
+ XLogP: z.ZodOptional<z.ZodNumber>;
29
+ ExactMass: z.ZodOptional<z.ZodNumber>;
30
+ MonoisotopicMass: z.ZodOptional<z.ZodNumber>;
31
+ TPSA: z.ZodOptional<z.ZodNumber>;
32
+ Complexity: z.ZodOptional<z.ZodNumber>;
33
+ Charge: z.ZodOptional<z.ZodNumber>;
34
+ HBondDonorCount: z.ZodOptional<z.ZodNumber>;
35
+ HBondAcceptorCount: z.ZodOptional<z.ZodNumber>;
36
+ RotatableBondCount: z.ZodOptional<z.ZodNumber>;
37
+ HeavyAtomCount: z.ZodOptional<z.ZodNumber>;
38
+ CovalentUnitCount: z.ZodOptional<z.ZodNumber>;
39
+ }, "strip", z.ZodTypeAny, {
40
+ CID: number;
41
+ MolecularFormula?: string | undefined;
42
+ MolecularWeight?: number | undefined;
43
+ InChI?: string | undefined;
44
+ InChIKey?: string | undefined;
45
+ IUPACName?: string | undefined;
46
+ Title?: string | undefined;
47
+ XLogP?: number | undefined;
48
+ ExactMass?: number | undefined;
49
+ MonoisotopicMass?: number | undefined;
50
+ TPSA?: number | undefined;
51
+ Complexity?: number | undefined;
52
+ Charge?: number | undefined;
53
+ HBondDonorCount?: number | undefined;
54
+ HBondAcceptorCount?: number | undefined;
55
+ RotatableBondCount?: number | undefined;
56
+ HeavyAtomCount?: number | undefined;
57
+ CovalentUnitCount?: number | undefined;
58
+ }, {
59
+ CID: number;
60
+ MolecularFormula?: string | undefined;
61
+ MolecularWeight?: number | undefined;
62
+ InChI?: string | undefined;
63
+ InChIKey?: string | undefined;
64
+ IUPACName?: string | undefined;
65
+ Title?: string | undefined;
66
+ XLogP?: number | undefined;
67
+ ExactMass?: number | undefined;
68
+ MonoisotopicMass?: number | undefined;
69
+ TPSA?: number | undefined;
70
+ Complexity?: number | undefined;
71
+ Charge?: number | undefined;
72
+ HBondDonorCount?: number | undefined;
73
+ HBondAcceptorCount?: number | undefined;
74
+ RotatableBondCount?: number | undefined;
75
+ HeavyAtomCount?: number | undefined;
76
+ CovalentUnitCount?: number | undefined;
77
+ }>, "many">;
78
+ }, "strip", z.ZodTypeAny, {
79
+ results: {
80
+ CID: number;
81
+ MolecularFormula?: string | undefined;
82
+ MolecularWeight?: number | undefined;
83
+ InChI?: string | undefined;
84
+ InChIKey?: string | undefined;
85
+ IUPACName?: string | undefined;
86
+ Title?: string | undefined;
87
+ XLogP?: number | undefined;
88
+ ExactMass?: number | undefined;
89
+ MonoisotopicMass?: number | undefined;
90
+ TPSA?: number | undefined;
91
+ Complexity?: number | undefined;
92
+ Charge?: number | undefined;
93
+ HBondDonorCount?: number | undefined;
94
+ HBondAcceptorCount?: number | undefined;
95
+ RotatableBondCount?: number | undefined;
96
+ HeavyAtomCount?: number | undefined;
97
+ CovalentUnitCount?: number | undefined;
98
+ }[];
99
+ }, {
100
+ results: {
101
+ CID: number;
102
+ MolecularFormula?: string | undefined;
103
+ MolecularWeight?: number | undefined;
104
+ InChI?: string | undefined;
105
+ InChIKey?: string | undefined;
106
+ IUPACName?: string | undefined;
107
+ Title?: string | undefined;
108
+ XLogP?: number | undefined;
109
+ ExactMass?: number | undefined;
110
+ MonoisotopicMass?: number | undefined;
111
+ TPSA?: number | undefined;
112
+ Complexity?: number | undefined;
113
+ Charge?: number | undefined;
114
+ HBondDonorCount?: number | undefined;
115
+ HBondAcceptorCount?: number | undefined;
116
+ RotatableBondCount?: number | undefined;
117
+ HeavyAtomCount?: number | undefined;
118
+ CovalentUnitCount?: number | undefined;
119
+ }[];
120
+ }>;
121
+ export type PubchemFetchCompoundPropertiesOutput = z.infer<typeof PubchemFetchCompoundPropertiesOutputSchema>;
122
+ /**
123
+ * Core logic for the `pubchem_fetch_compound_properties` tool. It retrieves a list of
124
+ * specified physicochemical properties for one or more PubChem Compound IDs (CIDs).
125
+ *
126
+ * @param {PubchemFetchCompoundPropertiesInput} params - The validated input parameters.
127
+ * @param {RequestContext} context - The request context for logging, tracing, and error handling.
128
+ * @returns {Promise<PubchemFetchCompoundPropertiesOutput>} A promise that resolves with the fetched properties.
129
+ * @throws {McpError} Throws a structured error if the API request fails, CIDs are not found, or the response is malformed.
130
+ */
131
+ export declare function pubchemFetchCompoundPropertiesLogic(params: PubchemFetchCompoundPropertiesInput, context: RequestContext): Promise<PubchemFetchCompoundPropertiesOutput>;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @fileoverview Defines the core logic, schemas, and types for the `pubchem_fetch_compound_properties` tool.
3
+ * @module src/mcp-server/tools/fetchCompoundProperties/logic
4
+ */
5
+ import { z } from "zod";
6
+ import { pubChemApiClient } from "../../../services/pubchem/pubchemApiClient.js";
7
+ import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
8
+ import { logger } from "../../../utils/index.js";
9
+ // 1. Define and export the Zod enum for available compound properties
10
+ export const PubchemCompoundPropertiesEnum = z.enum([
11
+ "MolecularFormula",
12
+ "MolecularWeight",
13
+ "InChI",
14
+ "InChIKey",
15
+ "IUPACName",
16
+ "Title",
17
+ "XLogP",
18
+ "ExactMass",
19
+ "MonoisotopicMass",
20
+ "TPSA",
21
+ "Complexity",
22
+ "Charge",
23
+ "HBondDonorCount",
24
+ "HBondAcceptorCount",
25
+ "RotatableBondCount",
26
+ "HeavyAtomCount",
27
+ "CovalentUnitCount",
28
+ ]);
29
+ // 2. Define and export the Zod schema for input validation
30
+ export const PubchemFetchCompoundPropertiesInputSchema = z.object({
31
+ cids: z
32
+ .array(z.number().int().positive())
33
+ .min(1, "At least one CID is required.")
34
+ .describe("An array of one or more PubChem Compound IDs (CIDs) to fetch properties for. Must be positive integers."),
35
+ properties: z
36
+ .array(PubchemCompoundPropertiesEnum)
37
+ .min(1, "At least one property must be specified.")
38
+ .describe("A list of physicochemical properties to retrieve for each CID."),
39
+ });
40
+ // 4. Define and export the Zod schema for a single compound's properties in the output
41
+ const CompoundPropertiesSchema = z
42
+ .object({
43
+ CID: z.number().int().describe("The PubChem Compound ID."),
44
+ MolecularFormula: z.string().optional(),
45
+ MolecularWeight: z.number().optional(),
46
+ InChI: z.string().optional(),
47
+ InChIKey: z.string().optional(),
48
+ IUPACName: z.string().optional(),
49
+ Title: z.string().optional(),
50
+ XLogP: z.number().optional(),
51
+ ExactMass: z.number().optional(),
52
+ MonoisotopicMass: z.number().optional(),
53
+ TPSA: z.number().optional(),
54
+ Complexity: z.number().optional(),
55
+ Charge: z.number().optional(),
56
+ HBondDonorCount: z.number().int().optional(),
57
+ HBondAcceptorCount: z.number().int().optional(),
58
+ RotatableBondCount: z.number().int().optional(),
59
+ HeavyAtomCount: z.number().int().optional(),
60
+ CovalentUnitCount: z.number().int().optional(),
61
+ })
62
+ .describe("An object containing the requested properties for a single compound.");
63
+ // 5. Define and export the Zod schema for the tool's complete output
64
+ export const PubchemFetchCompoundPropertiesOutputSchema = z.object({
65
+ results: z
66
+ .array(CompoundPropertiesSchema)
67
+ .describe("A list of property results, with one object for each successfully retrieved CID."),
68
+ });
69
+ /**
70
+ * Core logic for the `pubchem_fetch_compound_properties` tool. It retrieves a list of
71
+ * specified physicochemical properties for one or more PubChem Compound IDs (CIDs).
72
+ *
73
+ * @param {PubchemFetchCompoundPropertiesInput} params - The validated input parameters.
74
+ * @param {RequestContext} context - The request context for logging, tracing, and error handling.
75
+ * @returns {Promise<PubchemFetchCompoundPropertiesOutput>} A promise that resolves with the fetched properties.
76
+ * @throws {McpError} Throws a structured error if the API request fails, CIDs are not found, or the response is malformed.
77
+ */
78
+ export async function pubchemFetchCompoundPropertiesLogic(params, context) {
79
+ logger.debug("Processing pubchem_fetch_compound_properties logic...", {
80
+ ...context,
81
+ params,
82
+ });
83
+ const { cids, properties } = params;
84
+ const cidsString = cids.join(",");
85
+ const propertiesString = properties.join(",");
86
+ const path = `/compound/cid/${cidsString}/property/${propertiesString}/JSON`;
87
+ const response = await pubChemApiClient.get(path, context);
88
+ logger.debug("Raw PubChem response for pubchem_fetch_compound_properties", {
89
+ ...context,
90
+ response,
91
+ });
92
+ if (!response || !response.PropertyTable?.Properties) {
93
+ throw new McpError(BaseErrorCode.NOT_FOUND, "Received an unexpected response format from PubChem API. Ensure CIDs are valid.", { ...context, cids, response });
94
+ }
95
+ const result = {
96
+ results: response.PropertyTable.Properties,
97
+ };
98
+ logger.info(`Successfully fetched properties for ${result.results.length} CIDs.`, context);
99
+ return result;
100
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @fileoverview Handles the registration of the `pubchem_fetch_compound_properties` tool.
3
+ * @module src/mcp-server/tools/fetchCompoundProperties/registration
4
+ */
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ /**
7
+ * Registers the 'pubchem_fetch_compound_properties' tool with the MCP server.
8
+ * This tool fetches a list of specified physicochemical properties for one or more
9
+ * PubChem Compound IDs (CIDs).
10
+ *
11
+ * @param {McpServer} server - The MCP server instance to register the tool with.
12
+ */
13
+ export declare const registerPubchemFetchCompoundPropertiesTool: (server: McpServer) => Promise<void>;