Skip to main content
Glama
JCF0

CG Alpha MCP

by JCF0

elfa_set_base

Configure the base URL for ELFA's sentiment data API to enable crypto market analysis with combined sentiment and technical indicators.

Instructions

Set ELFA base URL (e.g., https://api.elfa.ai).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
baseYes

Implementation Reference

  • The main handler function for the 'elfa_set_base' tool. It extracts the 'base' parameter from args, validates it as a URL, sets the global ELFA_BASE variable, and returns success or error response.
    "elfa_set_base": async (args) => {
      const base = args && args.base;
      try { const u = new URL(base); ELFA_BASE = u.toString().replace(/\/+$/,""); return { content: textContent({ ok:true, base: ELFA_BASE }) }; }
      catch { return { content: textContent({ ok:false, message:"Invalid URL for 'base'" }), isError:true }; }
    },
  • The schema definition for the 'elfa_set_base' tool, specifying input schema requiring a 'base' string, description, and annotations.
    { name:"elfa_set_base",
      description:"Set ELFA base URL (e.g., https://api.elfa.ai).",
      inputSchema:{ type:"object", properties:{ base:{type:"string"} }, required:["base"] },
      annotations:{ title:"ELFA: Set Base URL", readOnlyHint:false, openWorldHint:false }
    },
  • mcp-server.js:123-262 (registration)
    The toolHandlers object registers the 'elfa_set_base' handler function, which is used in tools/call method.
    const toolHandlers = {
      // Admin: set auth
      "elfa_set_auth": async (args) => {
        const key = args && args.key;
        const headerName = args && args.headerName;
        const scheme = args && args.scheme;
        if (!key || typeof key !== "string") return { content: textContent({ ok:false, message:"Missing 'key' (string)" }), isError:true };
        if (headerName && typeof headerName === "string") ELFA_AUTH.headerName = headerName;
        if (scheme !== undefined && typeof scheme === "string") ELFA_AUTH.scheme = scheme;
        ELFA_AUTH.key = key;
        return { content: textContent({ ok:true, headerName: ELFA_AUTH.headerName || "", scheme: ELFA_AUTH.scheme || "", key: maskKey(ELFA_AUTH.key) }) };
      },
    
      // Admin: set base URL
      "elfa_set_base": async (args) => {
        const base = args && args.base;
        try { const u = new URL(base); ELFA_BASE = u.toString().replace(/\/+$/,""); return { content: textContent({ ok:true, base: ELFA_BASE }) }; }
        catch { return { content: textContent({ ok:false, message:"Invalid URL for 'base'" }), isError:true }; }
      },
    
      // Admin: reload .env (no restart)
      "elfa_reload_env": async () => {
        loadEnvMulti();
        ELFA_AUTH = buildAuthFromEnv();
        ELFA_BASE = (process.env.ELFA_BASE || ELFA_BASE).replace(/\/+$/,"");
        return { content: textContent({
          ok: true,
          base: ELFA_BASE,
          loaded: ENV_INFO.loaded,
          from: ENV_INFO.from,
          vars: ENV_INFO.vars,
          auth: { headerName: ELFA_AUTH.headerName || "", scheme: ELFA_AUTH.scheme || "", key: maskKey(ELFA_AUTH.key) }
        }) };
      },
    
      // Admin: status
      "elfa_status": async () => {
        return { content: textContent({
          base: ELFA_BASE,
          loaded: ENV_INFO.loaded,
          from: ENV_INFO.from,
          vars: ENV_INFO.vars,
          auth: { headerName: ELFA_AUTH.headerName || "", scheme: ELFA_AUTH.scheme || "", key: maskKey(ELFA_AUTH.key) }
        }) };
      },
    
      // Generic proxy
      "elfa_query": async (args, meta) => {
        const path = args && args.path;
        if (!path || typeof path !== "string") return { content: textContent({ error:true, message:"Missing required 'path' (string)" }), isError:true };
        const method = (args.method || "GET").toUpperCase();
        const query  = args.query || undefined;
        const body   = args.body  || undefined;
        progressNotify(meta && meta.progressToken, 1, 3, "Calling ELFA");
        const { ok, status, data } = await elfaFetch(path, { method, query, body });
        progressNotify(meta && meta.progressToken, 2, 3, "Formatting result");
        if (!ok) return { content: textContent({ error:true, status, data }), isError:true, _meta:{ status } };
        progressNotify(meta && meta.progressToken, 3, 3, "Done");
        return { content: textContent({ ok:true, status, data }) };
      },
    
      // /v2/aggregations/trending-tokens  (this replaces the old /v2/data/trending)
      "elfa_trending": async (args, meta) => {
        return toolHandlers["elfa_trending_tokens"](args, meta);
      },
    
      "elfa_trending_tokens": async (args, meta) => {
        const query = {};
        if (args && args.timeframe !== undefined) query.timeframe = args.timeframe; // "24h","7d","30d"
        if (args && args.chain     !== undefined) query.chain     = args.chain;
        if (args && args.limit     !== undefined) query.limit     = args.limit;
        if (args && args.cursor    !== undefined) query.cursor    = args.cursor;
        return toolHandlers["elfa_query"]({ path: "/v2/aggregations/trending-tokens", method: "GET", query }, meta);
      },
    
      // /v2/data/token-news
      "elfa_token_news": async (args, meta) => {
        const query = {};
        if (args && args.symbols !== undefined) query.symbols = args.symbols; // "ETH,BTC"
        if (args && args.chain   !== undefined) query.chain   = args.chain;
        if (args && args.start   !== undefined) query.start   = args.start;
        if (args && args.end     !== undefined) query.end     = args.end;
        if (args && args.limit   !== undefined) query.limit   = args.limit;
        if (args && args.cursor  !== undefined) query.cursor  = args.cursor;
        if (args && args.sources !== undefined) query.sources = args.sources;
        return toolHandlers["elfa_query"]({ path: "/v2/data/token-news", method: "GET", query }, meta);
      },
    
      // /v2/data/keyword-mentions
      "elfa_keyword_mentions": async (args, meta) => {
        const query = {};
        if (args && args.keywords !== undefined) query.keywords = Array.isArray(args.keywords) ? args.keywords.join(",") : String(args.keywords);
        if (args && args.start   !== undefined) query.start   = args.start;
        if (args && args.end     !== undefined) query.end     = args.end;
        if (args && args.chain   !== undefined) query.chain   = args.chain;
        if (args && args.limit   !== undefined) query.limit   = args.limit;
        if (args && args.cursor  !== undefined) query.cursor  = args.cursor;
        if (args && args.sources !== undefined) query.sources = args.sources;
        return toolHandlers["elfa_query"]({ path: "/v2/data/keyword-mentions", method: "GET", query }, meta);
      },
    
      // ----- TA tools -----
    
      // Compute RSI on an array of closes (oldest → newest)
      "ta_rsi": async (args) => {
        const values = Array.isArray(args?.values) ? args.values : null;
        const period = Number.isFinite(Number(args?.period)) ? Number(args.period) : 14;
        if (!values || values.length === 0) {
          return { content: textContent({ error:true, message:"'values' must be a non-empty array of numbers (oldest → newest)" }), isError:true };
        }
        const out = taRSI(values, period);
        return { content: textContent({ ok:true, rsi: out, period }) };
      },
    
      // Compute Bollinger Bands on an array of closes (oldest → newest)
      "ta_bollinger": async (args) => {
        const values = Array.isArray(args?.values) ? args.values : null;
        const period = Number.isFinite(Number(args?.period)) ? Number(args.period) : 20;
        const mult   = Number.isFinite(Number(args?.mult))   ? Number(args.mult)   : 2;
        if (!values || values.length === 0) {
          return { content: textContent({ error:true, message:"'values' must be a non-empty array of numbers (oldest → newest)" }), isError:true };
        }
        const out = taBoll(values, period, mult);
        return { content: textContent({ ok:true, ...out, period, mult }) };
      },
    
      // Convenience: return both indicators in one call
      "ta_summary": async (args) => {
        const values = Array.isArray(args?.values) ? args.values : null;
        const rsiPeriod = Number.isFinite(Number(args?.rsiPeriod)) ? Number(args.rsiPeriod) : 14;
        const bbPeriod  = Number.isFinite(Number(args?.bbPeriod))  ? Number(args.bbPeriod)  : 20;
        const bbMult    = Number.isFinite(Number(args?.bbMult))    ? Number(args.bbMult)    : 2;
        if (!values || values.length === 0) {
          return { content: textContent({ error:true, message:"'values' must be a non-empty array of numbers (oldest → newest)" }), isError:true };
        }
        const rsiVal = taRSI(values, rsiPeriod);
        const bbVal  = taBoll(values, bbPeriod, bbMult);
        return { content: textContent({ ok:true, rsi: rsiVal, bollinger: bbVal, rsiPeriod, bbPeriod, bbMult }) };
      }
    };

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/JCF0/cg-alpha-mcp'

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