Static source inference · medium confidence · evidence: Streamable HTTP
Current-spec patterns detected
Summary
The server demonstrates acceptable tool definitions with consistent structure across 12 tools spanning Jira, ServiceNow, Slack, and StatusPage integrations. All tools have descriptions (10-50 chars, mostly short) and JSON Schema input definitions with typed parameters. However, descriptions are uniformly terse (far below the 194-char baseline from production tools), lacking actionable context for LLM selection. Parameter descriptions exist but are minimal (18-35 chars vs. 72-char baseline). Output schemas are NOT documented in the tool definitions, responses are inferred from response struct types but not declared in the tool registration. Error handling is absent from visible code (no recovery guidance, categorization, or validation). No parameter enums are used despite multiple tools accepting constrained values (issue types, risk levels, maintenance windows). Tools follow clean verb_noun naming (issue_create, slack_post, change_update) but lack composition patterns: no tool accepts pagination, no documented output structures guide chaining, and responses lack downstream IDs needed for multi-step workflows.
Descriptions are critically short (10-50 chars vs. 194-char baseline). Tools like 'issue_list' (23 chars) and 'slack_list_channels' (24 chars) lack context for LLM selection, they do not explain WHEN to use the tool, what it returns, or how it differs from related tools.
No output schemas documented. Tool definitions register input schemas but do not declare the structure of responses (e.g., issue_create returns IssueCreateResponse with 'issue_id' and 'url', but this is not visible in the tool registration). LLMs cannot plan downstream calls or extract fields without documented response schemas.
Expand tool descriptions to 80 - 150 characters. Current descriptions (10 - 50 chars) lack context. Example for 'issue_create': 'Create a new Jira issue (Epic, Task, or Sub-task). Returns issue_id and URL. Use when you need to track new work; if you're updating an existing issue, use issue_update instead.' This clarifies intent and distinguishes from related tools.
Document output schemas in the tool registration. For 'issue_create', add a 'returns' field or schema block showing: {type: 'object', properties: {issue_id: {type: 'string'}, url: {type: 'string'}}, required: ['issue_id', 'url']}. This enables LLMs to plan downstream calls (e.g., pass issue_id to issue_update).
Convert free-form string parameters to enums. For 'type' (issue_create, issue_update), declare enum: ['Epic', 'Task', 'Sub-task']. For 'risk' (change_create, change_update), enum: ['Low', 'Medium', 'High']. Enums are machine-parseable and prevent hallucinated values.
Enhance parameter descriptions with format and value guidance. For 'channel' (slack_post, slack_recent_messages), clarify: 'Slack channel name or ID. Accepts: #project, C12345, or project (will resolve to channel). Required.' For 'assignee', specify: 'Username or email (e.g., jane.doe or jane.doe@example.com). Must exist in Jira or call search_users() first.'
Add pagination to list endpoints. 'issue_list', 'change_list', 'slack_list_channels', and 'statuspage_list' should accept limit (default 20, max 100) and offset or cursor parameters. Return a total_count and next_offset. Add to descriptions: 'Returns up to 20 results. Use offset for pagination to handle large datasets.'
Parameter descriptions are minimal (18-35 chars). Descriptions like 'Slack channel to post to' (26 chars) lack guidance on format expectations. For example, 'channel' parameter does not clarify whether it accepts '#project' or 'C12345' or 'project' (human-readable name vs. opaque ID). This forces LLMs to guess.
No enums used for constrained parameters. 'type' in issue_create accepts 'Epic, Task, Sub-task' but is defined as free-form string. 'risk' in change_create accepts 'Low, Medium, High' but lacks enum constraint. Free-form strings invite hallucinated values; LLMs cannot validate against examples in descriptions alone.
No error handling guidance visible in tool definitions. Code shows in-memory mock data but no error responses, validation, or recovery guidance. An LLM cannot know if a failure is retryable, user-fixable, or fatal. For example, assigning a nonexistent user should return actionable guidance, not a generic error.
Pagination absent. 'issue_list', 'change_list', and 'slack_list_channels' have no limit, offset, page_size, or cursor parameters. If the in-memory store grows to thousands of items (or real API backing returns large datasets), responses will blow the context window. No cap or pagination mechanism is visible.
Response chaining not optimized. For example, if an agent calls 'issue_create' and later needs to call 'issue_update', the create response must return an 'issue_id' field that update can accept. While the code defines IssueCreateResponse with 'issue_id', it is not documented in the tool schema, so LLMs cannot know the field name exists.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). The MCP spec (2026-07-28) supports tool annotations to flag write operations, deletions, and idempotent calls. Tools like 'issue_update' and 'slack_post' modify state but lack destructiveHint/readOnlyHint to guide agent behavior. Agents cannot distinguish safe reads from risky writes without additional metadata.
Implement error recovery guidance. When a tool fails (e.g., invalid assignee), return structured error: {error: 'user_not_found', message: 'Assignee jane.smith not found. Try search_users(query="jane") to find valid usernames.', recoverable: true}. This guides agent self-correction.
Add tool annotations. For destructive tools (none visible, but 'issue_update' and 'change_update' modify state), add destructiveHint: true. For read-only tools ('issue_list', 'slack_list_channels'), add readOnlyHint: true. This signals agent behavior without additional schema complexity.
Clarify ID vs. name parameters. For 'issue_id' (issue_update), specify: 'Jira issue ID, e.g., JIRA-1001 or JIRA-1234. If you only have a summary or description, call issue_list() and search by keyword.' For 'channel' (slack), accept both human-readable names and system IDs to match user intent ('Send to #project' vs. 'Send to C12345').
Add parameter constraints in descriptions. For 'summary' and 'description' (issue_create), specify: 'summary: required, 1 - 200 characters. description: required, 10 - 5000 characters.' For 'window' (change_create), clarify format: 'ISO 8601 duration or timestamp range, e.g., 2024-01-15T14:00:00Z to 2024-01-15T16:00:00Z.'
Document idempotence guarantees. If create_issue is idempotent (calling twice with the same parameters returns the same issue_id without duplicating), state: 'Idempotent: calling twice with identical inputs will return the same issue_id without creating a duplicate.' This enables confident retry behavior.