#
tokens: 7608/50000 9/9 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .env.example
├── .gitignore
├── deno.json
├── deno.lock
├── Dockerfile
├── main_test.ts
├── main.ts
├── README.md
└── tool
    ├── toolHandler.ts
    └── toolInfo.ts
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
.env
```

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
ACCESS_KEY=xxx
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# DeBanK MCP Server

A stateless Model Context Protocol (MCP) server for interacting with the DeBanK API to retrieve blockchain and DeFi data.

## Overview

This project implements a Model Context Protocol (MCP) server that provides various tools for querying blockchain data, including chains, protocols, tokens, pools, and user assets. Built with the [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/mcp), it leverages the HTTP Streamable transport to provide a modern, efficient API interface.

The server is designed to be completely stateless, with each request being handled independently, making it highly scalable and robust for production environments.

## Features

- **Stateless Architecture**: Each request creates a new server instance and transport
- **Comprehensive DeFi Data Tools**: Access to chains, protocols, tokens, pools, and user data
- **Pagination Support**: All list-returning endpoints support pagination
- **Error Handling**: Robust error handling and reporting

## Tools Available

| Tool Name | Description |
|-----------|-------------|
| `get_chain_info` | Get information about blockchains |
| `get_protocol_info` | Get information about DeFi protocols |
| `get_token_info` | Get information about tokens |
| `get_pool_info` | Get detailed information about a specific liquidity pool |
| `get_user_assets` | Get information about a user's assets across different blockchains |
| `get_user_activities` | Get information about a user's protocol positions, transaction history, and balance charts |
| `get_user_authorizations` | Get information about a user's token and NFT authorizations |
| `get_collection_nft_list` | Get a list of NFTs in a specific collection |
| `wallet_tools` | Access wallet-related functionality |

## Prerequisites

- [Deno](https://deno.land/) 1.35 or later
- DeBanK API Access Key - [Get one here](https://pro.debank.com/)

## Installation

1. Clone the repository
```bash
git clone https://github.com/yourusername/debank-mcp-server.git
cd debank-mcp-server
```

2. Set up your environment variables
```bash
export ACCESS_KEY=your_debank_api_key
```

## Running the Server

Start the server with the following command:

```bash
deno run --allow-net --allow-env main.ts
```

The server will start and listen on port 8080 by default. You can now send MCP requests to `http://localhost:8080/mcp`.

## MCP HTTP Streamable Implementation

This project uses the StreamableHTTPServerTransport from the Model Context Protocol SDK to handle MCP requests. Every request creates a new server instance and transport, making the service completely stateless:

```typescript
// Create new server instance and transport for each request
const server = createServer();
const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => randomUUID(),
});

// Connect to server
await server.connect(transport);

// Handle request
await transport.handleRequest(req, res, req.body);
```

This approach simplifies deployment and scaling, as there's no need to manage session state across multiple instances.

## Project Structure

```
├── main.ts                # Main server file with MCP endpoint handling
├── deno.json              # Deno configuration
├── deno.lock              # Dependency lock file
├── tool/
│   ├── toolInfo.ts        # Tool definitions
│   └── toolHandler.ts     # Tool handler implementations
└── README.md              # This file
```

## Configuration

The following environment variables can be configured:

- `ACCESS_KEY` - Your DeBanK API access key
- `PORT` - (Optional) Port to run the server on (default: 8080)

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

This project is licensed under the MIT License - see the LICENSE file for details.

## Acknowledgments

