A Spring Boot-based MCP server for managing courses with chatbot assistance, providing tools for adding, retrieving, searching, updating, and removing courses from a MySQL database
This Spring AI MCP server exposes 5 course management tools with HTTP transport. Critical issues: (1) Tool names lack action verbs, 'addNewCourse', 'removeCourseById', 'updateCourseByCourseId' are awkward; 'getAllCourses' and 'getCoursesByTitle' partially qualify. Production tools favor verb_noun (create_course, delete_course, update_course, list_courses, search_courses). (2) Descriptions are present but terse (avg 85 chars, below the 194-char baseline for A+ tools). Examples: 'Add a new course with the given title and description' lacks context on return value, data constraints, or when to use it vs alternatives. 'Get the list of all the available courses whose courseTitle matches with the provided courseTitle' is redundant and doesn't explain input format or result limits. (3) All 5 tools have basic input schemas with type and description for parameters, which is positive. However, no output schemas are documented, the LLM cannot predict what fields will be returned, breaking the composition pattern. (4) Error handling is minimal; descriptions do not guide recovery (e.g., 'If no course is found, return 'Course doesn't exist'' is a vague spec, not an error handling pattern). (5) Destructive and write operations (removeCourseById, updateCourseByCourseId) rely on a 'userConfirmed' boolean parameter to prevent accidents, an anti-pattern. Per pattern:confirmation-request, a better design would be two separate tools (e.g., confirm_course_removal + execute_removal) or a dry-run parameter. (6) Parameter naming is inconsistent: courseTitle, courseId, userConfirmed mix camelCase and use type suffixes. (7) No evidence of pagination for list operations, getAllCourses returns all courses with no limit or offset, risking context window exhaustion. (8) Schemas visible in the tool definitions, but no response structure documented for any tool. Average per-tool score: 42 (range 30 - 55).
Add a new course with the given title and description
Get the list of all Currently Available Courses.
Get the list of all the available courses whose courseTitle matches with the provided courseTitle.
Remove the course whose courseId matches the provided courseId. If no course is found, return 'Course doesn't exist'. Requires userConfirmed=true to proceed deletion. If user confirms the deletion then proceed with {userConfirmed}=true
Update the title and description of a course based on its courseId. Requires userConfirmed=true to proceed updating course. If user confirms the updating course then proceed with {userConfirmed}=true
Tool names do not follow verb_noun convention. 'addNewCourse' is awkward; 'getAllCourses' is redundant. LLMs rely on action verbs (create, list, search, update, delete) to infer intent before reading descriptions.
No output schemas documented for any tool. LLMs cannot predict which fields will be returned (course_id, title, description, created_at, etc.), preventing downstream tool chaining and data extraction.
Destructive operations (removeCourseById, updateCourseByCourseId) use a 'userConfirmed' boolean parameter to gate execution. This is an anti-pattern; proper design requires a dry-run step or two-phase confirmation tool flow.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 43 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 46 | - | v1 |
Tool descriptions are terse (avg 85 chars vs 194-char baseline) and lack context on return values, constraints, or decision points between similar tools. Example: 'Get the list of all the available courses whose courseTitle matches with the provided courseTitle' is redundant and doesn't specify if search is case-sensitive or regex-enabled.
getAllCourses returns all courses with no pagination (limit, offset, page_size). Large result sets will exhaust the LLM context window. Baseline: A+ tools return max 20-50 items and include total count and next_cursor.
No error recovery guidance. 'If no course is found, return 'Course doesn't exist'' is a vague spec; descriptions should guide the LLM on next steps (e.g., 'Try searching with getCoursesByTitle()'). Error responses must be actionable.