Multi-module demonstration of MCP (Model Context Protocol) servers and clients using Spring AI. Includes a Java-based MCP server exposing stock exchange tools, a Java MCP client that connects to MCP servers, and a Python MCP server with employee information tools.
This is a multi-module demo project with mixed transport concerns and serious definition quality gaps. The Java Spring AI server (mcp-server) uses WebMVC HTTP, providing basic HTTP accessibility. However, the Python server relies on FastMCP which defaults to STDIO. Tool definitions are sparse: 3 Java tools have minimal descriptions (10-20 chars) and incomplete schemas; 1 Python tool has a docstring but no formal schema visible. Parameter descriptions are absent or trivial. No error handling, no output schema documentation, no enum constraints, no pagination support. The 'get_info_about' tool is particularly weak, its description is multi-line narrative prose rather than a concise agent-friendly summary. Tool naming uses verb prefixes (getCompanyByName, getAllCompanies, getStockByCompany, get_info_about) but some are overly specific without flexibility. No evidence of composition testing, idempotency guarantees, or recovery guidance. This appears to be a learning/demo project, not production-ready tooling.
Get All Companies
Get a company by name
Get stock information for a company
Get Information about a given employee name: - Employee Name - Salary
Tool descriptions are extremely short (10 - 25 characters) and lack context. 'Get a company by name', 'Get All Companies', 'Get stock information for a company' do not explain WHEN to use each tool or what distinguishes them. LLMs cannot optimize tool selection with such minimal docstrings.
Parameter descriptions are missing entirely. The 'companyName' parameter appears in three tools with no explanation of format constraints, whether partial matches are accepted, case sensitivity, or valid examples. This forces LLMs to guess.
Output schemas are not documented. The tools return unspecified data structures (presumably JSON objects with company/stock fields), but without documented output schemas, LLMs cannot plan downstream tool calls or extract specific fields.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 34 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 34 | - | v1 |
No pagination support. getAllCompanies returns all companies with no limit, offset, or cursor. If the dataset grows beyond a few dozen records, the response will bloat the LLM context window, degrading reasoning.
get_info_about's description is verbose narrative prose (3+ lines in docstring), not a concise summary. LLMs prefer 50 - 200 character descriptions that fit in a single line and answer: what does it do, when is it useful, what does it return?
No error handling guidance. Tools provide no recovery hints or error categorization. If getAllCompanies fails, the LLM does not know whether to retry, ask the user, or abandon the operation.
Python server (mcp-python-server) likely uses STDIO transport (FastMCP default). STDIO cannot be used by hosted MCP clients and is not remotely accessible. This caps the Python server's protocol readiness at 50.
No tool composition. Three stock exchange tools (getCompanyByName, getAllCompanies, getStockByCompany) do not guarantee that output from one feeds into the next. For example, getAllCompanies should return company names that can be passed directly to getStockByCompany, but this is undocumented.
No parameter constraints. 'companyName' accepts any string; there is no enum, regex pattern, or length limit. LLMs may pass invalid names, typos, or empty strings without guidance.
Tool naming inconsistency: Java tools use camelCase (getCompanyByName, getAllCompanies), Python tool uses snake_case (get_info_about). While both are valid, mixed conventions across a suite create cognitive friction for LLMs expected to call diverse toolsets.