Skip to main content
Glama
MissionSquad

MCP Avantage

by MissionSquad

crypto_daily

Fetch daily cryptocurrency time series data for analysis and tracking by specifying symbol and market parameters.

Instructions

Fetches daily time series data for a cryptocurrency.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
symbolYesThe cryptocurrency symbol (e.g., "BTC").
marketYesThe exchange market (e.g., "USD", "EUR").
datatypeNoData format for the response.json

Implementation Reference

  • src/index.ts:511-522 (registration)
    Registration of the 'crypto_daily' MCP tool, including name, description, input schema reference, and execute handler that wraps the AVantage library call.
    server.addTool({
      name: "crypto_daily",
      description: "Fetches daily time series data for a cryptocurrency.",
      parameters: schemas.CryptoTimeSeriesParamsSchema,
      execute: (
        args,
        context // Let type be inferred
      ) =>
        executeAvantageTool("crypto_daily", args, context, (av, params) =>
          av.crypto.daily(params)
        ),
    });
  • Zod schema defining the input parameters for the crypto_daily tool: cryptocurrency symbol, market (e.g., USD), and optional datatype.
    export const CryptoTimeSeriesParamsSchema = z.object({
      symbol: z.string().describe('The cryptocurrency symbol (e.g., "BTC").'),
      market: z.string().describe('The exchange market (e.g., "USD", "EUR").'),
      datatype: DatatypeSchema.default('json').optional(),
    }).describe('Parameters for fetching daily/weekly/monthly crypto time series data.')
  • Generic async handler function executed by crypto_daily (and other tools). Manages authentication, AVantage client lifecycle, invokes av.crypto.daily(params), processes response, and handles errors.
    async function executeAvantageTool<TArgs, TResult>(
      toolName: string,
      args: TArgs,
      context: Context<Record<string, unknown> | undefined>, // Use the imported Context type directly
      avantageMethod: (
        av: AVantage,
        args: TArgs
      ) => Promise<{ error?: boolean; reason?: string; data?: TResult }>
    ): Promise<string> {
      logger.info(`Executing '${toolName}' tool for request ID: ${context}`);
      logger.debug(`Args for ${toolName}: ${JSON.stringify(args)}`);
    
      // --- Authentication & Resource Management ---
      // Access extraArgs safely - it might be null or undefined
      const extraArgsApiKey = context.extraArgs?.apiKey as string | undefined;
      const apiKey = extraArgsApiKey || config.apiKey;
    
      if (!apiKey) {
        logger.error(`'${toolName}' failed: Alpha Vantage API key missing.`);
        throw new UserError(apiKeyErrorMessage);
      }
      logger.debug(
        `Using AV API key (source: ${extraArgsApiKey ? "extraArgs" : "environment"}) for ${toolName}`
      );
    
      try {
        // Get or create AVantage instance managed by ResourceManager
        const av = await resourceManager.getResource<AVantage>(
          apiKey, // Cache key is the resolved API key
          "avantage_client", // Type identifier for logging
          async (key) => {
            // Factory Function
            logger.info(
              `Creating new AVantage instance for key ending ...${key.slice(-4)}`
            );
            // AVantage library reads AV_PREMIUM from process.env internally
            return new AVantage(key);
          },
          async (avInstance) => {
            // Cleanup Function (no-op needed for AVantage)
            logger.debug(`Destroying AVantage instance (no-op)`);
          }
        );
    
        // --- Library Call ---
        const result = await avantageMethod(av, args);
    
        // --- Response Handling ---
        if (result.error) {
          logger.warn(
            `'${toolName}' failed. Reason from avantage: ${result.reason}`
          );
          throw new UserError(result.reason || `Tool '${toolName}' failed.`);
        }
    
        if (result.data === undefined || result.data === null) {
          logger.warn(`'${toolName}' completed successfully but returned no data.`);
          return "null"; // Return string "null" for empty data
        }
    
        logger.info(`'${toolName}' completed successfully.`);
        // Stringify the data part of the response
        return JSON.stringify(result.data);
      } catch (error: any) {
        logger.error(
          `Error during execution of '${toolName}': ${error.message}`,
          error
        );
        // If it's already a UserError, rethrow it
        if (error instanceof UserError) {
          throw error;
        }
        // Otherwise, wrap it in a UserError
        throw new UserError(
          `An unexpected error occurred while executing tool '${toolName}': ${error.message}`
        );
      }
    }
  • Helper code within executeAvantageTool for obtaining/managing AVantage API client instance via resourceManager, used by crypto_daily.
    // Get or create AVantage instance managed by ResourceManager
    const av = await resourceManager.getResource<AVantage>(
      apiKey, // Cache key is the resolved API key
      "avantage_client", // Type identifier for logging
      async (key) => {
        // Factory Function
        logger.info(
          `Creating new AVantage instance for key ending ...${key.slice(-4)}`
        );
        // AVantage library reads AV_PREMIUM from process.env internally
        return new AVantage(key);
      },
      async (avInstance) => {
        // Cleanup Function (no-op needed for AVantage)
        logger.debug(`Destroying AVantage instance (no-op)`);
      }
    );
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/MissionSquad/mcp-avantage'

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