AI-powered stock investment analysis and recommendation system with RAG-based chat, technical analysis, backtesting, and LLM-driven reporting for Korean stock market (KOSPI/KOSDAQ)
Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
Friendantial has 10 tools with basic MCP definitions, but substantial gaps in parameter descriptions, schema completeness, and error handling. Most tools have names that are RESTful path-style rather than verb-noun action patterns. Input schemas ARE visible and typed (good), but parameter descriptions are minimal (most are 1-2 lines, e.g. 'Stock code (e.g., 005930.KS)'). No output schemas documented. No error handling guidance. No tool annotations (readOnlyHint, etc.). The frontend and Dockerfile show this is a working FastAPI service, but MCP integration lacks the rigor required for reliable agent composition.
Tools (10)
backtest/simulateread only50/100
Simulate stock recommendations at a past date and calculate 7-day forward returns for backtesting
Tool names are RESTful paths, not action verbs. 'reporting/summary' should be 'generate_investment_report_summary'; 'basic_analysis/recommendations' should be 'get_stock_recommendations'; 'market-data/ohlcv/{stock_code}' should be 'fetch_ohlcv'. LLMs infer intent from verb-noun patterns (get_, create_, search_, etc.), not REST paths. Path-style names make tool selection ambiguous and force LLMs to read full descriptions instead of parsing the name.
Parameter descriptions are too short and lack actionable detail. Example: 'Stock code (e.g., 005930.KS)' (28 chars) does not explain format, valid range, or when to use the tool. Missing: format specification, length constraints, valid patterns, dependencies on other parameters.
Example for 'stock_code': 'Korean stock code in format XXXXXX.KS (e.g., 005930.KS for Samsung Electronics). Use this tool to fetch detailed information for a specific listed stock.' For 'persona': 'Choose "friend" for casual, conversational advice, or "analyst" for formal technical analysis and metrics.'
Document output schemas for all tools. Example for 'reporting/summary': 'Returns { "report": string (markdown formatted report), "timestamp": ISO-8601 date string, "stocks_analyzed": integer count }'. For 'basic_analysis/recommendations': 'Returns { "candidates": array of { "code": string, "name": string, "score": number (0-100), "stars": integer (1-5), "reason": string, "price": number }, "total_stocks_evaluated": integer, "strategy_used": string }'.
Add error handling guidance to each tool description. Example: 'If the stock code is invalid, returns HTTP 404 with message "Stock code not found. Try list_all_stocks() to see available tickers." If the AI service is temporarily unavailable, returns HTTP 503, retry after 30 seconds.'
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Score history
Overall score trend
↓ 12 points across a rubric change (v1 → v2)
41/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-22
F
41
<=2025-11-25
v2
2026-03-09
D
53
-
v1
RAG-based Q&A endpoint that answers investment questions about a stock using recent news as context
reporting/stock/{stock_code}read onlyauth50/100
Generate detailed AI analysis report for a specific stock
reporting/summaryread onlyauth50/100
Generate AI investment report summary with portfolio recommendations based on market analysis and strategy
No output schemas documented. Tools return JSON responses (e.g. 'report' field in reporting/summary, 'candidates' array in basic_analysis/recommendations), but LLMs have no visibility into response structure, field types, or required fields. This forces LLMs to guess what fields exist and their types, leading to failed downstream tool calls and incorrect data extraction.
No error handling guidance. Tools do not document what errors they may return, error recovery paths, or how agents should respond to failures. Example: If 'reporting/stock/{stock_code}' is called with an invalid stock code, the description provides no hint about whether the agent should retry, ask the user, or try a different code.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). All 10 tools are marked risk='READ_ONLY' in the metadata provided, but this is not visible in the MCP tool definitions themselves. Modern MCP servers should include toolAnnotations (readOnlyHint, destructiveHint) in the tool schema so clients can make safety decisions automatically.
Parameter naming inconsistency and ambiguity. 'stock_code' parameter appears in 5 tools but is not consistently documented. Some tools accept it as a path parameter (e.g., 'reporting/stock/{stock_code}'), others as a query param (e.g., 'market-data/ohlcv/{stock_code}'). Description should clarify format (KS suffix? ISIN? Bloomberg ticker?), not just example.
'health' tool is poorly named and described. 'health' is a noun, not a verb. Should be 'check_health' or 'get_server_status'. Description 'Health check endpoint that returns server status and current timestamp' is generic and does not explain when an LLM should call this tool instead of a business tool. No parameters listed, so no way to know if it accepts configuration.
Missing parameter constraints and validation guidance. Example: 'persona' enum is ['friend', 'analyst'] but the description does not explain what each persona means or when to choose one. 'strategy' enum is ['day_trader', 'long_term_trader'] but no description of risk profile, time horizon, or suitability criteria. LLMs cannot reason about parameter selection without this context.
No pagination guidance for tools that return lists. 'basic_analysis/recommendations' returns 'candidates' (top 5 stocks) and 'history/recommendations' accepts 'limit' parameter, but no documentation of total count, next_cursor, or how to fetch older records.
Tool composition and chaining unclear. 'opinion/{stock_code}' is a RAG-based Q&A tool that 'answers investment questions about a stock using recent news as context', but no description of what 'recent news' means or how it relates to 'basic_analysis/news-sentiment/{stock_code}'. An agent might call both tools redundantly.
Add tool annotations (readOnlyHint) to the tool definitions. All 10 tools are read-only; mark them with readOnlyHint=true so clients know they are safe to call without user confirmation.
Document enum values with explanations. For 'strategy', add: 'day_trader: short-term positions (1 day to 1 week), higher volatility tolerance, focus on technical patterns | long_term_trader: positions held weeks to years, fundamental focus, lower volatility tolerance.'
Clarify parameter dependencies and constraints. For 'backtest/simulate', document: 'target_date and codes are both optional. If codes is omitted, simulates all available stocks. If target_date is omitted, uses the most recent backtest date available.' For 'history/recommendations', add: 'limit must be 1 - 1000; defaults to 20. as_of must be a valid trading day in YYYY-MM-DD format.'
Add pagination support with explicit guidance. For 'history/recommendations', add parameters: 'offset' (default 0) and document response: 'Returns { "records": [...], "total_available": integer, "offset": integer, "limit": integer, "has_more": boolean }'. For 'basic_analysis/recommendations', document: 'Always returns top 5 stocks; use get_recommendation_history() to access historical rankings.'
Document tool interaction flows. Create a brief guide: 'To analyze a stock: 1) fetch_ohlcv(code), 2) calculate_technical_indicators(code), 3) fetch_news_sentiment(code), 4) generate_stock_analysis_report(code, persona). Use answer_stock_question_rag(code, question) for follow-up analysis.' This prevents agent redundancy and enables efficient composition.
Validate inputs server-side and return clear error messages. Example: If persona is invalid, return: 'Invalid persona "investor". Must be one of: friend, analyst. Use friend for casual advice or analyst for formal metrics.' If stock_code format is wrong, return: 'Invalid stock code "005930". Expected format: XXXXXX.KS (e.g., 005930.KS). Use this to specify Korean Exchange tickers.'