- [Model Context Protocol](https://github.com/modelcontextprotocol/mcp)
- [DeBanK API](https://pro.debank.com/)

```

--------------------------------------------------------------------------------
/main_test.ts:
--------------------------------------------------------------------------------

```typescript
import { assertEquals } from "@std/assert";
import { add } from "./main.ts";

Deno.test(function addTest() {
  assertEquals(add(2, 3), 5);
});

```

--------------------------------------------------------------------------------
/deno.json:
--------------------------------------------------------------------------------

```json
{
  "tasks": {
    "dev": "deno run --watch main.ts",
    "start": "deno run main.ts"
  },
  "imports": {
    "@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/sdk@^1.10.2",
    "@std/assert": "jsr:@std/assert@1"
  }
}
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
FROM denoland/deno:1.41.3

# Set working directory
WORKDIR /app

# Copy dependency configuration files
COPY deno.json deno.lock ./

# Copy source code
COPY . .

# Cache dependencies
RUN deno cache main.ts

# Expose port (port 8080 is used in main.ts)
EXPOSE 8080

# Configure health check
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
  CMD deno eval "try { await fetch('http://localhost:8080/mcp'); Deno.exit(0); } catch { Deno.exit(1); }"

# Run application
CMD ["deno", "run", "--allow-net", "--allow-env", "--allow-read", "main.ts"]

```

--------------------------------------------------------------------------------
/main.ts:
--------------------------------------------------------------------------------

```typescript
// debank.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import express, { Request, Response, NextFunction } from "npm:express";
import { randomUUID } from "node:crypto";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { ListToolsRequestSchema, CallToolRequestSchema } from "@modelcontextprotocol/sdk";
import toolsList from "./tool/toolInfo.ts";
import { toolToHandler } from "./tool/toolHandler.ts";

// Server configuration
const APP_NAME = "debank";
const APP_VERSION = "1.0.0";
const PORT = 8080;

// Create MCP server
function createServer() {
  const server = new Server(
    {
      name: APP_NAME,
      version: APP_VERSION,
    },
    {
      capabilities: {
        tools: {},
      },
    }
  );

  server.setRequestHandler(ListToolsRequestSchema, () => {
    console.log("Handling listTools request");
    return {
      tools: toolsList,
    };
  });

  server.setRequestHandler(CallToolRequestSchema, async (request) => {
    console.log(`Handling callTool request for tool: ${request.params.name}`);
    try {
      const requestToolName = request.params.name;

      const isMcptool = toolsList.some(
        (tool) => tool.name === requestToolName,
      );

      if (isMcptool) {
        const tool = toolsList.find((tool) => tool.name === requestToolName);
        if (!tool) {
          console.log(`Tool ${requestToolName} not found`);
          return { error: `Tool ${requestToolName} not found` };
        }

        const handler = toolToHandler[requestToolName];

        if (!handler) {
          console.log(`Handler for ${requestToolName} not found`);
          return { error: `Handler for ${requestToolName} not found` };
        }

        console.log(`Calling handler for ${requestToolName}`);
        const result = await handler(request.params.arguments as any);
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(result),
            },
          ],
        };
      }
      console.log(`Tool ${requestToolName} not found in toolsList`);
      return {
        content: [
          {
            type: "text",
            text: "Tool not found",
          },
        ],
      };
    } catch (error) {
      console.error(`Error calling tool: ${error}`);
      return {
        content: [
          {
            type: "text",
            text: `Tool ${request.params.name} failed: ${error}`,
          },
        ],
      };
    }
  });

  return server;
}

// Start server
const startServer = async () => {
  const app = express();
  app.use(express.json());

  // Logging middleware
  app.use((req: Request, res: Response, next: NextFunction) => {
    console.log(`${req.method} ${req.url}`);
    console.log('Headers:', JSON.stringify(req.headers));
    if (req.body) {
      console.log('Body:', JSON.stringify(req.body));
    }
    next();
  });

  // Single endpoint to handle all MCP requests - stateless mode
  app.all('/mcp', async (req: Request, res: Response) => {
    console.log(`Received ${req.method} request to /mcp`);

    try {
      // Create new server instance and transport for each request
      const server = createServer();
      const transport = new StreamableHTTPServerTransport({
        sessionIdGenerator: () => randomUUID(),
      });

      // Connect to server
      await server.connect(transport);

      // Handle request
      await transport.handleRequest(req, res, req.body);
    } catch (error) {
      console.error('Error handling MCP request:', error);
      if (!res.headersSent) {
        res.status(500).json({
          jsonrpc: '2.0',
          error: {
            code: -32603,
            message: 'Internal server error',
          },
          id: null,
        });
      }
    }
  });

  const server = app.listen(PORT, () => {
    console.log(`DeBanK MCP Server listening on port ${PORT}`);
  });

  // Handle server shutdown
  process.on('SIGINT', () => {
    console.log('Shutting down server...');
    server.close(() => {
      console.log('Server shutdown complete');
      process.exit(0);
    });
  });
};

