@@ -7,7 +7,7 @@ import { logger } from "../logger/winston";
77export const CMC_BASE_URL = "https://pro-api.coinmarketcap.com/v1" ;
88
99const CMCPlatformSchema = z . object ( {
10- id : z . number ( ) . describe ( "Platform ID" ) ,
10+ id : z . union ( [ z . number ( ) , z . string ( ) ] ) . describe ( "Platform ID" ) ,
1111 name : z . string ( ) . describe ( "Platform name" ) ,
1212 symbol : z . string ( ) . describe ( "Platform symbol" ) ,
1313 slug : z . string ( ) . describe ( "Platform slug" ) ,
@@ -47,6 +47,51 @@ const CMCResponseSchema = z.object({
4747 } ) ,
4848} ) ;
4949
50+ const CMCMetadataV2Schema = z . object ( {
51+ data : z . record (
52+ z . object ( {
53+ id : z . number ( ) . describe ( "CoinMarketCap ID" ) ,
54+ name : z . string ( ) . describe ( "Token name" ) ,
55+ symbol : z . string ( ) . describe ( "Token symbol" ) ,
56+ category : z . string ( ) . describe ( "Token category" ) ,
57+ description : z . string ( ) . describe ( "Token description" ) ,
58+ slug : z . string ( ) . describe ( "Token slug" ) ,
59+ logo : z . string ( ) . optional ( ) . describe ( "Token logo URL" ) ,
60+ subreddit : z . string ( ) . optional ( ) . describe ( "Token subreddit" ) ,
61+ notice : z . string ( ) . optional ( ) . describe ( "Token notice" ) ,
62+ tags : z . array ( z . string ( ) ) . optional ( ) . describe ( "Token tags" ) ,
63+ "tag-names" : z . array ( z . string ( ) ) . optional ( ) . describe ( "Token tag names" ) ,
64+ "tag-groups" : z . array ( z . string ( ) ) . optional ( ) . describe ( "Token tag groups" ) ,
65+ urls : z
66+ . object ( {
67+ website : z . array ( z . string ( ) ) . optional ( ) ,
68+ twitter : z . array ( z . string ( ) ) . optional ( ) ,
69+ message_board : z . array ( z . string ( ) ) . optional ( ) ,
70+ chat : z . array ( z . string ( ) ) . optional ( ) ,
71+ facebook : z . array ( z . string ( ) ) . optional ( ) ,
72+ explorer : z . array ( z . string ( ) ) . optional ( ) ,
73+ reddit : z . array ( z . string ( ) ) . optional ( ) ,
74+ technical_doc : z . array ( z . string ( ) ) . optional ( ) ,
75+ source_code : z . array ( z . string ( ) ) . optional ( ) ,
76+ announcement : z . array ( z . string ( ) ) . optional ( ) ,
77+ } )
78+ . optional ( ) ,
79+ platform : CMCPlatformSchema . nullable ( ) . optional ( ) ,
80+ date_added : z . string ( ) . optional ( ) ,
81+ twitter_username : z . string ( ) . optional ( ) ,
82+ is_hidden : z . number ( ) . optional ( ) ,
83+ } )
84+ ) ,
85+ status : z . object ( {
86+ timestamp : z . string ( ) ,
87+ error_code : z . number ( ) ,
88+ error_message : z . string ( ) . nullable ( ) ,
89+ elapsed : z . number ( ) ,
90+ credit_count : z . number ( ) ,
91+ notice : z . string ( ) . nullable ( ) ,
92+ } ) ,
93+ } ) ;
94+
5095const GetTokenMapToolSchema = {
5196 name : "get_cmc_token_map" ,
5297 description :
@@ -150,6 +195,62 @@ const GetTokenMapToolSchema = {
150195 } ,
151196} ;
152197
198+ const GetMetadataV2ToolSchema = {
199+ name : "get_cmc_metadata_v2" ,
200+ description :
201+ "Fetches detailed metadata for cryptocurrencies including logo, description, website URLs, and social links.\n" +
202+ "If you don't know the token id, use get_cmc_token_map tool to get the token id first." ,
203+ parameters : z . object ( {
204+ id : z
205+ . string ( )
206+ . optional ( )
207+ . describe ( "Comma-separated CoinMarketCap cryptocurrency IDs" ) ,
208+ address : z . string ( ) . optional ( ) . describe ( "Contract address" ) ,
209+ skip_invalid : z . boolean ( ) . optional ( ) . default ( false ) ,
210+ aux : z
211+ . string ( )
212+ . optional ( )
213+ . default ( "urls,logo,description,tags,platform,date_added,notice" )
214+ . describe (
215+ "Only include necessary fields to reduce response size. Can be a single value or comma-separated list"
216+ ) ,
217+ } ) ,
218+ execute : async ( args : {
219+ id ?: string ;
220+ slug ?: string ;
221+ symbol ?: string ;
222+ address ?: string ;
223+ skip_invalid ?: boolean ;
224+ aux ?: string ;
225+ } ) => {
226+ try {
227+ const tool = new CMCBaseTool ( ) ;
228+ const response = await tool . getMetadataV2 ( args ) ;
229+ const parsedResponse = CMCMetadataV2Schema . parse ( response ) ;
230+
231+ return {
232+ tokens : Object . fromEntries (
233+ Object . entries ( parsedResponse . data ) . map ( ( [ symbol , tokens ] ) => [
234+ symbol ,
235+ tokens ,
236+ ] )
237+ ) ,
238+ metadata : {
239+ timestamp : parsedResponse . status . timestamp ,
240+ errorCode : parsedResponse . status . error_code ,
241+ errorMessage : parsedResponse . status . error_message ,
242+ elapsed : parsedResponse . status . elapsed ,
243+ creditCount : parsedResponse . status . credit_count ,
244+ notice : parsedResponse . status . notice ,
245+ } ,
246+ } ;
247+ } catch ( error ) {
248+ logger . error ( "Error executing get_cmc_metadata_v2 tool" , error ) ;
249+ return `Error executing get_cmc_metadata_v2 tool` ;
250+ }
251+ } ,
252+ } ;
253+
153254type CMCBaseParams = {
154255 start ?: number ;
155256 limit ?: number ;
@@ -162,6 +263,7 @@ type CMCBaseParams = {
162263export class CMCBaseTool extends APITool < CMCBaseParams > {
163264 schema = [
164265 { name : GetTokenMapToolSchema . name , tool : tool ( GetTokenMapToolSchema ) } ,
266+ { name : GetMetadataV2ToolSchema . name , tool : tool ( GetMetadataV2ToolSchema ) } ,
165267 ] ;
166268
167269 constructor ( ) {
@@ -207,4 +309,37 @@ export class CMCBaseTool extends APITool<CMCBaseParams> {
207309
208310 return await res . json ( ) ;
209311 }
312+
313+ async getMetadataV2 ( params : {
314+ id ?: string ;
315+ slug ?: string ;
316+ symbol ?: string ;
317+ address ?: string ;
318+ skip_invalid ?: boolean ;
319+ aux ?: string ;
320+ } ) {
321+ const queryParams = new URLSearchParams ( ) ;
322+
323+ if ( params . id ) queryParams . set ( "id" , params . id ) ;
324+ if ( params . slug ) queryParams . set ( "slug" , params . slug ) ;
325+ if ( params . symbol ) queryParams . set ( "symbol" , params . symbol ) ;
326+ if ( params . address ) queryParams . set ( "address" , params . address ) ;
327+ if ( params . skip_invalid ) queryParams . set ( "skip_invalid" , "true" ) ;
328+ if ( params . aux ) queryParams . set ( "aux" , params . aux ) ;
329+
330+ const res = await fetch (
331+ `${ CMC_BASE_URL } /cryptocurrency/info?${ queryParams . toString ( ) } ` ,
332+ {
333+ headers : {
334+ "X-CMC_PRO_API_KEY" : process . env . CMC_API_KEY || "" ,
335+ } ,
336+ }
337+ ) ;
338+
339+ if ( ! res . ok ) {
340+ throw new Error ( `API request failed with status: ${ res . status } ` ) ;
341+ }
342+
343+ return await res . json ( ) ;
344+ }
210345}
0 commit comments