Skip to main content
Glama
horustechltd

horus-flow-mcp

by horustechltd

scan_crypto_flow

Scan multiple cryptocurrencies for orderflow signals to assess portfolio-wide risk. Returns strongest buy/sell signals sorted by confidence.

Instructions

Scan multiple cryptocurrencies for orderflow signals at once.

Returns a summary with strongest buy/sell signals and individual results
sorted by confidence. Use this for portfolio-wide risk assessment.

Args:
    symbols: Comma-separated trading pairs (default: BTC, ETH, SOL, BNB, XRP)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
symbolsNoBTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,XRPUSDT

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Tool 3: Multi-Symbol Scanner - async function decorated with @mcp.tool() that scans multiple crypto symbols for orderflow signals simultaneously using asyncio.gather, sorts results by confidence, and returns a JSON summary with strongest buy/sell signals.
    @mcp.tool()
    async def scan_crypto_flow(symbols: str = "BTCUSDT,ETHUSDT,SOLUSDT,BNBUSDT,XRPUSDT") -> str:
        """Scan multiple cryptocurrencies for orderflow signals at once.
        
        Returns a summary with strongest buy/sell signals and individual results
        sorted by confidence. Use this for portfolio-wide risk assessment.
        
        Args:
            symbols: Comma-separated trading pairs (default: BTC, ETH, SOL, BNB, XRP)
        """
        import asyncio
        symbol_list = [s.strip().upper() for s in symbols.split(",")]
        
        tasks = [_fetch(f"/v1/flow/crypto/{sym}") for sym in symbol_list]
        raw_results = await asyncio.gather(*tasks)
        
        results = []
        for sym, data in zip(symbol_list, raw_results):
            if not data.get("error"):
                results.append(data)
            else:
                results.append({"symbol": sym, "signal": "UNAVAILABLE", "error": data.get("detail", "No data")})
    
        results.sort(key=lambda x: x.get("confidence", 0), reverse=True)
    
        summary = {
            "scanned": len(symbol_list),
            "available": len([r for r in results if r.get("signal") != "UNAVAILABLE"]),
            "strongest_buy": next((r["symbol"] for r in results if r.get("signal") == "BUY_PRESSURE"), None),
            "strongest_sell": next((r["symbol"] for r in results if r.get("signal") == "SELL_PRESSURE"), None),
            "results": results,
        }
        return json.dumps(summary, indent=2)
  • The @mcp.tool() decorator registers scan_crypto_flow as an MCP tool on the FastMCP server instance.
    @mcp.tool()
  • The _fetch helper function is used internally by scan_crypto_flow to make HTTP requests to the RapidAPI endpoint.
    async def _fetch(endpoint: str) -> dict:
        """Fetch data from the live RapidAPI endpoint."""
        async with httpx.AsyncClient(timeout=10.0) as client:
            try:
                resp = await client.get(
                    f"{RAPIDAPI_BASE_URL}{endpoint}",
                    headers=HEADERS,
                )
                if resp.status_code == 200:
                    return resp.json()
                elif resp.status_code in [401, 403]:
                    return {
                        "error": True,
                        "signal": "UNAUTHORIZED",
                        "detail": "Invalid or missing RAPIDAPI_KEY. Please verify your RapidAPI subscription."
                    }
                elif resp.status_code == 429:
                    return {
                        "error": True,
                        "signal": "RATE_LIMITED",
                        "detail": "You have exceeded your RapidAPI quota. Please upgrade your plan."
                    }
                return {
                    "error": True,
                    "status_code": resp.status_code,
                    "detail": resp.text,
                }
            except Exception as e:
                return {
                    "error": True,
                    "detail": f"Network Error: {str(e)}"
                }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It mentions that the tool returns a summary and individual results sorted by confidence, indicating a read-like operation. However, it does not disclose potential behavioral traits such as authentication requirements, rate limits, error handling, or what happens if symbols are invalid. Basic transparency is present but incomplete.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: it starts with the main purpose, then describes the return, gives a usage context, and explains the argument. Every sentence serves a purpose with no unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that an output schema exists, the description does not need to explain return values. It adequately covers purpose, parameter, and usage context. The only gap is the minor inconsistency in the parameter default example, which slightly undermines completeness. Overall, it is mostly sufficient for a simple tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no descriptions (0% coverage). The description adds value by explaining the 'symbols' parameter as 'Comma-separated trading pairs' and provides a default list. This goes beyond the schema's mere type and default. However, there is a slight inconsistency: the schema default includes full trading pairs like 'BTCUSDT', while the description lists simple names like 'BTC'. This could cause confusion.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool scans multiple cryptocurrencies for orderflow signals, returns a summary with strongest buy/sell signals, and individual results sorted by confidence. It distinguishes from siblings like get_crypto_flow (likely for single asset) by explicitly mentioning 'multiple' and 'portfolio-wide risk assessment.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a clear use case: 'Use this for portfolio-wide risk assessment.' It implies the tool is for scanning multiple assets but does not explicitly state when not to use it or compare to alternatives. The context is clear but lacks exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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/horustechltd/horus-flow-mcp'

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