The Shipwright Build MCP server has 11 tools with verb-based names and basic descriptions, but exhibits significant quality gaps. Tools are registered via mcp.AddTool() in main.go with names and descriptions visible, but NO input schemas are defined in the registration code. The descriptions are present but brief (e.g., 'List Builds in a namespace with filtering options' = 56 chars). Parameter schemas are inferred from pkg/models/params.go structs but not explicitly exposed in tool definitions, the MCP spec requires input schemas to be declaratively registered with each tool. Without explicit schema registration, LLMs cannot discover parameter names, types, or constraints at runtime. Error handling is minimal (no recovery guidance, no categorization). Output schemas are undocumented. The server shows competent Kubernetes integration but fails to meet production-grade tool quality standards for agent-facing interfaces.
Tools (11)
create_buildwritesource verified32/100
Create a new Build resource
create_buildrunwritesource verified33/100
Create a new BuildRun resource (either from existing Build or inline)
delete_builddestructivesource verified32/100
Delete a Build resource
delete_buildrundestructivesource verified32/100
Delete a BuildRun resource
get_buildread onlysource verified35/100
Get a specific Build by name
get_buildrunread onlysource verified35/100
Get a specific BuildRun by name
list_buildrunsread onlysource verified35/100
List BuildRuns in a namespace with filtering options
NO input schemas registered with tools. Tools defined via mcp.AddTool(server, &mcp.Tool{Name, Description}, handler) lack InputSchema field. Parameter definitions exist in pkg/models/params.go structs but are NOT exposed to the MCP protocol. LLMs cannot discover parameter names, types, or constraints at runtime.
Tool descriptions are too brief (average ~55 chars). Examples: 'List Builds in a namespace with filtering options' (56 chars), 'Get a specific Build by name' (30 chars). Baseline A+ tools average 194 chars. Brief descriptions lack context for tool selection and do not state WHEN to use each tool vs. similar alternatives. Descriptions do not indicate if tools modify state (critical for agents planning side effects).
list_buildsget_buildcreate_builddelete_build
Recommendations
CRITICAL: Define InputSchema for each tool. Update mcp.Tool registration to include InputSchema with JSON Schema defining all parameters (namespace, prefix, label-selector, name, etc.) with type, description, required status, and enum constraints where applicable. Example: InputSchema must include {"type": "object", "properties": {"namespace": {"type": "string", "description": "Kubernetes namespace to query"}, ...}, "required": ["namespace"]}.
CRITICAL: Expand tool descriptions to 100-200 chars. State WHAT, WHEN, and CONSEQUENCES. Examples: 'List all Build resources in a Kubernetes namespace. Filters by name prefix or label selectors. Use this to discover available builds before creating a BuildRun. Returns name, status, and source info.' For destructive tools, explicitly state 'This DELETES the resource permanently.'
HIGH: Document output schemas in tool descriptions or separate docs. Describe what fields each tool returns (e.g., 'Returns: {name, namespace, status, source_type, output_image, created_at}'). This enables LLMs to extract needed data and plan follow-up calls.
HIGH: Add error recovery hints to descriptions. E.g., 'If build not found, call list_builds() with a prefix to find the correct name.' Implement structured error responses with 'code', 'message', and 'suggestedNextStep' fields.
HIGH: Implement confirmation step for delete_build and delete_buildrun. Require a confirm parameter (default false) or add a separate confirm_delete_build(name, namespace) tool. Alternatively, implement dry-run mode to preview deletions.
No output schemas documented. The source code provides no indication of what fields tools return (e.g., does list_builds return name, status, uid, annotations, or all of them?). LLMs cannot plan downstream tool calls or extract needed data without knowing response structure. Output documentation is required for agent reasoning.
No error handling guidance. Tools return results or errors with no recovery suggestions. An LLM receiving 'Build not found' has no hint to call list_builds() or search by prefix. Errors lack categorization (retryable vs. fatal). No constraint violation details (e.g., what made the input invalid?).
Destructive tools (delete_build, delete_buildrun) lack confirmation or dry-run support. Agents can irreversibly delete resources without a confirmation step or preview. No pattern::confirmation-request implementation. No dry-run parameter to let agents test before committing.
Parameter descriptions in code exist but are not surfaced in tool registration. Tools accept 'namespace', 'prefix', 'label-selector', etc., but the mcp.Tool struct does not include param documentation in the source visible to the protocol. Parameter descriptions must be part of the InputSchema.
Pagination not visible in tool definitions. list_* tools likely handle pagination internally, but tool specs do not declare limit, offset, or cursor parameters. LLMs cannot request specific page sizes or navigate large result sets. If a namespace contains 1000 builds, list_builds returns all or a server default with no way for the agent to control result volume.
'restart_buildrun' combines two concerns: fetch existing BuildRun + create a new one. Verb 'restart' is indirect; 'create_buildrun_from_existing' would be clearer. Tool naming should reflect the primary action; complexity should be internal.
restart_buildrun
HIGH: Surface parameter constraints. Add enum values for strategy-kind (e.g., ['BuildStrategy', 'ClusterBuildStrategy']), document required vs. optional params, and specify format for timeout (duration string like '10m', '3600s').
MEDIUM: Add pagination parameters to list_* tools. Include limit (1-100, default 20), offset/page, and return a total_count or next_cursor in responses. Document in tool description: 'Returns up to 20 results per call; use offset to paginate through large namespaces.'
MEDIUM: Rename restart_buildrun to create_buildrun_from_existing or clarify its semantics. If it fetches a BuildRun and creates a new one with the same spec, document this clearly. Consider whether restart is the right verb or if a more explicit name aids discoverability.
MEDIUM: Add input validation descriptions. For create_build, document that output-image must be a valid container image reference (e.g., 'myregistry.azurecr.io/myimage:tag'), timeout must be a Go duration string, and strategy must exist. Let LLMs know what to validate.
LOW: Consider tool annotations (readOnlyHint, destructiveHint, idempotentHint) in future MCP spec versions. Mark list_* and get_* tools as readOnlyHint=true, delete_* as destructiveHint=true, and create_buildrun as idempotentHint=false (since each call creates a new run). These hints guide agent caution.