Skip to main content
Glama
by frahman5
bitso-tools.ts15.5 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import { BitsoApiClient } from "../client.js"; import { ToolResult } from "../types.js"; import { createLogger } from "../utils/logging.js"; const logToFile = createLogger(import.meta.url, 'BITSO_TOOLS'); const ListWithdrawalsSchema = z.object({ currency: z.string().optional(), limit: z.number().int().positive().max(100).optional(), marker: z.string().optional(), method: z.string().optional(), origin_id: z.string().optional(), status: z.string().optional(), wid: z.string().optional(), }); const GetWithdrawalSchema = z.object({ wid: z.string().min(1, "Withdrawal ID is required"), }); const GetWithdrawalsByIdsSchema = z.object({ wids: z.string().min(1, "Comma-separated withdrawal IDs are required"), }); const GetWithdrawalsByOriginIdsSchema = z.object({ origin_ids: z.string().min(1, "Comma-separated origin IDs are required"), }); const ListFundingsSchema = z.object({ limit: z.number().int().positive().max(100).optional(), marker: z.string().optional(), method: z.string().optional(), status: z.string().optional(), fids: z.string().optional(), }); const GetFundingSchema = z.object({ fid: z.string().min(1, "Funding ID is required"), }); export function registerBitsoTools(server: McpServer, client: BitsoApiClient): void { // Tool 1: List withdrawals server.tool( "list_withdrawals", { description: "List withdrawals with optional filtering parameters", inputSchema: { type: "object", properties: { currency: { type: "string", description: "Filter by transaction currency" }, limit: { type: "number", description: "Number of objects to return (max 100, default 25)", minimum: 1, maximum: 100 }, marker: { type: "string", description: "Pagination marker" }, method: { type: "string", description: "Filter by withdrawal method" }, origin_id: { type: "string", description: "Filter by client-supplied ID" }, status: { type: "string", description: "Filter by withdrawal status" }, wid: { type: "string", description: "Filter by specific withdrawal ID" } } } }, async (params): Promise<ToolResult> => { try { const validatedParams = ListWithdrawalsSchema.parse(params); logToFile('INFO', 'List withdrawals tool called', validatedParams); const response = await client.getWithdrawals(validatedParams); if (!response.success || !response.payload || response.payload.length === 0) { return { content: [ { type: "text", text: "No withdrawals found with the specified criteria." } ] }; } const withdrawalList = response.payload.map(withdrawal => `• ${withdrawal.wid} - ${withdrawal.currency} ${withdrawal.amount} Status: ${withdrawal.status} Method: ${withdrawal.method} Created: ${withdrawal.created_at} ${withdrawal.origin_id ? `Origin ID: ${withdrawal.origin_id}` : ''}` ).join('\n\n'); return { content: [ { type: "text", text: `Found ${response.payload.length} withdrawal(s): ${withdrawalList}` } ] }; } catch (error) { logToFile('ERROR', 'Error in list_withdrawals tool', error); if (error instanceof z.ZodError) { const errorMessage = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join(', '); return { content: [ { type: "text", text: `Validation error: ${errorMessage}` } ] }; } return { content: [ { type: "text", text: `Error listing withdrawals: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Tool 2: Get specific withdrawal server.tool( "get_withdrawal", { description: "Get details of a specific withdrawal by ID", inputSchema: { type: "object", properties: { wid: { type: "string", description: "The withdrawal ID to retrieve" } }, required: ["wid"] } }, async (params): Promise<ToolResult> => { try { const validatedParams = GetWithdrawalSchema.parse(params); logToFile('INFO', 'Get withdrawal tool called', { wid: validatedParams.wid }); const withdrawal = await client.getWithdrawal(validatedParams.wid); return { content: [ { type: "text", text: `Withdrawal Details: ID: ${withdrawal.wid} Status: ${withdrawal.status} Currency: ${withdrawal.currency} Amount: ${withdrawal.amount} Method: ${withdrawal.method} Created: ${withdrawal.created_at} ${withdrawal.origin_id ? `Origin ID: ${withdrawal.origin_id}` : ''} ${withdrawal.asset ? `Asset: ${withdrawal.asset}` : ''} ${withdrawal.network ? `Network: ${withdrawal.network}` : ''} ${withdrawal.protocol ? `Protocol: ${withdrawal.protocol}` : ''} Details: ${JSON.stringify(withdrawal.details, null, 2)}` } ] }; } catch (error) { logToFile('ERROR', 'Error in get_withdrawal tool', error); if (error instanceof z.ZodError) { const errorMessage = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join(', '); return { content: [ { type: "text", text: `Validation error: ${errorMessage}` } ] }; } return { content: [ { type: "text", text: `Error retrieving withdrawal: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Tool 3: Get withdrawals by multiple IDs server.tool( "get_withdrawals_by_ids", { description: "Get multiple withdrawals by comma-separated withdrawal IDs", inputSchema: { type: "object", properties: { wids: { type: "string", description: "Comma-separated withdrawal IDs (e.g., 'wid1,wid2,wid3')" } }, required: ["wids"] } }, async (params): Promise<ToolResult> => { try { const validatedParams = GetWithdrawalsByIdsSchema.parse(params); logToFile('INFO', 'Get withdrawals by IDs tool called', { wids: validatedParams.wids }); const response = await client.getWithdrawals({ wid: validatedParams.wids }); if (!response.success || !response.payload || response.payload.length === 0) { return { content: [ { type: "text", text: "No withdrawals found with the specified IDs." } ] }; } const withdrawalList = response.payload.map(withdrawal => `• ${withdrawal.wid} - ${withdrawal.currency} ${withdrawal.amount} Status: ${withdrawal.status} Method: ${withdrawal.method} Created: ${withdrawal.created_at}` ).join('\n\n'); return { content: [ { type: "text", text: `Found ${response.payload.length} withdrawal(s): ${withdrawalList}` } ] }; } catch (error) { logToFile('ERROR', 'Error in get_withdrawals_by_ids tool', error); if (error instanceof z.ZodError) { const errorMessage = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join(', '); return { content: [ { type: "text", text: `Validation error: ${errorMessage}` } ] }; } return { content: [ { type: "text", text: `Error retrieving withdrawals: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Tool 4: Get withdrawals by origin IDs server.tool( "get_withdrawals_by_origin_ids", { description: "Get withdrawals by comma-separated origin IDs (client-supplied IDs)", inputSchema: { type: "object", properties: { origin_ids: { type: "string", description: "Comma-separated origin IDs (e.g., 'origin1,origin2,origin3')" } }, required: ["origin_ids"] } }, async (params): Promise<ToolResult> => { try { const validatedParams = GetWithdrawalsByOriginIdsSchema.parse(params); logToFile('INFO', 'Get withdrawals by origin IDs tool called', { origin_ids: validatedParams.origin_ids }); const response = await client.getWithdrawals({ origin_id: validatedParams.origin_ids }); if (!response.success || !response.payload || response.payload.length === 0) { return { content: [ { type: "text", text: "No withdrawals found with the specified origin IDs." } ] }; } const withdrawalList = response.payload.map(withdrawal => `• ${withdrawal.wid} - ${withdrawal.currency} ${withdrawal.amount} Status: ${withdrawal.status} Method: ${withdrawal.method} Origin ID: ${withdrawal.origin_id} Created: ${withdrawal.created_at}` ).join('\n\n'); return { content: [ { type: "text", text: `Found ${response.payload.length} withdrawal(s): ${withdrawalList}` } ] }; } catch (error) { logToFile('ERROR', 'Error in get_withdrawals_by_origin_ids tool', error); if (error instanceof z.ZodError) { const errorMessage = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join(', '); return { content: [ { type: "text", text: `Validation error: ${errorMessage}` } ] }; } return { content: [ { type: "text", text: `Error retrieving withdrawals: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Tool 5: List fundings server.tool( "list_fundings", { description: "List fundings with optional filtering parameters", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of objects to return (max 100, default 25)", minimum: 1, maximum: 100 }, marker: { type: "string", description: "Pagination marker" }, method: { type: "string", description: "Filter by funding method" }, status: { type: "string", description: "Filter by funding status" }, fids: { type: "string", description: "Comma-separated funding IDs to filter by" } } } }, async (params): Promise<ToolResult> => { try { const validatedParams = ListFundingsSchema.parse(params); logToFile('INFO', 'List fundings tool called', validatedParams); const response = await client.getFundings(validatedParams); if (!response.success || !response.payload || response.payload.length === 0) { return { content: [ { type: "text", text: "No fundings found with the specified criteria." } ] }; } const fundingList = response.payload.map(funding => `• ${funding.fid} - ${funding.currency} ${funding.amount} Status: ${funding.status} Method: ${funding.method} Created: ${funding.created_at}` ).join('\n\n'); return { content: [ { type: "text", text: `Found ${response.payload.length} funding(s): ${fundingList}` } ] }; } catch (error) { logToFile('ERROR', 'Error in list_fundings tool', error); if (error instanceof z.ZodError) { const errorMessage = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join(', '); return { content: [ { type: "text", text: `Validation error: ${errorMessage}` } ] }; } return { content: [ { type: "text", text: `Error listing fundings: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); // Tool 6: Get specific funding server.tool( "get_funding", { description: "Get details of a specific funding by ID", inputSchema: { type: "object", properties: { fid: { type: "string", description: "The funding ID to retrieve" } }, required: ["fid"] } }, async (params): Promise<ToolResult> => { try { const validatedParams = GetFundingSchema.parse(params); logToFile('INFO', 'Get funding tool called', { fid: validatedParams.fid }); const funding = await client.getFunding(validatedParams.fid); return { content: [ { type: "text", text: `Funding Details: ID: ${funding.fid} Status: ${funding.status} Currency: ${funding.currency} Amount: ${funding.amount} Method: ${funding.method} Created: ${funding.created_at} Details: ${JSON.stringify(funding.details, null, 2)}` } ] }; } catch (error) { logToFile('ERROR', 'Error in get_funding tool', error); if (error instanceof z.ZodError) { const errorMessage = error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join(', '); return { content: [ { type: "text", text: `Validation error: ${errorMessage}` } ] }; } return { content: [ { type: "text", text: `Error retrieving funding: ${error instanceof Error ? error.message : String(error)}` } ] }; } } ); logToFile('INFO', 'All Bitso tools registered successfully'); }

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/frahman5/bitso-mcp'

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