MCP server for tsdevstack CLI - exposes tools and resources to AI agents for infrastructure management, deployment, and project state queries
This server exposes only 1 tool (add_bucket_storage) with a well-structured description but critical schema and parameter documentation gaps. The tool description is comprehensive and detailed (>600 chars), explaining what the tool does locally, cloud deployment, and usage patterns, exceeding the 50-200 char LLM-optimized range by a wide margin and likely causing token waste. The input schema declares a 'name' parameter with a string type and a description, but the schema lacks critical validation constraints: no minimum/maximum length enforcement, no regex pattern despite the description mentioning '2-30 chars, kebab-case', no enum for valid formats. The description itself ('Bucket logical name (kebab-case, 2-30 chars, e.g. "uploads", "media-assets"). Cloud name derived as {project}-{name}-{env}.') contains example values ('uploads', 'media-assets'), which violates the pattern:tool-description guidance, LLMs tend to reuse example values literally. No output schema is documented: the tool description mentions regenerating files and generating environment variables, but does not specify what the tool returns to the LLM. This forces the agent to guess what happened. The tool lacks error handling guidance: no indication of what happens if the bucket name is invalid, if the bucket already exists, or if file operations fail. No recovery paths are offered. The tool is a WRITE operation (marked as 'WRITE' risk), but the description does not explicitly state this is an irreversible action or suggest a dry-run/confirmation pattern. No tool annotations (idempotentHint, destructiveHint, readOnlyHint) are visible in the source code provided, despite toolAnnotations being marked 'true' in features. The server is STDIO-only (hard cap at 50), and this single tool's gaps prevent it from reaching even the low threshold.
Add an object storage bucket to the project. What it does locally: - Adds bucket to storage.buckets in config.json - Regenerates docker-compose.yml with MinIO (S3-compatible) container + minio-init job that auto-creates the bucket - Regenerates secrets with STORAGE_ENDPOINT, STORAGE_ACCESS_KEY, STORAGE_SECRET_KEY, STORAGE_BUCKET_{NAME} - First bucket also adds MinIO ports 9000 (API) + 9001 (web console) to docker-compose After running this, tell the user to: 1. Run `docker compose up -d` to start MinIO 2. Access MinIO console at http://localhost:9001 (minioadmin/minioadmin) To use in NestJS code: - Import StorageModule.forRoot({ buckets: ['bucket-name'] }) in app module - Inject with @InjectStorage('bucket-name') storage: StorageProvider - Or inject StorageService for multi-bucket access via storageService.getProvider('bucket-name') - StorageProvider interface: upload, download, downloadStream, delete, list, copy, getMetadata, getPresignedUrl, exists, getNativeClient Cloud deployment: - Run infra_deploy — Terraform creates the cloud bucket (S3 on AWS, GCS on GCP, Azure Blob container on Azure) - After terraform apply, STORAGE_BUCKET_* names are synced to the cloud secret manager (shared scope) - No separate STORAGE_PROVIDER env var needed — the storage adapter is derived from SECRETS_PROVIDER at runtime (local/aws→S3, gcp→GCS, azure→Azure Blob) - Azure also injects AZURE_STORAGE_ACCOUNT_NAME as an env var on Container Apps
Output schema not documented. Tool description mentions regenerating docker-compose.yml, secrets, and ports, but does not specify what the tool returns to the LLM. Agent cannot plan downstream actions without knowing the response structure.
Input parameter lacks formal validation constraints in schema. Description states 'kebab-case, 2-30 chars', but the JSON schema for 'name' parameter shows only type='string' with no minLength, maxLength, or pattern fields. LLMs cannot read constraint descriptions reliably, they depend on schema properties.
Tool description contains example values ('uploads', 'media-assets'). LLMs tend to reuse example values literally in subsequent calls, causing failures when those exact names are not valid in the user's context.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 49 | 2026-07-28+ | v2 |
| 2026-03-09 | D | 51 | - | v1 |
No error handling or recovery guidance. Description does not explain what happens if bucket name is invalid, already exists, or if file I/O fails. No actionable error messages or alternative paths provided.
Destructive operation not explicitly marked. Tool modifies config.json, docker-compose.yml, and secrets (irreversible side effects), but description does not use language like 'This creates...' or 'This modifies...'. No confirmation or dry-run pattern offered despite being a WRITE operation.
Tool description is 600+ characters, far exceeding the 50-200 char LLM-optimized range. Excessive detail wastes tokens and buries the core intent. Audience is an LLM planning tool usage, not a human reading comprehensive docs.
Tool annotations (destructiveHint, idempotentHint, readOnlyHint) are marked as supported in the server's feature flags, but no evidence they are applied to the tool definition in the source code provided. If annotations are not present, mark as false.