// Start server
startServer();
```

--------------------------------------------------------------------------------
/tool/toolInfo.ts:
--------------------------------------------------------------------------------

```typescript
export const getChainInfo = {
    name: "get_chain_info",
    description: "Get information about blockchains via GET requests to /v1/chain or /v1/chain/list. " +
        "Can retrieve details about a specific chain or list all supported chains.",
    inputSchema: {
        type: "object",
        properties: {
            id: { type: "string", description: "Optional chain identifier (e.g. eth, bsc, xdai)" },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: []
    }
}

export const getProtocolInfo = {
    name: "get_protocol_info",
    description: "Get information about DeFi protocols via GET requests to various protocol endpoints. " +
        "Can retrieve details about a specific protocol, list protocols on a chain, or fetch top holders.",
    inputSchema: {
        type: "object",
        properties: {
            id: { type: "string", description: "Protocol identifier (e.g. curve, uniswap)" },
            chain_id: { type: "string", description: "Chain identifier (e.g. eth, bsc)" },
            get_top_holders: { type: "boolean", description: "Set to True to fetch the top holders of a protocol", default: false },
            start: { type: "number", description: "Integer offset for pagination" },
            limit: { type: "number", description: "Number of results to return", default: 10 },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: []
    }
}

export const getTokenInfo = {
    name: "get_token_info",
    description: "Get information about tokens via GET requests to various token endpoints. " +
        "Can retrieve token details, top holders, or historical prices.",
    inputSchema: {
        type: "object",
        properties: {
            chain_id: { type: "string", description: "Chain identifier (e.g. eth, bsc, xdai)" },
            id: { type: "string", description: "Token identifier - either a contract address or a native token id" },
            action: { type: "string", description: "Type of information to retrieve", default: "details" },
            date_at: { type: "string", description: "UTC timezone date in YYYY-MM-DD format" },
            start: { type: "number", description: "Integer offset for pagination", default: 0 },
            limit: { type: "number", description: "Number of holders to return", default: 100 },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: ["chain_id", "id"]
    }
}

export const getPoolInfo = {
    name: "get_pool_info",
    description: "Get detailed information about a specific liquidity pool via a GET request to /v1/pool. " +
        "Returns detailed statistics about the pool including its deposits, user counts, and associated protocol.",
    inputSchema: {
        type: "object",
        properties: {
            id: { type: "string", description: "Pool identifier" },
            chain_id: { type: "string", description: "Chain identifier (e.g. eth, bsc, xdai)" }
        },
        required: ["id", "chain_id"]
    }
}

export const getUserAssets = {
    name: "get_user_assets",
    description: "Get information about a user's assets across different blockchains. " +
        "Can retrieve basic balance, token lists, NFTs, and more with optional chain filtering.",
    inputSchema: {
        type: "object",
        properties: {
            id: { type: "string", description: "User wallet address" },
            asset_type: { type: "string", description: "Type of asset information to retrieve", default: "balance" },
            chain_id: { type: "string", description: "Chain identifier for single-chain queries" },
            token_id: { type: "string", description: "Token identifier for specific token balance query" },
            chain_ids: { type: "string", description: "Optional comma-separated list of chain IDs" },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: ["id"]
    }
}

export const getUserActivities = {
    name: "get_user_activities",
    description: "Get information about a user's protocol positions, transaction history, and balance charts. " +
        "Supports filtering by chain and protocol.",
    inputSchema: {
        type: "object",
        properties: {
            id: { type: "string", description: "User wallet address" },
            activity_type: { type: "string", description: "Type of activity information to retrieve" },
            chain_id: { type: "string", description: "Chain identifier for single-chain queries" },
            protocol_id: { type: "string", description: "Protocol identifier for specific protocol query" },
            chain_ids: { type: "string", description: "Optional comma-separated list of chain IDs" },
            page_count: { type: "number", description: "Optional number of pages to return for history queries" },
            start_time: { type: "number", description: "Optional Unix timestamp to start from for history queries" },
            is_simple: { type: "boolean", description: "Whether to use simple or complex protocol list", default: true },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: ["id", "activity_type"]
    }
}

export const getUserAuthorizations = {
    name: "get_user_authorizations",
    description: "Get information about a user's token and NFT authorizations on a specific blockchain.",
    inputSchema: {
        type: "object",
        properties: {
            id: { type: "string", description: "User wallet address" },
            chain_id: { type: "string", description: "Chain identifier (e.g. eth, bsc, xdai)" },
            auth_type: { type: "string", description: "Type of authorization to retrieve", default: "token" },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: ["id", "chain_id"]
    }
}

export const getCollectionNftList = {
    name: "get_collection_nft_list",
    description: "Get a list of NFTs in a specific collection using a GET request to /v1/collection/nft_list. " +
        "Returns an array of NFT objects with details like name, description, content, and attributes.",
    inputSchema: {
        type: "object",
        properties: {
            id: { type: "string", description: "NFT contract address" },
            chain_id: { type: "string", description: "Chain identifier (e.g. eth, bsc, xdai)" },
            start: { type: "number", description: "Integer offset for pagination", default: 0 },
            limit: { type: "number", description: "Number of NFTs to return", default: 20 },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: ["id", "chain_id"]
    }
}

export const walletTools = {
    name: "wallet_tools",
    description: "Access wallet-related functionality: get gas prices, analyze transactions, or simulate transactions.",
    inputSchema: {
        type: "object",
        properties: {
            action: { type: "string", description: "Type of wallet action to perform" },
            chain_id: { type: "string", description: "Chain identifier (e.g. eth, bsc, xdai)" },
            tx: { type: "object", description: "Transaction object" },
            pending_tx_list: { type: "array", description: "Optional list of transactions to execute before the main transaction" },
            page: { type: "number", description: "Page number, starting from 1", default: 1 },
            page_size: { type: "number", description: "Number of records per page", default: 5 }
        },
        required: ["action"]
    }
}

export default [
    getChainInfo,
    getProtocolInfo,
    getTokenInfo,
    getPoolInfo,
    getUserAssets,
    getUserActivities,
    getUserAuthorizations,
    getCollectionNftList,
    walletTools
]


```

--------------------------------------------------------------------------------
/tool/toolHandler.ts:
--------------------------------------------------------------------------------

```typescript
import { getChainInfo, getCollectionNftList, getPoolInfo, getProtocolInfo, getTokenInfo, getUserActivities, getUserAssets, getUserAuthorizations, walletTools } from "./toolInfo.ts";

// DeBanK API configuration
const ACCESS_KEY = Deno.env.get("ACCESS_KEY");
const BASE_URL = "https://pro-openapi.debank.com";

// Pagination function types
interface PaginationInfo {
    page: number;
    page_size: number;
    total_items: number;
    total_pages: number;
}

interface PaginatedResult<T> {
    data: T[];
    pagination: PaginationInfo;
}

// Pagination function
function paginateResults<T>(results: T[] | null | undefined, page = 1, page_size = 5): PaginatedResult<T> | null | undefined {
    if (results === null || results === undefined || !Array.isArray(results)) {
        return results as any;
    }

    const start_idx = (page - 1) * page_size;
    const end_idx = start_idx + page_size;
    const total_items = results.length;
    const total_pages = Math.ceil(total_items / page_size);

    const paginated_results = results.slice(start_idx, end_idx);

    const pagination_info: PaginationInfo = {
        page,
        page_size,
        total_items,
        total_pages
    };

    return {
        data: paginated_results,
        pagination: pagination_info
    };
}

// Network request function
async function makeNwsRequest(url: string): Promise<any> {
    const headers = {
        "Accept": "application/json",
        "AccessKey": ACCESS_KEY || ""
    };

    try {
        const response = await fetch(url, {
            method: "GET",
            headers
        });

        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }

        return await response.json();
    } catch (error) {
        console.error("Request error:", error);
        return null;
    }
}

// POST request function
async function makePostRequest(url: string, data: any): Promise<any> {
    const headers = {
        "Accept": "application/json",
        "Content-Type": "application/json",
        "AccessKey": ACCESS_KEY || ""
    };

    try {
        const response = await fetch(url, {
            method: "POST",
            headers,
            body: JSON.stringify(data)
        });

        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }

        return await response.json();
    } catch (error) {
        console.error("POST request error:", error);
        return null;
    }
}


export const getChainInfoHandler = async ({ id, page = 1, page_size = 5 }: { id?: string, page?: number, page_size?: number }) => {
    if (id) {
        return await makeNwsRequest(`${BASE_URL}/v1/chain?id=${id}`);
    } else {
        const results = await makeNwsRequest(`${BASE_URL}/v1/chain/list`);
        return paginateResults(results, page, page_size);
    }
}

export const getProtocolInfoHandler = async ({ id, chain_id, get_top_holders = false, start, limit = 10, page = 1, page_size = 5 }: { id?: string, chain_id?: string, get_top_holders?: boolean, start?: number, limit?: number, page?: number, page_size?: number }) => {
    if (id && get_top_holders) {
        // Get top holders of a protocol
        let url = `${BASE_URL}/v1/protocol/top_holders?id=${id}`;
        if (start !== undefined) {
            url += `&start=${start}`;
        }
        if (limit !== undefined) {
            url += `&limit=${limit}`;
        }
        const results = await makeNwsRequest(url);
        return paginateResults(results, page, page_size);
    } else if (id) {
        // Get specific protocol info
        return await makeNwsRequest(`${BASE_URL}/v1/protocol?id=${id}`);
    } else if (chain_id) {
        // Get protocols on a chain
        const protocols = await makeNwsRequest(`${BASE_URL}/v1/protocol/list?chain_id=${chain_id}`);
        if (protocols) {
            // Sort protocols by TVL in descending order
            const sorted_protocols = [...protocols].sort((a, b) =>
                (b.tvl || 0) - (a.tvl || 0)
            );
            return paginateResults(sorted_protocols, page, page_size);
        }
        return null;
    } else {
        return { error: "Either id or chain_id must be provided" };
    }
}

export const getTokenInfoHandler = async ({ chain_id, id, action = "details", date_at, start = 0, limit = 100, page = 1, page_size = 5 }: { chain_id: string, id: string, action?: string, date_at?: string, start?: number, limit?: number, page?: number, page_size?: number }) => {
    if (action === "details") {
        return await makeNwsRequest(`${BASE_URL}/v1/token?chain_id=${chain_id}&id=${id}`);
    } else if (action === "holders") {
        const url = `${BASE_URL}/v1/token/top_holders?chain_id=${chain_id}&id=${id}&start=${start}&limit=${limit}`;
        const results = await makeNwsRequest(url);
        return paginateResults(results, page, page_size);
    } else if (action === "history") {
        if (!date_at) {
            return { error: "date_at parameter is required for historical price" };
        }
        return await makeNwsRequest(`${BASE_URL}/v1/token/history_price?chain_id=${chain_id}&id=${id}&date_at=${date_at}`);
    } else {
        return { error: "Invalid action parameter. Use 'details', 'holders', or 'history'." };
    }
}

export const getPoolInfoHandler = async ({ id, chain_id }: { id: string, chain_id: string }) => {
    return await makeNwsRequest(`${BASE_URL}/v1/pool?id=${id}&chain_id=${chain_id}`);
}

export const getUserAssetsHandler = async ({ id, asset_type = "balance", chain_id, token_id, chain_ids, page = 1, page_size = 5 }: { id: string, asset_type?: string, chain_id?: string, token_id?: string, chain_ids?: string, page?: number, page_size?: number }) => {
    if (asset_type === "balance") {
        if (chain_id) {
            return await makeNwsRequest(`${BASE_URL}/v1/user/chain_balance?id=${id}&chain_id=${chain_id}`);
        } else {
            let url = `${BASE_URL}/v1/user/total_balance?id=${id}`;
            if (chain_ids) {
                url += `&chain_ids=${chain_ids}`;
            }
            return await makeNwsRequest(url);
        }
    } else if (asset_type === "chains") {
        const results = await makeNwsRequest(`${BASE_URL}/v1/user/used_chain_list?id=${id}`);
        return paginateResults(results, page, page_size);
    } else if (asset_type === "tokens") {
        let results;
        if (chain_id) {
            results = await makeNwsRequest(`${BASE_URL}/v1/user/token_list?id=${id}&chain_id=${chain_id}`);
        } else {
            let url = `${BASE_URL}/v1/user/all_token_list?id=${id}`;
            if (chain_ids) {
                url += `&chain_ids=${chain_ids}`;
            }
            results = await makeNwsRequest(url);
        }
        return paginateResults(results, page, page_size);
    } else if (asset_type === "token") {
        if (!chain_id || !token_id) {
            return { error: "chain_id and token_id are required for token balance query" };
        }
        return await makeNwsRequest(`${BASE_URL}/v1/user/token_balance?id=${id}&chain_id=${chain_id}&token_id=${token_id}`);
    } else if (asset_type === "nfts") {
        let results;
        if (chain_id) {
            results = await makeNwsRequest(`${BASE_URL}/v1/user/nft_list?id=${id}&chain_id=${chain_id}`);
        } else {
            let url = `${BASE_URL}/v1/user/all_nft_list?id=${id}`;
            if (chain_ids) {
                url += `&chain_ids=${chain_ids}`;
            }
            results = await makeNwsRequest(url);
        }
        return paginateResults(results, page, page_size);
    } else {
        return { error: "Invalid asset_type parameter" };
    }
}

export const getUserActivitiesHandler = async ({ id, activity_type, chain_id, protocol_id, chain_ids, page_count, start_time, is_simple = true, page = 1, page_size = 5 }: { id: string, activity_type: string, chain_id?: string, protocol_id?: string, chain_ids?: string, page_count?: number, start_time?: number, is_simple?: boolean, page?: number, page_size?: number }) => {
    if (activity_type === "protocols") {
        if (protocol_id) {
            // Get specific protocol info
            return await makeNwsRequest(`${BASE_URL}/v1/user/protocol?id=${id}&protocol_id=${protocol_id}`);
        } else if (chain_id) {
            // Get protocol list for a specific chain
            let results;
            if (is_simple) {
                results = await makeNwsRequest(`${BASE_URL}/v1/user/simple_protocol_list?id=${id}&chain_id=${chain_id}`);
            } else {
                results = await makeNwsRequest(`${BASE_URL}/v1/user/complex_protocol_list?id=${id}&chain_id=${chain_id}`);
            }
            return paginateResults(results, page, page_size);
        } else {
            // Get protocol list for all chains
            const url_base = `${BASE_URL}/v1/user/all_${is_simple ? "simple" : "complex"}_protocol_list`;
            let url = `${url_base}?id=${id}`;
            if (chain_ids) {
                url += `&chain_ids=${chain_ids}`;
            }
            const results = await makeNwsRequest(url);
            return paginateResults(results, page, page_size);
        }
    } else if (activity_type === "history") {
        let url;
        if (chain_id) {
            // Get history for a specific chain
            url = `${BASE_URL}/v1/user/history_list?id=${id}&chain_id=${chain_id}`;
        } else {
            // Get history for all chains
            url = `${BASE_URL}/v1/user/history?id=${id}`;
            if (chain_ids) {
                url += `&chain_ids=${chain_ids}`;
            }
        }

        if (page_count !== undefined) {
            url += `&page_count=${page_count}`;
        }
        if (start_time !== undefined) {
            url += `&start_time=${start_time}`;
        }

        const results = await makeNwsRequest(url);
        return paginateResults(results, page, page_size);
    } else if (activity_type === "chart") {
        let results;
        if (chain_id) {
            // Get chart for a specific chain
            results = await makeNwsRequest(`${BASE_URL}/v1/user/chain_net_curve?id=${id}&chain_id=${chain_id}`);
        } else {
            // Get chart for all chains
            let url = `${BASE_URL}/v1/user/total_net_curve?id=${id}`;
            if (chain_ids) {
                url += `&chain_ids=${chain_ids}`;
            }
            results = await makeNwsRequest(url);
        }
        return paginateResults(results, page, page_size);
    } else {
        return { error: "Invalid activity_type parameter" };
    }
}

export const getUserAuthorizationsHandler = async ({ id, chain_id, auth_type = "token", page = 1, page_size = 5 }: { id: string, chain_id: string, auth_type?: string, page?: number, page_size?: number }) => {
    if (auth_type === "token") {
        const results = await makeNwsRequest(`${BASE_URL}/v1/user/token_auth_list?id=${id}&chain_id=${chain_id}`);
        return paginateResults(results, page, page_size);
    } else if (auth_type === "nft") {
        const results = await makeNwsRequest(`${BASE_URL}/v1/user/nft_auth_list?id=${id}&chain_id=${chain_id}`);
        return paginateResults(results, page, page_size);
    } else {
        return { error: "Invalid auth_type parameter. Use 'token' or 'nft'." };
    }
}

export const getCollectionNftListHandler = async ({ id, chain_id, start = 0, limit = 20, page = 1, page_size = 5 }: { id: string, chain_id: string, start?: number, limit?: number, page?: number, page_size?: number }) => {
    const url = `${BASE_URL}/v1/collection/nft_list?id=${id}&chain_id=${chain_id}&start=${start}&limit=${limit}`;
    const results = await makeNwsRequest(url);
    return paginateResults(results, page, page_size);
}

export const walletToolsHandler = async ({ action, chain_id, tx, pending_tx_list, page = 1, page_size = 5 }: { action: string, chain_id?: string, tx?: any, pending_tx_list?: any[], page?: number, page_size?: number }) => {
    if (action === "gas") {
        if (!chain_id) {
            return { error: "chain_id parameter is required for gas price query" };
        }
        const results = await makeNwsRequest(`${BASE_URL}/v1/wallet/gas_market?chain_id=${chain_id}`);
        return paginateResults(results, page, page_size);
    } else if (action === "explain_tx") {
        if (!tx) {
            return { error: "tx parameter is required for transaction explanation" };
        }
        const data = { tx };
        return await makePostRequest(`${BASE_URL}/v1/wallet/explain_tx`, data);
    } else if (action === "simulate_tx") {
        if (!tx) {
            return { error: "tx parameter is required for transaction simulation" };
        }
        const data: any = { tx };
        if (pending_tx_list) {
            data.pending_tx_list = pending_tx_list;
        }
        return await makePostRequest(`${BASE_URL}/v1/wallet/pre_exec_tx`, data);
    } else {
        return { error: "Invalid action parameter. Use 'gas', 'explain_tx', or 'simulate_tx'." };
    }
}



export const toolToHandler = {
    [getChainInfo.name]: getChainInfoHandler,
    [getProtocolInfo.name]: getProtocolInfoHandler,
    [getTokenInfo.name]: getTokenInfoHandler,
    [getPoolInfo.name]: getPoolInfoHandler,
    [getUserAssets.name]: getUserAssetsHandler,
    [getUserActivities.name]: getUserActivitiesHandler,
    [getUserAuthorizations.name]: getUserAuthorizationsHandler,
    [getCollectionNftList.name]: getCollectionNftListHandler,
    [walletTools.name]: walletToolsHandler
}
```