Skip to main content
Glama

call_nodit_api

Execute blockchain API calls to access and process real-time data across multiple networks like Ethereum and Polygon using operation IDs.

Instructions

This function calls a specific Nodit Blockchain Context API using its operationId. Before making the call, it's recommended to verify the detailed API specifications using the 'get_nodit_api_spec' tool. Please note that using this tool will consume your API quota.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
chainYesNodit chain to call. e.g. 'ethereum' or 'polygon'.
networkYesNodit network to call. e.g. 'mainnet' or 'amoy'.
operationIdYesNodit API operationId to call.
requestBodyYesJSON request body matching the API's spec.

Implementation Reference

  • The core handler function that implements the 'call_nodit_api' tool. It validates the operationId, determines if it's a node or data API, constructs the appropriate API URL, checks API key, makes a POST request with timeout, handles various HTTP errors with customized user-friendly messages, parses the JSON response, and returns it as tool content.
    async ({ chain, network, operationId, requestBody }) => { const toolName = "call_nodit_api"; if (isWebhookApi(operationId)) { return createErrorResponse( `The Nodit Webhook APIs cannot be invoked via "${toolName}".`, toolName, ) } if (isBlockedOperationId(operationId)) { return createErrorResponse( `The operationId(${operationId}) cannot be invoked via "${toolName}".`, toolName, ) } const apiKey = process.env.NODIT_API_KEY; if (!apiKey) { return createErrorResponse(`NODIT_API_KEY environment variable is not set. It is required to call nodit api. Please check your tool configuration.`, toolName); } const isNodeApiCall = isNodeApi(operationId); const canFindOperationId = isNodeApiCall ? isValidNodeApi(operationId, noditNodeApiSpecMap) : findNoditDataApiDetails(operationId, noditDataApiSpec) if (!canFindOperationId) { return createErrorResponse(`Invalid operationId '${operationId}'. Use 'list_nodit_data_apis' or 'list_nodit_node_apis' first.`, toolName); } const commonMistakeForOperationIdRules = isNodeApiCall && chain !== "ethereum" && !operationId.includes("-") if (commonMistakeForOperationIdRules) { return createErrorResponse(`Invalid operationId '${operationId}'. For non-ethereum chains, operationId must include the chain prefix.`, toolName); } let apiUrl; if (isNodeApiCall) { const apiUrlTemplate = findNoditNodeApiSpec(operationId, noditNodeApiSpecMap)!.servers[0].url apiUrl = apiUrlTemplate.replace(`{${chain}-network}`, `${chain}-${network}`) } else { const noditDataApiPath = Object.entries(noditDataApiSpec.paths).find(([, spec]) => spec.post?.operationId === operationId) if (!noditDataApiPath) { return createErrorResponse(`Invalid operationId '${operationId}'. No API URL found for operationId '${operationId}'.`, toolName); } const apiUrlTemplate = noditDataApiSpec.servers[0].url + noditDataApiPath[0]; apiUrl = apiUrlTemplate.replace('{chain}/{network}', `${chain}/${network}`) } if (!apiUrl) { return createErrorResponse(`Invalid operationId '${operationId}'. No API URL found for operationId '${operationId}'.`, toolName); } const { signal, cleanup } = createTimeoutSignal(TIMEOUT_MS); try { const apiOptions: RequestInit = { method: 'POST', headers: { 'X-API-KEY': apiKey, 'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'nodit-mcp-server' }, body: JSON.stringify(requestBody), signal, } log(`Calling apiUrl: ${apiUrl}, apiOptions: ${JSON.stringify(apiOptions, null, 2)}`); const response = await fetch(apiUrl, apiOptions); const responseBodyText = await response.text(); if (!response.ok) { const statusMessages: Record<number, string> = { 400: `${responseBodyText}. Help the user identify what went wrong in their request. Explain the likely issue based on the error message, and provide a corrected example if possible.`, 403: `${responseBodyText}. Let the user know that this API is only available to paid plan users. Explain that their current plan does not include access, and suggest upgrading to a paid tier via https://nodit.io/pricing .`, 404: `${responseBodyText}. Let the user know that no data was found for the provided ID or address. This usually means the resource doesn't exist or hasn't been indexed yet. Suggest double-checking the input or trying again later.`, 429: `${responseBodyText}. Inform the user that they've reached their current plan's usage limit. Recommend reviewing their usage or upgrading via https://nodit.io/pricing. Optionally mention the Referral Program: https://developer.nodit.io/docs/referral-program.`, 500: `${responseBodyText}. This is not the user's fault. Let them know it's likely a temporary issue. Suggest retrying soon or contacting support at https://developer.nodit.io/discuss if the problem continues.`, 503: `${responseBodyText}. Inform the user that the service may be under maintenance or experiencing high load. Suggest retrying shortly, and checking the Notice section in the Nodit Developer Portal (https://developer.nodit.io).` }; if (statusMessages[response.status]) { return createErrorResponse(statusMessages[response.status], toolName); } let errorDetails = `Raw error response: ${responseBodyText}`; try { const errorJson = JSON.parse(responseBodyText); errorDetails = `Error Details (JSON):\n${JSON.stringify(errorJson, null, 2)}`; } catch (e) { /* ignore parsing error, use raw text */ } return createErrorResponse(`API Error (Status ${response.status}). ${errorDetails}`, toolName); } try { JSON.parse(responseBodyText); log(`Tool (${toolName}): API Success (${response.status}) for ${operationId}`); return { content: [{ type: "text", text: responseBodyText }] }; } catch (parseError) { return createErrorResponse(`API returned OK status but body was not valid JSON. Raw response: ${responseBodyText}`, toolName); } } catch (error) { let message = (error as Error).message; if (error instanceof Error && error.name === 'AbortError') { message = `The request took longer than expected and has been terminated. This may be due to high server load or because the requested data is taking longer to process. Please try again later.`; } return createErrorResponse(`Network/fetch error calling API: ${message}`, toolName); } finally { cleanup(); } } );
  • Zod-based input schema defining the parameters for the 'call_nodit_api' tool: chain, network, operationId, and requestBody.
    { chain: z.string().describe("Nodit chain to call. e.g. 'ethereum' or 'polygon'."), network: z.string().describe("Nodit network to call. e.g. 'mainnet' or 'amoy'."), operationId: z.string().describe("Nodit API operationId to call."), requestBody: z.record(z.any()).describe("JSON request body matching the API's spec."), },
  • Registers the 'call_nodit_api' tool on the McpServer instance, loading necessary API specs, defining name, description, input schema, and handler function.
    export function registerCallNoditApiTool(server: McpServer) { const noditNodeApiSpecMap: Map<string, NoditOpenApiSpecType> = loadNoditNodeApiSpecMap(); const noditDataApiSpec: NoditOpenApiSpecType = loadNoditDataApiSpec(); server.tool( "call_nodit_api", "This function calls a specific Nodit Blockchain Context API using its operationId. Before making the call, it's recommended to verify the detailed API specifications using the 'get_nodit_api_spec' tool. Please note that using this tool will consume your API quota.", { chain: z.string().describe("Nodit chain to call. e.g. 'ethereum' or 'polygon'."), network: z.string().describe("Nodit network to call. e.g. 'mainnet' or 'amoy'."), operationId: z.string().describe("Nodit API operationId to call."), requestBody: z.record(z.any()).describe("JSON request body matching the API's spec."), }, async ({ chain, network, operationId, requestBody }) => { const toolName = "call_nodit_api"; if (isWebhookApi(operationId)) { return createErrorResponse( `The Nodit Webhook APIs cannot be invoked via "${toolName}".`, toolName, ) } if (isBlockedOperationId(operationId)) { return createErrorResponse( `The operationId(${operationId}) cannot be invoked via "${toolName}".`, toolName, ) } const apiKey = process.env.NODIT_API_KEY; if (!apiKey) { return createErrorResponse(`NODIT_API_KEY environment variable is not set. It is required to call nodit api. Please check your tool configuration.`, toolName); } const isNodeApiCall = isNodeApi(operationId); const canFindOperationId = isNodeApiCall ? isValidNodeApi(operationId, noditNodeApiSpecMap) : findNoditDataApiDetails(operationId, noditDataApiSpec) if (!canFindOperationId) { return createErrorResponse(`Invalid operationId '${operationId}'. Use 'list_nodit_data_apis' or 'list_nodit_node_apis' first.`, toolName); } const commonMistakeForOperationIdRules = isNodeApiCall && chain !== "ethereum" && !operationId.includes("-") if (commonMistakeForOperationIdRules) { return createErrorResponse(`Invalid operationId '${operationId}'. For non-ethereum chains, operationId must include the chain prefix.`, toolName); } let apiUrl; if (isNodeApiCall) { const apiUrlTemplate = findNoditNodeApiSpec(operationId, noditNodeApiSpecMap)!.servers[0].url apiUrl = apiUrlTemplate.replace(`{${chain}-network}`, `${chain}-${network}`) } else { const noditDataApiPath = Object.entries(noditDataApiSpec.paths).find(([, spec]) => spec.post?.operationId === operationId) if (!noditDataApiPath) { return createErrorResponse(`Invalid operationId '${operationId}'. No API URL found for operationId '${operationId}'.`, toolName); } const apiUrlTemplate = noditDataApiSpec.servers[0].url + noditDataApiPath[0]; apiUrl = apiUrlTemplate.replace('{chain}/{network}', `${chain}/${network}`) } if (!apiUrl) { return createErrorResponse(`Invalid operationId '${operationId}'. No API URL found for operationId '${operationId}'.`, toolName); } const { signal, cleanup } = createTimeoutSignal(TIMEOUT_MS); try { const apiOptions: RequestInit = { method: 'POST', headers: { 'X-API-KEY': apiKey, 'Accept': 'application/json', 'Content-Type': 'application/json', 'User-Agent': 'nodit-mcp-server' }, body: JSON.stringify(requestBody), signal, } log(`Calling apiUrl: ${apiUrl}, apiOptions: ${JSON.stringify(apiOptions, null, 2)}`); const response = await fetch(apiUrl, apiOptions); const responseBodyText = await response.text(); if (!response.ok) { const statusMessages: Record<number, string> = { 400: `${responseBodyText}. Help the user identify what went wrong in their request. Explain the likely issue based on the error message, and provide a corrected example if possible.`, 403: `${responseBodyText}. Let the user know that this API is only available to paid plan users. Explain that their current plan does not include access, and suggest upgrading to a paid tier via https://nodit.io/pricing .`, 404: `${responseBodyText}. Let the user know that no data was found for the provided ID or address. This usually means the resource doesn't exist or hasn't been indexed yet. Suggest double-checking the input or trying again later.`, 429: `${responseBodyText}. Inform the user that they've reached their current plan's usage limit. Recommend reviewing their usage or upgrading via https://nodit.io/pricing. Optionally mention the Referral Program: https://developer.nodit.io/docs/referral-program.`, 500: `${responseBodyText}. This is not the user's fault. Let them know it's likely a temporary issue. Suggest retrying soon or contacting support at https://developer.nodit.io/discuss if the problem continues.`, 503: `${responseBodyText}. Inform the user that the service may be under maintenance or experiencing high load. Suggest retrying shortly, and checking the Notice section in the Nodit Developer Portal (https://developer.nodit.io).` }; if (statusMessages[response.status]) { return createErrorResponse(statusMessages[response.status], toolName); } let errorDetails = `Raw error response: ${responseBodyText}`; try { const errorJson = JSON.parse(responseBodyText); errorDetails = `Error Details (JSON):\n${JSON.stringify(errorJson, null, 2)}`; } catch (e) { /* ignore parsing error, use raw text */ } return createErrorResponse(`API Error (Status ${response.status}). ${errorDetails}`, toolName); } try { JSON.parse(responseBodyText); log(`Tool (${toolName}): API Success (${response.status}) for ${operationId}`); return { content: [{ type: "text", text: responseBodyText }] }; } catch (parseError) { return createErrorResponse(`API returned OK status but body was not valid JSON. Raw response: ${responseBodyText}`, toolName); } } catch (error) { let message = (error as Error).message; if (error instanceof Error && error.name === 'AbortError') { message = `The request took longer than expected and has been terminated. This may be due to high server load or because the requested data is taking longer to process. Please try again later.`; } return createErrorResponse(`Network/fetch error calling API: ${message}`, toolName); } finally { cleanup(); } } ); }
  • Imports and calls registerCallNoditApiTool within the registerAllTools function to include it in the overall toolset.
    import { registerCallNoditApiTool } from "./call-nodit-api.js"; export function registerAllTools(server: McpServer) { registerApiCategoriesTools(server); registerNodeApiTools(server); registerDataApiTools(server); registerWebhookApiTools(server); registerAptosIndexerTools(server); registerGetNoditApiSpecTool(server); registerCallNoditApiTool(server);
  • src/index.ts:4-16 (registration)
    Top-level call to registerAllTools in the main server initialization, which indirectly registers the 'call_nodit_api' tool.
    import { registerAllTools } from "./tools/index.js"; async function main() { const server = new McpServer({ name: "nodit-blockchain-context", version: "1.0.0", capabilities: { resources: {}, tools: {}, }, }); registerAllTools(server);

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/noditlabs/nodit-mcp-server'

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