Skip to main content
Glama
sammcj

Bybit MCP Server

by sammcj

get_trades

Retrieve recent trades for a specified trading pair and category (spot, linear, inverse) with a customizable limit up to 1000, using the Bybit MCP Server for real-time cryptocurrency data access.

Instructions

Get recent trades for a trading pair

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
categoryNoCategory of the instrument (spot, linear, inverse)
limitNoLimit for the number of trades (max 1000)
symbolYesTrading pair symbol (e.g., 'BTCUSDT')

Implementation Reference

  • Executes the get_trades tool: validates symbol (required), optional category (spot/linear/inverse) and limit, fetches recent public trades from Bybit API using getPublicTradingHistory, formats response with id, symbol, price, size, side, time, isBlockTrade, handles errors via BaseTool.
    async toolCall(request: z.infer<typeof CallToolRequestSchema>) {
      try {
        const args = request.params.arguments as unknown
        if (!args || typeof args !== 'object') {
          throw new Error("Invalid arguments")
        }
    
        const typedArgs = args as Record<string, unknown>
    
        if (!typedArgs.symbol || typeof typedArgs.symbol !== 'string') {
          throw new Error("Missing or invalid symbol parameter")
        }
    
        const symbol = typedArgs.symbol
        const category = (
          typedArgs.category &&
          typeof typedArgs.category === 'string' &&
          ["spot", "linear", "inverse"].includes(typedArgs.category)
        ) ? typedArgs.category as SupportedCategory
          : CONSTANTS.DEFAULT_CATEGORY as SupportedCategory
    
        const limit = (
          typedArgs.limit &&
          typeof typedArgs.limit === 'string' &&
          ["1", "10", "50", "100", "200", "500", "1000"].includes(typedArgs.limit)
        ) ? parseInt(typedArgs.limit, 10) : 200
    
        const params: GetPublicTradingHistoryParamsV5 = {
          category,
          symbol,
          limit,
        }
    
        const response = await this.client.getPublicTradingHistory(params)
    
        if (response.retCode !== 0) {
          throw new Error(`Bybit API error: ${response.retMsg}`)
        }
    
        // Transform the trade data into a more readable format and return as array
        const formattedTrades = response.result.list.map(trade => ({
          id: trade.execId,
          symbol: trade.symbol,
          price: trade.price,
          size: trade.size,
          side: trade.side,
          time: trade.time,
          isBlockTrade: trade.isBlockTrade,
        }))
    
        return this.formatResponse(formattedTrades)
      } catch (error) {
        return this.handleError(error)
      }
    }
  • Tool definition including name, description, and input schema validation for parameters: symbol (required string), category (enum string), limit (enum string).
    toolDefinition: Tool = {
      name: this.name,
      description: "Get recent trades for a trading pair",
      inputSchema: {
        type: "object",
        properties: {
          symbol: {
            type: "string",
            description: "Trading pair symbol (e.g., 'BTCUSDT')",
          },
          category: {
            type: "string",
            description: "Category of the instrument (spot, linear, inverse)",
            enum: ["spot", "linear", "inverse"],
          },
          limit: {
            type: "string",
            description: "Limit for the number of trades (max 1000)",
            enum: ["1", "10", "50", "100", "200", "500", "1000"],
          },
        },
        required: ["symbol"],
      },
    };
  • Dynamically discovers, imports, instantiates (new ToolClass()), validates, and collects all BaseToolImplementation subclasses from src/tools/*.ts including GetTrades, returning array of tool instances.
    export async function loadTools(): Promise<BaseToolImplementation[]> {
      try {
        const toolsPath = await findToolsPath()
        const files = await fs.readdir(toolsPath)
        const tools: BaseToolImplementation[] = []
    
        for (const file of files) {
          if (!isToolFile(file)) {
            continue
          }
    
          try {
            const modulePath = `file://${join(toolsPath, file)}`
            const { default: ToolClass } = await import(modulePath)
    
            if (!ToolClass || typeof ToolClass !== 'function') {
              console.warn(JSON.stringify({
                type: "warning",
                message: `Invalid tool class in ${file}`
              }))
              continue
            }
    
            const tool = new ToolClass()
    
            if (
              tool instanceof BaseToolImplementation &&
              tool.name &&
              tool.toolDefinition &&
              typeof tool.toolCall === "function"
            ) {
              tools.push(tool)
              console.info(JSON.stringify({
                type: "info",
                message: `Loaded tool: ${tool.name}`
              }))
            } else {
              console.warn(JSON.stringify({
                type: "warning",
                message: `Invalid tool implementation in ${file}`
              }))
            }
          } catch (error) {
            console.error(JSON.stringify({
              type: "error",
              message: `Error loading tool from ${file}: ${error instanceof Error ? error.message : String(error)}`
            }))
          }
        }
    
        return tools
      } catch (error) {
        console.error(JSON.stringify({
          type: "error",
          message: `Failed to load tools: ${error instanceof Error ? error.message : String(error)}`
        }))
        return []
      }
    }
  • src/index.ts:82-115 (registration)
    Registers the generic MCP CallTool handler: looks up tool by name from toolsMap (populated with get_trades), validates arguments, calls tool.toolCall(request).
    server.setRequestHandler(CallToolRequestSchema, async (request) => {
      try {
        if (!toolsMap) {
          throw new Error("Tools not initialized")
        }
    
        const tool = toolsMap.get(request.params.name)
        if (!tool) {
          throw {
            code: METHOD_NOT_FOUND,
            message: `Unknown tool: ${request.params.name}. Available tools: ${Array.from(
              toolsMap.keys()
            ).join(", ")}`
          }
        }
    
        if (!request.params.arguments || typeof request.params.arguments !== 'object') {
          throw {
            code: INVALID_PARAMS,
            message: "Invalid or missing arguments"
          }
        }
    
        return tool.toolCall(request)
      } catch (error: any) {
        if (error.code) {
          throw error
        }
        throw {
          code: INTERNAL_ERROR,
          message: error instanceof Error ? error.message : String(error)
        }
      }
    })
  • src/index.ts:73-80 (registration)
    Registers MCP ListTools handler: returns array of tool definitions (including get_trades schema) from loaded toolsMap.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      if (!toolsMap || toolsMap.size === 0) {
        return { tools: [] }
      }
      return {
        tools: Array.from(toolsMap.values()).map((tool) => tool.toolDefinition),
      }
    })
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It mentions 'recent trades' but doesn't disclose behavioral traits such as time recency (e.g., last hour, day), data format, pagination, rate limits, or authentication needs. For a tool with no annotations, this leaves significant gaps in understanding how it behaves.

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 a single, efficient sentence with zero waste. It's front-loaded and appropriately sized for a simple retrieval tool, making it easy to parse quickly.

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

Completeness2/5

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

Given no annotations, no output schema, and 3 parameters, the description is incomplete. It lacks details on return values (e.g., trade data format), error handling, or behavioral constraints like rate limits. For a tool in a trading context with siblings, more context is needed to ensure proper usage.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents all parameters (symbol, category, limit) with descriptions and enums. The description adds no additional meaning beyond implying 'recent' for time context, but doesn't specify how recency is defined or interact with parameters. Baseline 3 is appropriate as the schema does the heavy lifting.

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

Purpose4/5

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

The description clearly states the verb 'Get' and the resource 'recent trades for a trading pair', making the purpose understandable. However, it doesn't differentiate from sibling tools like get_order_history or get_ticker, which might also retrieve trade-related data, so it misses full sibling distinction.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. With siblings like get_order_history (which might retrieve user-specific trades) or get_ticker (which provides price data), there's no indication of context, exclusions, or prerequisites for selecting this tool.

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

Related 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/sammcj/bybit-mcp'

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