MCP server that fetches cryptocurrency token prices from Uniswap V3 pools across multiple blockchain networks (Ethereum, Polygon, Arbitrum, Optimism) and converts prices to USD using CryptoCompare API.
The server defines two tools with explicit registration and basic descriptions. Both tools have typed input schemas using Zod validation, which is positive. However, there are significant gaps: (1) Descriptions lack LLM-optimization depth, they are lengthy and bury key distinctions; (2) Parameters have type constraints but several lack actionable guidance; (3) Output schemas are not documented, responses are inferred from the code but not formally declared; (4) Error handling is minimal, with generic error messages that don't guide the agent on recovery; (5) The getTokenPrice tool includes example addresses in its description (DAI on Ethereum, DAI on BSC), which violates the pattern-tool-description rule and risks LLMs treating those as literal fallback values. The naming is clear (verb-first: 'get'), but parameter descriptions could be more prescriptive about valid inputs and fallback behavior.
Returns a list of supported blockchain networks, including their chain IDs and names, formatted as a Markdown table.
Fetches the current price of a token against USDT, USDC/BUSD, or WETH/WBNB (in that order) in a Uniswap V3/PancakeSwap V3 pool with 0.3% fee tier on the specified chain. Automatically retrieves token decimals and symbol. Converts the price to USD using CryptoCompare API for all quote tokens. Returns the price in USD.
Output schemas are not documented. Callers cannot determine what fields to expect in responses without reading the implementation. getTokenPrice returns {content: [{type, text}], isError} but this contract is inferred, not declared.
Parameter descriptions include concrete example addresses (0x6B175474E89094C44Da98b954EedeAC495271d0F for DAI on Ethereum, 0x1AF3F329e8BE154074D8769D3FFa4eE058B1DBc3 for DAI on BSC). LLMs reuse example values literally, risking incorrect token pricing if the agent passes these examples in real calls instead of adapting to actual user context.
Error handling does not guide recovery. When a pool is not found, the tool silently tries the next quote token with no feedback. If all pools fail, the error message 'Error fetching [...]' is generic and does not tell the agent what to try next (e.g., verify the token exists on that chain, check if liquidity exists in a different pool).
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 53 | 2026-07-28+ | v2 |
getTokenPrice description is verbose (200+ words) and includes implementation details (fee tier 0.3%, pool selection logic) that clutter the LLM's decision-making. Descriptions should focus on WHAT the tool does, WHEN to use it, and what result to expect, not HOW it works internally.
chainId parameter lacks validation guidance in its description. The description states it accepts numbers like '1 for Ethereum, 137 for Polygon, 42161 for Arbitrum, 10 for Optimism, 56 for BSC', but does not clarify: (a) are these the ONLY valid values? (b) what happens if an unsupported chain is passed? (c) should the LLM call getSupportedChains first? Enum or explicit constraint is missing.
No documented relationship between the two tools. The pattern suggests discovery tools (like getSupportedChains) should indicate when to call them. The description of getSupportedChains should explicitly state: 'Call this first to see supported chains before invoking getTokenPrice.' This is a composition gap.