MCP server control plane and visualization platform with support for tool management, resource browsing, logging, and multi-server orchestration
mcpv exposes 4 tools via gRPC. Tool definitions are present in cmd/mcpvctl/tools.go but exhibit critical structural gaps: descriptions are generic and lack actionable context; parameter descriptions are minimal; input schemas lack type constraints (enums, ranges, patterns); output schemas are not documented; error handling provides no recovery guidance. The 'call' and 'call-task' tools accept JSON-as-string parameters (argumentsJson), which is a code smell, this violates the parameter clarity principle and forces LLMs to reason about nested JSON structure rather than working with typed parameters. Tool naming is functional but not verb-first idiomatic (e.g., 'list' and 'watch' lack object clarity, list what? watch what?). No evidence of pagination, per-tool result limits, or response shaping. The 'caller' parameter appears in all tools but its purpose and expected format are never documented. No security declarations (permissions, scopes, audit trails). This server would not pass production code review.
Call a tool
Call a tool asynchronously (task)
List tools
Watch tool snapshots
Generic tool names lack object context. 'list' does not indicate what is being listed (tools? resources? services?). Per naming guidance, should be 'list_tools', 'list_resources', etc. LLMs cannot infer intent from 'list' alone when multiple discovery tools may exist.
Descriptions are under 50 characters and provide no actionable context. 'List tools' and 'Watch tool snapshots' do not explain WHEN to use the tool, WHAT it returns, or WHY an agent would call it. Per pattern:tool-description, descriptions must be 10 - 1024 chars with clear usage guidance. These descriptions are too sparse.
Parameter 'argumentsJson' accepts JSON as a string. This forces LLMs to reason about nested JSON structure, violates parameter clarity (pattern:constrained-input), and is error-prone. Tool should accept typed parameters or at least document the expected JSON schema for argumentsJson. No schema or validation hints provided.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 28 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 27 | - | v1 |
The 'caller' parameter appears in all four tools but is never documented. What is a 'caller'? Is it a user ID, agent ID, session token? What format is expected? Per pattern:tool-description, every parameter must have a description. Undocumented parameters force LLMs to guess.
No output schema documentation. The 'list' tool returns '200' response body (per gRPC), but what structure does it contain? What fields should an agent expect? Per pattern:tool and mxe:strip-api-responses, response schemas must be documented so agents can extract relevant fields for downstream calls.
No error handling guidance. If 'call' fails (invalid tool name, routing error, timeout), what should the agent do? Retry? Call a different tool? Ask the user? Per pattern:recovery-guide, error responses must tell the LLM what to do next. Code contains no recovery hints or error classification.
No pagination or result limits declared. The 'list' tool likely returns all tools in one response. Per mxe:enforce-result-limits, responses should cap at 20 - 50 items and offer pagination cursors. Large unbound responses waste tokens and degrade LLM reasoning. No 'limit' or 'offset' parameters visible.
No security declarations. No evidence of permission gates (pattern:permission-gate), scope declarations (pattern:scope-declaration), or audit trails (pattern:audit-trail). Tools like 'call' can invoke arbitrary remote tools, what permissions does an agent need? How are sensitive calls logged?
'call-task' accepts 'ttlMs' and 'pollIntervalMs' parameters with no documented constraints. What are valid ranges? Can pollIntervalMs exceed ttlMs? Per review:param-validation-rules, parameters must document expected ranges and formats. Unbounded numeric params let LLMs pass absurd values.
Tool composition unclear. The 'list' tool returns available tools; 'call' invokes them. But does 'call' require the tool name exactly as returned by 'list'? Are IDs stable across calls? Per pattern:tool-chain, tool A's output must contain the exact identifiers tool B accepts. No documentation of this chain.