A Kotlin-based MCP server providing file management and Gradle project tools
This Kotlin MCP server exhibits significant structural issues across tool definitions. While all 5 tools are explicitly registered with names and basic schemas, the implementation reveals critical gaps in parameter documentation, schema specificity, and error guidance. Parameter descriptions are almost entirely missing, the code shows properties like 'path', 'content', 'directoryName', and 'task' defined as bare JsonPrimitive("string") with no descriptions attached. Tool descriptions are minimal (10 - 50 chars), below the production baseline of 194 chars. Output schemas exist but are skeletal (e.g., LoadFileTool.output declares only 'content' as a string with no description of what content means or how large it might be). Error messages are generic ('Path argument is required', 'projectName argument is required') and offer no recovery guidance. The tool composition lacks clarity on idempotency, permission boundaries, and security implications of file/project operations. The server does use proper Tool.Input/Output classes, indicating some structure, but the quality is far below production standards.
Run a Gradle build in a given project directory. Uses gradlew.bat if available, falls back to gradle.
Create a Kotlin project
Load a file content
read directory content
Save content to a file
Parameter descriptions are almost entirely absent. All 5 tools define input parameters as bare JsonPrimitive("string") with no description fields attached. The rubric mandates: 'Every parameter needs a description explaining what it controls.' and '100% of A+ tool params have descriptions.' This server has ~0%.
Tool descriptions are far below production baseline (194 chars average). Most descriptions are 20 - 40 characters and lack critical context: WHAT does the tool do exactly? WHEN should the LLM call it? WHAT are prerequisites and constraints? 'Save content to a file' tells an LLM nothing about overwrite behavior, directory assumptions, or max file size.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 52 | 2025-06-18+ | v2 |
| 2026-03-09 | F | 34 | - | v1 |
Output schemas are skeletal or missing. LoadFileTool, ReadDirTool, and BuildProjectTool declare only a single string field with no description of structure, encoding, or size limits. CreateKotlinProject output doesn't explain what directoryName represents (absolute path? relative? just the name?). The rubric requires: 'Document the output schema. LLMs need to know what fields to expect.' 100% of A+ tools have documented return types.
No error guidance or recovery hints. Error responses are generic ('Path argument is required', 'projectName argument is required'). The rubric mandates: 'Error responses must tell the LLM what to do next' and cite the pattern recovery-guide. Current errors give the agent nothing actionable. E.g., when a file path is invalid, should the LLM try a different path? Call read-directory first?
Security concerns are undocumented. save-file and load-file perform filesystem operations but the tool definitions provide no documentation of: (1) what directory sandboxing is enforced, (2) what path traversal protections exist, (3) who is permitted to read/write which files. The code passes a SafeFileManager but the tool is silent on permissions.
Composition issues: create-kotlin-project combines multiple responsibilities (directory creation, scaffolding, Gradle init). Per the rubric pattern:tool, 'Each tool should do exactly one thing.' This tool should either be split into separate tools or named more specifically (e.g., 'scaffold-kotlin-gradle-project'). Also, the relationship between create-kotlin-project and build-project is not documented, can build-project work on projects created by this tool?
No parameter constraints or enums. Tasks like 'build', 'test', 'clean' are common Gradle tasks but the build-project tool accepts a free-form 'task' string with no enum or constraint. An LLM might try invalid task names like 'compile' or 'run' and fail silently. The rubric states: 'When a parameter accepts one of a known set of values, declare it as an enum.'