An MCP server for tracking and managing cryptocurrency portfolio allocations.
CryptoPortfolioMCP has 4 tools with clear, descriptive docstrings (average 258 chars) and reasonably good schema definitions in FastMCP. However, several patterns are missing or under-specified. Tool names start with action verbs (get_, add_, portfolio_), descriptions explain what/when/why well, and parameters include type information. But: (1) parameter descriptions are embedded in docstrings rather than attached to schema fields, the source shows descriptions in the Python docstrings, but it's unclear if they're actually propagated to the JSON Schema that the MCP server exposes; (2) no enum constraints, input validation, or error guidance; (3) output schemas are documented in docstrings but not formally declared in schema definitions; (4) the add_holding tool lacks input validation rules (e.g., minimum positive amount); (5) portfolio_value_history accepts a Context parameter that is framework-provided, which is unusual and should not be exposed as a user-facing parameter; (6) no error handling patterns or recovery guidance. On the positive side, names are action-verb prefixed, descriptions exceed 100 chars (good token density), and the tools compose logically (get price, add holdings, view summary). The code is maintainable and uses FastMCP idioms correctly.
Add a cryptocurrency holding to the portfolio. Parameters: coin_symbol (str): The trading pair symbol (e.g., "BTC/USDT" or "btc"). If no "/USDT" is provided, it will be appended automatically. Case-insensitive. amount (float): The quantity of the cryptocurrency to add. Must be a positive number. Returns: A confirmation message indicating the holding was added. Example: add_holding("BTC", 0.1) -> "Added 0.1 BTC/USDT to portfolio"
Get current portfolio summary with total value using Binance prices. Returns: A string containing a formatted summary of all holdings with current prices and total portfolio value in USDT. Example: "Portfolio Summary (Binance Prices):\nBTC/USDT: 0.1 @ $60000.00 = $6000.00\nETH/USDT: 2.0 @ $2000.00 = $4000.00\nTotal Value: $10000.00"
Get current price for a cryptocurrency from Binance. Parameters: coin_symbol (str): The trading pair symbol (e.g., "ETH/USDT" or "eth"). If no "/USDT" is provided, it will be appended automatically. Case-insensitive. Returns: A string with the current price in USDT. Example: get_price("ETH") -> "Current price of ETH/USDT on Binance: $2000.50"
Generate a chart of portfolio value over time using Binance prices. Parameters: ctx (Context): MCP context object for progress reporting. Automatically provided by the MCP framework. Returns: An Image object containing a PNG chart of portfolio value history. Notes: - Uses current prices for historical points (simplified implementation) - Chart shows value progression as holdings were added
Parameter descriptions in docstrings, not schema, unclear if exposed to MCP clients. The FastMCP decorator appears to use Python docstrings for description, but JSON Schema parameter fields (in Input schema) lack explicit descriptions.
add_holding has no input validation or enum constraints. Accepts coin_symbol as free-form string; should validate against known Binance trading pairs or at least document the constraint. Amount parameter lacks minimum/maximum bounds.
portfolio_value_history exposes Context (ctx) as a parameter. This is a framework-provided object that should not be surfaced in the tool signature. The MCP spec handles progress reporting via the context, but users should not need to pass it explicitly. This breaks the natural interface expectation.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 55 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 43 | - | v1 |
No error handling guidance. Tools can fail (API rate limits, invalid symbol, database errors) but return no structured error messages or recovery hints. LLM cannot distinguish retryable from fatal errors.
Output schemas not formally declared. Docstrings describe return types (string, Image) but JSON Schema doesn't include output type definitions. LLM cannot parse structured results reliably.
Prompt 'analyze_portfolio' references tools but has no example or structured input schema. Prompts should declare what context/state they expect to operate on.
No idempotency guarantees. add_holding creates a new record every time it's called with the same parameters, which risks duplicate holdings if retried. Should either be marked as non-idempotent or support duplicate detection.