get-news-by-type
Retrieve cryptocurrency news articles filtered by specific categories like handpicked, trending, bullish, or bearish to stay informed about market developments.
Instructions
Get news articles based on a type.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | News type | |
| page | No | Page number | |
| limit | No | Number of results per page |
Implementation Reference
- src/tools/toolConfigs.ts:317-327 (schema)Tool configuration defining the name 'get-news-by-type', description, API endpoint '/news/type/{type}', HTTP method GET, and Zod input schema for parameters (type enum, page, limit). This config is used for both schema validation and registration.{ name: 'get-news-by-type', description: 'Get news articles based on a type.', endpoint: '/news/type/{type}', method: 'GET', parameters: { type: z.enum(['handpicked', 'trending', 'latest', 'bullish', 'bearish']).describe('News type'), page: z.number().optional().describe('Page number').default(1), limit: z.number().optional().describe('Number of results per page').default(20), }, },
- src/tools/toolConfigs.ts:317-327 (schema)Tool schema and configuration defining the name, description, endpoint '/news/type/{type}', method GET, and Zod input parameters for the get-news-by-type tool.{ name: 'get-news-by-type', description: 'Get news articles based on a type.', endpoint: '/news/type/{type}', method: 'GET', parameters: { type: z.enum(['handpicked', 'trending', 'latest', 'bullish', 'bearish']).describe('News type'), page: z.number().optional().describe('Page number').default(1), limit: z.number().optional().describe('Number of results per page').default(20), }, },
- src/index.ts:4-18 (registration)Imports toolFactory and toolConfigs, creates MCP server, and calls registerTools(server, allToolConfigs) to register the get-news-by-type tool along with others.import { registerTools } from './tools/toolFactory.js'; import { allToolConfigs } from './tools/toolConfigs.js'; // Create server instance const server = new McpServer({ name: 'coinstats-mcp', version: '1.0.0', capabilities: { resources: {}, tools: {}, }, }); // Register all tools from configurations registerTools(server, allToolConfigs);
- src/tools/toolFactory.ts:21-77 (handler)The inline handler function registered for get-news-by-type (and other API tools), which constructs the API request using the tool config and delegates to universalApiHandler for execution.server.tool(config.name, config.description, config.parameters, async (params: Record<string, any>) => { // Handle local operations if (config.isLocal) { // Handle specific local tools if (config.name === 'save-share-token') { await saveToCache('shareToken', params.shareToken); return { content: [ { type: 'text', text: 'Share token saved successfully', }, ], }; } if (config.name === 'get-share-token') { const shareToken = await getFromCache('shareToken'); return { content: [ { type: 'text', text: shareToken ? shareToken : 'No share token found in cache', isError: !shareToken, }, ], }; } // Future local tools can be added here // Default response for unhandled local tools return { content: [ { type: 'text', text: 'Operation completed', }, ], }; } // Handle API operations const basePath = config.basePath || COINSTATS_API_BASE; const method = config.method || 'GET'; // Methods that typically have a request body const bodyMethods = ['POST', 'PUT', 'PATCH', 'DELETE']; // For GET/DELETE requests, all params go in the URL // For POST/PUT/PATCH, send params as the body if (bodyMethods.includes(method.toUpperCase())) { return universalApiHandler(basePath, config.endpoint, method, {}, params); } else { return universalApiHandler(basePath, config.endpoint, method, params); } });
- src/tools/toolFactory.ts:19-79 (registration)Registers the get-news-by-type tool (via allToolConfigs) with the MCP server by calling server.tool() with its config details and handler.export function registerTools(server: McpServer, toolConfigs: ToolConfig<any>[]) { toolConfigs.forEach((config) => { server.tool(config.name, config.description, config.parameters, async (params: Record<string, any>) => { // Handle local operations if (config.isLocal) { // Handle specific local tools if (config.name === 'save-share-token') { await saveToCache('shareToken', params.shareToken); return { content: [ { type: 'text', text: 'Share token saved successfully', }, ], }; } if (config.name === 'get-share-token') { const shareToken = await getFromCache('shareToken'); return { content: [ { type: 'text', text: shareToken ? shareToken : 'No share token found in cache', isError: !shareToken, }, ], }; } // Future local tools can be added here // Default response for unhandled local tools return { content: [ { type: 'text', text: 'Operation completed', }, ], }; } // Handle API operations const basePath = config.basePath || COINSTATS_API_BASE; const method = config.method || 'GET'; // Methods that typically have a request body const bodyMethods = ['POST', 'PUT', 'PATCH', 'DELETE']; // For GET/DELETE requests, all params go in the URL // For POST/PUT/PATCH, send params as the body if (bodyMethods.includes(method.toUpperCase())) { return universalApiHandler(basePath, config.endpoint, method, {}, params); } else { return universalApiHandler(basePath, config.endpoint, method, params); } }); }); }
- src/tools/toolFactory.ts:19-79 (registration)registerTools iterates over allToolConfigs and calls server.tool for each, registering 'get-news-by-type' with its schema and a generic async handler that delegates to universalApiHandler for API calls.export function registerTools(server: McpServer, toolConfigs: ToolConfig<any>[]) { toolConfigs.forEach((config) => { server.tool(config.name, config.description, config.parameters, async (params: Record<string, any>) => { // Handle local operations if (config.isLocal) { // Handle specific local tools if (config.name === 'save-share-token') { await saveToCache('shareToken', params.shareToken); return { content: [ { type: 'text', text: 'Share token saved successfully', }, ], }; } if (config.name === 'get-share-token') { const shareToken = await getFromCache('shareToken'); return { content: [ { type: 'text', text: shareToken ? shareToken : 'No share token found in cache', isError: !shareToken, }, ], }; } // Future local tools can be added here // Default response for unhandled local tools return { content: [ { type: 'text', text: 'Operation completed', }, ], }; } // Handle API operations const basePath = config.basePath || COINSTATS_API_BASE; const method = config.method || 'GET'; // Methods that typically have a request body const bodyMethods = ['POST', 'PUT', 'PATCH', 'DELETE']; // For GET/DELETE requests, all params go in the URL // For POST/PUT/PATCH, send params as the body if (bodyMethods.includes(method.toUpperCase())) { return universalApiHandler(basePath, config.endpoint, method, {}, params); } else { return universalApiHandler(basePath, config.endpoint, method, params); } }); }); }
- src/services/request.ts:35-97 (handler)Core handler logic executed for get-news-by-type: processes endpoint '/news/type/{type}' by replacing {type} with param value, adds remaining params (page, limit) as query string, fetches from CoinStats API, returns JSON stringified response as MCP text content or error.export async function universalApiHandler<T>( basePath: string, endpoint: string, method: string = 'GET', params: Record<string, any> = {}, body?: any ): Promise<{ content: Array<{ type: 'text'; text: string; isError?: boolean }>; }> { try { // Handle path parameters - replace {paramName} in endpoint with actual values let processedEndpoint = endpoint; let processedParams = { ...params }; // Find all path parameters in the endpoint (e.g., {coinId}, {id}, {type}) const pathParamMatches = endpoint.match(/\{([^}]+)\}/g); if (pathParamMatches) { for (const match of pathParamMatches) { const paramName = match.slice(1, -1); // Remove { and } if (processedParams[paramName] !== undefined) { // Replace the placeholder with the actual value processedEndpoint = processedEndpoint.replace(match, processedParams[paramName]); // Remove the parameter from query params since it's now part of the path delete processedParams[paramName]; } else { throw new Error(`Required path parameter '${paramName}' is missing`); } } } // MCP clients might not support '~' in parameter names, so we replace '-' with '~' specifically for the /coins endpoint before making the request. if (endpoint === '/coins') { processedParams = Object.entries(processedParams).reduce((acc, [key, value]) => { acc[key.replace(/-/g, '~')] = value; return acc; }, {} as Record<string, any>); } const url = `${basePath}${processedEndpoint}`; const data = await makeRequestCsApi<T>(url, method, processedParams, body); if (!data) { return { content: [{ type: 'text', text: 'Something went wrong', isError: true }], }; } return { content: [ { type: 'text', text: JSON.stringify(data), }, ], }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error}`, isError: true }], }; } }
- src/services/request.ts:35-97 (handler)Core universal API handler invoked by the tool handler; processes endpoint path parameters like {type} for /news/type/{type}, makes authenticated fetch to CoinStats API base + endpoint, returns JSON response in MCP content format.export async function universalApiHandler<T>( basePath: string, endpoint: string, method: string = 'GET', params: Record<string, any> = {}, body?: any ): Promise<{ content: Array<{ type: 'text'; text: string; isError?: boolean }>; }> { try { // Handle path parameters - replace {paramName} in endpoint with actual values let processedEndpoint = endpoint; let processedParams = { ...params }; // Find all path parameters in the endpoint (e.g., {coinId}, {id}, {type}) const pathParamMatches = endpoint.match(/\{([^}]+)\}/g); if (pathParamMatches) { for (const match of pathParamMatches) { const paramName = match.slice(1, -1); // Remove { and } if (processedParams[paramName] !== undefined) { // Replace the placeholder with the actual value processedEndpoint = processedEndpoint.replace(match, processedParams[paramName]); // Remove the parameter from query params since it's now part of the path delete processedParams[paramName]; } else { throw new Error(`Required path parameter '${paramName}' is missing`); } } } // MCP clients might not support '~' in parameter names, so we replace '-' with '~' specifically for the /coins endpoint before making the request. if (endpoint === '/coins') { processedParams = Object.entries(processedParams).reduce((acc, [key, value]) => { acc[key.replace(/-/g, '~')] = value; return acc; }, {} as Record<string, any>); } const url = `${basePath}${processedEndpoint}`; const data = await makeRequestCsApi<T>(url, method, processedParams, body); if (!data) { return { content: [{ type: 'text', text: 'Something went wrong', isError: true }], }; } return { content: [ { type: 'text', text: JSON.stringify(data), }, ], }; } catch (error) { return { content: [{ type: 'text', text: `Error: ${error}`, isError: true }], }; } }
- src/index.ts:17-18 (registration)Main server initialization calls registerTools to register get-news-by-type with the MCP server.// Register all tools from configurations registerTools(server, allToolConfigs);