A distributed microservices architecture for AI agents processing financial data with Kafka-based asynchronous communication, featuring an API gateway, orchestrator agent, specialized agents (investment, news, knowledge), and a Next.js frontend.
This is a microservices/backend system masquerading as an MCP server. The submission conflates a multi-agent Kafka orchestration platform with MCP tool definitions. Critical structural issues: (1) No MCP server scaffolding detected, no initialize handler, no resources/prompts, no stateless request-response. (2) Tool definitions are inferred from route files and comments, not explicitly registered in MCP format. (3) Parameters have some type hints but lack LLM-optimized descriptions, many describe implementation details rather than user intent. (4) Schemas are partial: most lack explicit input schema registration. (5) Output shapes are undocumented. (6) No error recovery guidance. (7) Tools like 'handleAgentTask' and 'routeToAgent' expose internal Kafka orchestration concerns (taskId, correlationId, agentType filters) rather than user-facing abstractions. (8) Multiple tools (query, response, stream) implement a single logical operation (async polling) split across 3 separate tools, forcing agents into three-call sequences. (9) Email tools (sendWelcomeEmail, sendNewsSummaryEmail) leak SMTP implementation details. This is a backend system, not a production MCP server.
Analyze user's MSE watchlist stocks with personalized AI analysis. Returns Mongolian text analysis based on user profile and watchlist symbols.
Analyze sentiment of financial news using Gemini - returns one of: positive, negative, neutral
Fetch news from Finnhub API - optionally filtered by stock symbol or news category
Generate AI response using Gemini with personalization based on user profile and action type. Supports portfolio analysis, market analysis, watchlist analysis, and generic advice. Returns responses in Mongolian.
Get MSE stock data - prioritize mse_trading_status for current prices, fallback to mse_trading_history for historical data. Supports both raw symbol and -O-0000 suffix forms.
Fetch user investment profile from PostgreSQL for personalization - includes investment goal, risk tolerance, and preferred industries
No MCP server scaffolding detected. This is a backend microservices system (Express + Kafka), not an MCP server. No initialize handler, no tools.list response, no resources/prompts endpoints. Tools are inferred from route files, not explicitly registered in MCP format.
Tool definitions are inferred, not explicitly visible in MCP registration. Cannot verify actual input schemas, output types, or error handling contract. Per the HARD SCORING RULE, inferred tools cap at 50 per-tool.
Async polling pattern (query → response → stream) forces agents into three-step sequences for a single logical operation. Query submits to Kafka, response polls cached result, stream opens SSE. Should compose into one user-facing tool that handles async internally. Violates single-responsibility pattern.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 32 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 38 | - | v1 |
Handle news agent task - fetches financial news, analyzes sentiment with Gemini, publishes news.events, and sends response with summary to agent.responses topic
Handle investment agent task - receives messages from agent.tasks Kafka topic, generates AI response using Gemini, and sends response to agent.responses topic
Handle knowledge query from knowledge.queries Kafka topic - performs semantic search and sends results to knowledge.results topic
Return recent cached AI responses for the authenticated user
Load knowledge base from PostgreSQL into in-memory store for search operations
Get investment advice for portfolio (legacy compatibility endpoint)
Process user request - classifies intent using Gemini, detects complexity, optionally queries knowledge base for RAG context, and routes to appropriate agent or Flink planner
Universal agent query endpoint - sends query to user.requests topic, orchestrator will route to appropriate agent
Get agent response - polling endpoint to retrieve cached agent responses
Route simple user request to appropriate specialized agent (investment, news, knowledge) based on intent. Fetches user profile for personalization if investment agent.
Route complex user request to Flink Planner for multi-step workflow orchestration
Simple semantic search on knowledge base using keyword matching. Scores documents based on keyword presence and applies filters by content type and symbol. Returns top K results normalized by score.
Send daily news summary email to user using Nodemailer with HTML template
Send welcome email to new user using Nodemailer with HTML template
Server-Sent Events (SSE) endpoint for streaming agent responses in real-time
handleAgentTask (duplicate name, appears in investment-agent and news-agent) exposes internal Kafka orchestration (taskId, correlationId, agentType='investment'|'news' filters) instead of user intent. LLM must reason about Kafka topics and message formats, not abstracted intent. Violates abstraction and composition patterns.
Descriptions are thin and implementation-focused. E.g., 'Get agent response - polling endpoint to retrieve cached agent responses', does not explain WHEN to call (after query?), WHAT it returns, or WHAT errors mean. Average ~50 chars when rubric baseline for A-tier is 194 chars. No guidance on idempotence, retry strategy, or recovery.
No output schemas documented anywhere. Descriptions lack return type examples. getMSEData says 'Supports both raw symbol and -O-0000 suffix forms', but does not specify what fields are in the result or pagination contract. Agents cannot infer downstream tool compatibility.
Email tools (sendWelcomeEmail, sendNewsSummaryEmail) are WRITE operations but lack confirmation/dry-run support, documented idempotence, or error recovery guidance. Description does not state 'calling twice with same input sends email twice', agents may retry on network errors, causing duplicate emails.
Parameter 'type' in query tool is ambiguous (agent type? request type?) and enum-constrained to undocumented values ('portfolio', 'news', 'market', 'risk', 'etc'). No enum definition provided. Agents cannot know valid values without trial-and-error.
Pagination not implemented. history() accepts limit but no offset/page/cursor; getMSEData fetches 'top 50 by volume' with no way to iterate. Large result sets waste context and risk hallucination. Rubric requires pagination: page/offset + limit + total count.
No error recovery guidance. Descriptions do not explain what each tool returns on failure, whether errors are retryable, or what the LLM should do next. E.g., 'request not found', should it retry polling (response tool), or move on?