--- name: edt-mcp-tool-conventions description: Cross-tool consistency contract for EDT-MCP tools — parameter naming, error shape, output format, pagination, not-found semantics, schema/README alignment. Use when editing any class under tools/impl, adding a parameter, changing a tool's output, or reviewing a tool for consistency. --- # EDT-MCP — tool contract (consistency) The same concept must behave the same way across every tool. This skill is the canon to hold to. ## Parameter naming | Concept | Canonical | Anti-example | |---|---|---| | Project | `projectName` | `project` | | Module | `modulePath` (from `src/`; the resolver also accepts an absolute path) | `module`, or a decomposed `objectName+moduleType+formName+commandName` | | Fully-qualified name | `fqn` | — | | Object name | `objectName` | — | | Synonym / language | `synonym` / `language` | — | | Limit / offset | `limit` / `offset` | `maxResults`, `maxDepth` | Parameter names are **lowerCamelCase** — `ToolContractConsistencyTest` fails snake_case. When renaming a parameter, accept the old name as a documented alias for one release, then deprecate. ## Read parameters typed Read arguments via `JsonUtils.extractStringArgument/extractIntArgument/extractBooleanArgument/extractObjectArray`; check required ones via `JsonUtils.requireArguments(params, "a", "b")` (returns a ready error-JSON or null). Don't parse a raw `Map` by hand. (There is no typed `ToolParams` class — `JsonUtils` is the canon.) **Every parameter read in `execute()` must be declared in `getInputSchema()`** (otherwise it is invisible to schema-driven clients) and vice versa. ## Error contract - Errors only via `ToolResult.error(...)` (machine-readable: success=false + message/code). Never return a bare `"Error: …"` / `"Project not found"` string, never let an exception escape the tool. - "project not found" — one text/shape through the shared `ProjectContext` resolver. ## Output format - Similar tools use the same format (don't make one JSON and another markdown without a reason). The plugin default is markdown (see `IMcpTool.ResponseType`). - JSON fields use one style (don't mix camelCase/snake_case in similar responses). - not-found — one semantics: an empty list for "list", an error for "get a specific one". Don't mix null/empty/error. ### Response format policy (Markdown vs JSON) `structuredContent`/JSON is for the client to consume (UI rendering, verbatim round-trip of identifiers, a future `outputSchema`), NOT for the agent to read. **MARKDOWN is the default** (token-efficient, readable). A tool returns JSON only when its result carries: - **(a)** round-trip IDs another tool consumes; - **(b)** machine-structured positions (e.g. error line/column); - **(c)** a declared `outputSchema`; - **(d)** UI-rendered data. Action/confirmation/status results with none of these return MARKDOWN. `write_module_source` is the reference MARKDOWN action tool; `AbstractMetadataWriteTool` subclasses stay JSON because they return the created object's round-trip FQN. Tool families that stay JSON, and why: - metadata-writes (`create_metadata`, `modify_metadata`, `delete_metadata`) → addressed by **FQN** *(a)*; - debug / profiling tools → launch / application / breakpoint **IDs** + live session state *(a)*; - `validate_query` → error **line/col** *(b)*; - `list_configurations` → config **identities** *(a)*; - `clean_project`, `update_database` → destructive status whose JSON shape is consumed by e2e *(d-like)*. Markdown action tools (`revalidate_objects`, `export_configuration_to_xml`, `import_configuration_from_xml`, `write_module_source`) emit status + paths/counts only — no round-trip data. Build the body with `FrontMatter` + a markdown summary; any table goes through `MarkdownUtils` (escapes every cell); errors still via `ToolResult.error(...)`. ## Pagination Use the shared `Pagination` (`utils/Pagination.java`: one `limit`/`offset`, one truncation-notice format). Don't invent a per-tool scheme. ## Result / markdown assembly Through `ToolResult`/`JsonUtils` and the shared markdown-table builder, not a hand-rolled StringBuilder. ## Schema ↔ code ↔ README - `BuiltInToolRegistrar` is the source of truth for the tool set; the README catalog + the e2e golden (`tests/e2e/tools_list.golden.json`) must match it. A new tool changes the golden → regenerate (`EDT_MCP_UPDATE_GOLDEN=1`). - Every tool: a non-empty meaningful description and a description for every parameter. ## Class placement `tools/impl/` holds `IMcpTool` classes only. Utilities/abstract bases go in `utils/`/`tools/base/`. Project/model resolution goes through the shared helpers (skill `edt-mcp-architecture`). ru/en correctness — skill `edt-mcp-bilingual`.