Skip to main content
Glama

discover_pools

Find Cardano DEX liquidity pools for specific native tokens using Iris API data to analyze trading opportunities.

Instructions

Discover Cardano DEX liquidity pools for a native token via Iris API

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
symbolYesCardano token symbol (INDY, SNEK, MIN, NIGHT)

Implementation Reference

  • The main handler implementation of the discover_pools tool. It fetches liquidity pools from the Iris API for a given Cardano token symbol, filters pools matching the token's policy ID, sorts by TVL, and returns pool details including DEX name, TVL, reserves, price, and active status.
    server.tool(
      'discover_pools',
      'Discover Cardano DEX liquidity pools for a native token via Iris API',
      {
        symbol: z.string().describe('Cardano token symbol (INDY, SNEK, MIN, NIGHT)'),
      },
      async ({ symbol }) => {
        const upper = symbol.toUpperCase();
        const token = SUPPORTED_TOKENS[upper];
        if (!token) {
          throw new Error(
            `Unsupported token: ${symbol}. Supported: ${Object.keys(SUPPORTED_TOKENS).join(', ')}`
          );
        }
    
        const allPools = await fetchIrisPools();
        const tokenPools = allPools
          .filter((p: any) => matchesToken(p, token.policyId))
          .sort((a: any, b: any) => (b.state?.tvl || 0) - (a.state?.tvl || 0));
    
        return {
          content: [
            {
              type: 'text' as const,
              text: JSON.stringify(
                {
                  symbol: upper,
                  totalPools: tokenPools.length,
                  pools: tokenPools.map((p: any) => ({
                    identifier: p.identifier,
                    dex: p.dex || 'unknown',
                    tvl: p.state?.tvl || 0,
                    reserveA: p.state?.reserveA || 0,
                    reserveB: p.state?.reserveB || 0,
                    price: p.state?.price || null,
                    isActive: p.isActive !== false,
                  })),
                  timestamp: new Date().toISOString(),
                },
                null,
                2
              ),
            },
          ],
        };
      }
    );
  • Helper function fetchIrisPools() that fetches liquidity pools data from the Iris API endpoint. Used by discover_pools to retrieve all available pools.
    async function fetchIrisPools(): Promise<any[]> {
      const resp = await fetch(`${IRIS_BASE_URL}/api/liquidity-pools`, {
        headers: { 'User-Agent': 'OpenMM-MCP-Agent/1.0' },
        signal: AbortSignal.timeout(10000),
      });
      if (!resp.ok) {
        throw new Error(`Iris API error: ${resp.status}`);
      }
      const data = await resp.json();
      return data?.data || data || [];
    }
  • Helper function matchesToken() that checks if a pool contains a token with a specific policy ID. Used by discover_pools to filter pools for the requested token.
    function matchesToken(pool: any, policyId: string): boolean {
      const tokenA = pool.pair?.tokenA || pool.tokenA;
      const tokenB = pool.pair?.tokenB || pool.tokenB;
      return tokenA?.policyId === policyId || tokenB?.policyId === policyId;
    }
  • The registerCardanoTools function that registers both get_cardano_price and discover_pools tools with the MCP server. The discover_pools tool is registered starting at line 198.
    export function registerCardanoTools(server: McpServer): void {
      server.tool(
        'get_cardano_price',
        'Get aggregated price for a Cardano native token from DEX liquidity pools (TOKEN/USDT via ADA bridge)',
        {
          symbol: z.string().describe('Cardano token symbol (INDY, SNEK, MIN, NIGHT)'),
        },
        async ({ symbol }) => {
          const upper = symbol.toUpperCase();
          const token = SUPPORTED_TOKENS[upper];
          if (!token) {
            throw new Error(
              `Unsupported token: ${symbol}. Supported: ${Object.keys(SUPPORTED_TOKENS).join(', ')}`
            );
          }
    
          const [adaPrice, allPools] = await Promise.all([fetchADAUSDT(), fetchIrisPools()]);
    
          const tokenPools = allPools
            .filter((p: any) => matchesToken(p, token.policyId))
            .filter((p: any) => (p.state?.tvl || 0) >= token.minLiquidity)
            .sort((a: any, b: any) => (b.state?.tvl || 0) - (a.state?.tvl || 0))
            .slice(0, 3);
    
          if (tokenPools.length === 0) {
            throw new Error(`No liquidity pools found for ${upper} above minimum TVL threshold`);
          }
    
          const identifiers = tokenPools.map((p: any) => p.identifier).filter(Boolean);
          let tokenAdaPrice: number;
    
          if (identifiers.length > 0) {
            const prices = await fetchIrisPrices(identifiers);
            if (prices.length > 0) {
              const totalTvl = tokenPools.reduce((sum: number, p: any) => sum + (p.state?.tvl || 0), 0);
              tokenAdaPrice = tokenPools.reduce((sum: number, p: any, i: number) => {
                const weight = (p.state?.tvl || 0) / totalTvl;
                return sum + (prices[i] || 0) * weight;
              }, 0);
            } else {
              tokenAdaPrice =
                tokenPools.reduce((sum: number, p: any) => sum + (p.state?.price || 0), 0) /
                tokenPools.length;
            }
          } else {
            tokenAdaPrice =
              tokenPools.reduce((sum: number, p: any) => sum + (p.state?.price || 0), 0) /
              tokenPools.length;
          }
    
          const tokenUsdtPrice = tokenAdaPrice * adaPrice.price;
          const confidence = Math.min(tokenPools.length / 3, 1);
    
          return {
            content: [
              {
                type: 'text' as const,
                text: JSON.stringify(
                  {
                    symbol: `${upper}/USDT`,
                    price: tokenUsdtPrice,
                    tokenAdaPrice,
                    adaUsdtPrice: adaPrice.price,
                    confidence,
                    poolsUsed: tokenPools.length,
                    sources: {
                      ada: adaPrice.sources,
                      pools: tokenPools.map((p: any) => ({
                        dex: p.dex || 'unknown',
                        tvl: p.state?.tvl,
                      })),
                    },
                    timestamp: new Date().toISOString(),
                  },
                  null,
                  2
                ),
              },
            ],
          };
        }
      );
    
      server.tool(
        'discover_pools',
        'Discover Cardano DEX liquidity pools for a native token via Iris API',
        {
          symbol: z.string().describe('Cardano token symbol (INDY, SNEK, MIN, NIGHT)'),
        },
        async ({ symbol }) => {
          const upper = symbol.toUpperCase();
          const token = SUPPORTED_TOKENS[upper];
          if (!token) {
            throw new Error(
              `Unsupported token: ${symbol}. Supported: ${Object.keys(SUPPORTED_TOKENS).join(', ')}`
            );
          }
    
          const allPools = await fetchIrisPools();
          const tokenPools = allPools
            .filter((p: any) => matchesToken(p, token.policyId))
            .sort((a: any, b: any) => (b.state?.tvl || 0) - (a.state?.tvl || 0));
    
          return {
            content: [
              {
                type: 'text' as const,
                text: JSON.stringify(
                  {
                    symbol: upper,
                    totalPools: tokenPools.length,
                    pools: tokenPools.map((p: any) => ({
                      identifier: p.identifier,
                      dex: p.dex || 'unknown',
                      tvl: p.state?.tvl || 0,
                      reserveA: p.state?.reserveA || 0,
                      reserveB: p.state?.reserveB || 0,
                      price: p.state?.price || null,
                      isActive: p.isActive !== false,
                    })),
                    timestamp: new Date().toISOString(),
                  },
                  null,
                  2
                ),
              },
            ],
          };
        }
      );
    }
  • src/worker.ts:18-47 (registration)
    Worker endpoint that exposes the MCP server capabilities, listing discover_pools as one of the available tools in the server card JSON response.
    if (url.pathname === '/.well-known/mcp/server-card.json' && request.method === 'GET') {
      const card = {
        name: 'openmm-mcp-agent',
        version: '1.0.4',
        description:
          'MCP server for OpenMM — exposes market data, account, trading, and strategy tools to AI agents',
        url: 'https://openmm-mcp.qbtlabs.io/mcp',
        transport: { type: 'streamable-http' },
        capabilities: {
          tools: [
            { name: 'get_ticker' },
            { name: 'get_orderbook' },
            { name: 'get_trades' },
            { name: 'get_balance' },
            { name: 'list_orders' },
            { name: 'create_order' },
            { name: 'cancel_order' },
            { name: 'cancel_all_orders' },
            { name: 'start_grid_strategy' },
            { name: 'stop_strategy' },
            { name: 'get_strategy_status' },
            { name: 'get_cardano_price' },
            { name: 'discover_pools' },
          ],
        },
      };
      return new Response(JSON.stringify(card), {
        headers: { 'Content-Type': 'application/json' },
      });
    }

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/QBT-Labs/openmm-mcp'

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