From 1f108344de241d70ca56ef765057730f42c03162 Mon Sep 17 00:00:00 2001 From: Daniele Martinoli Date: Fri, 24 Oct 2025 22:17:39 +0200 Subject: [PATCH] MCP skills --- .claude/skills/deploy-mcp-server/SKILL.md | 499 ++++++++++++++++++ .claude/skills/manage-mcp-registries/SKILL.md | 435 +++++++++++++++ 2 files changed, 934 insertions(+) create mode 100644 .claude/skills/deploy-mcp-server/SKILL.md create mode 100644 .claude/skills/manage-mcp-registries/SKILL.md diff --git a/.claude/skills/deploy-mcp-server/SKILL.md b/.claude/skills/deploy-mcp-server/SKILL.md new file mode 100644 index 000000000..3a35f3887 --- /dev/null +++ b/.claude/skills/deploy-mcp-server/SKILL.md @@ -0,0 +1,499 @@ +--- +name: Deploy MCP Server to Kubernetes +description: Deploy an MCPServer to Kubernetes using configuration from a registry (Kubernetes or local CLI) (project) +--- + +# Deploy MCP Server to Kubernetes + +This skill helps you deploy an MCPServer custom resource to a Kubernetes cluster using server configuration retrieved from either a Kubernetes MCPRegistry or the local CLI registry. + +**Note:** For managing and querying MCPRegistry resources (listing registries, viewing available servers), use the **Manage MCP Registries** skill instead. + +## Instructions + +**IMPORTANT - Todo List Preparation:** + +Before executing any deployment steps, you MUST use the TodoWrite tool to create a comprehensive task list. This is critical for tracking the multi-step deployment process and ensuring no steps are skipped. + +Create a task list that includes ALL of these steps: +1. Gather required information (namespace, registry source) +2. Retrieve server configuration from registry +3. Process server configuration (transport, permissions, resources) +4. Handle ALL environment variables (MANDATORY - cannot be skipped) +5. Confirm resource settings +6. Generate and review YAML +7. Create secrets if needed +8. Deploy to Kubernetes +9. Verify deployment +10. Clean up (port-forwards, etc.) + +Mark each task as "in_progress" when you start it, and "completed" immediately when finished. This provides clear visibility to the user about deployment progress. + +Follow these steps to deploy an MCP server: + +**⚠️ IMPORTANT WORKFLOW REQUIREMENT ⚠️** + +When deploying an MCP server, you MUST complete ALL of the following steps in order: +1. Gather required information (namespace, registry source) +2. Retrieve server configuration from the registry +3. Process server configuration (transport, permissions, resources) +4. **Handle ALL environment variables** - THIS STEP IS MANDATORY and CANNOT be skipped +5. Confirm resource settings +6. Generate and review YAML +7. Deploy to Kubernetes +8. Verify deployment + +**The environment variable configuration step (Step 4) is REQUIRED for every deployment**, even if the user tries to skip it. You must explicitly walk through each environment variable with the user. + +### 1. Gather Required Information + +Ask the user for: +- **Server name**: The name of the MCP server to deploy (e.g., "fetch", "github") + - If the user is unsure, suggest using the **Manage MCP Registries** skill to list available servers +- **Namespace**: The Kubernetes namespace to deploy to (default: "toolhive-system") +- **Registry source**: Where to get the server configuration from: + - `kubernetes`: Use a Kubernetes MCPRegistry resource + - `local`: Use the local CLI registry (`thv registry info`) + +If using Kubernetes registry: +- **Registry namespace**: The namespace where the MCPRegistry is located (if different from deployment namespace) +- **Registry name**: The name of the MCPRegistry resource (if user knows it) + - If unsure, use the **Manage MCP Registries** skill to list available registries + +### 2. Retrieve Server Configuration + +#### Option A: Local CLI Registry + +Use `thv registry info --format json` to get the server configuration. + +Example: +```bash +thv registry info fetch --format json +``` + +This returns JSON with fields like: +- `image`: Container image to use +- `transport`: Transport protocol (stdio, streamable-http, sse) +- `permissions`: Network and file permissions +- `env_vars`: Required and optional environment variables +- `port`: Default port (if applicable) + +#### Option B: Kubernetes Registry + +1. Get the registry name and namespace from the user, or use the **Manage MCP Registries** skill to help them select one + +2. Extract the API endpoint from the MCPRegistry status: + ```bash + kubectl get mcpregistry -n -o jsonpath='{.status.apiStatus.endpoint}' + ``` + + The endpoint will be an in-cluster Service URL like: `http://thv-git-api.toolhive-system:8080` + +3. **Set up port-forward to access the registry API**: + + Extract the service name and port from the endpoint, then create port-forward: + ```bash + kubectl port-forward -n svc/ : + ``` + + Example: + ```bash + kubectl port-forward -n toolhive-system svc/thv-git-api 8080:8080 & + ``` + +4. **Query specific server configuration**: + ```bash + curl -s http://localhost:/v0/servers/ + ``` + + This returns the complete server configuration needed for deployment. + +5. Clean up the port-forward when deployment is complete: + ```bash + # Find and kill the port-forward process + ps aux | grep "kubectl port-forward" + kill + ``` + +### 3. Process Server Configuration + +Extract the necessary fields from the registry data: +- `image`: Required +- `transport`: Default to "stdio" if not specified +- `port`: Only include if transport is "streamable-http" or "sse" +- `targetPort`: Only if different from port +- `args`: Command-line arguments to pass to the container (if specified in registry) +- `env`: Environment variables (ask user for values of required vars) +- `resources`: Resource limits/requests (provide sensible defaults: 100m CPU, 128Mi memory) +- `permissions`: Convert to `permissionProfile` if network permissions are specified + +**IMPORTANT:** If the server configuration includes an `args` field, you MUST include it in the MCPServer spec. Many servers require specific command-line arguments to start properly (e.g., `["http"]` for HTTP mode, `["stdio"]` for stdio mode). Omitting required args will cause the container to fail or show help text instead of starting. + +#### 3.1 Handle stdio Transport - ProxyMode Selection + +If the transport is "stdio", ALWAYS ask the user to select the proxy mode: + +``` +The server uses 'stdio' transport, which requires a proxy for HTTP access. + +Select proxy mode: +A) sse (Server-Sent Events) - Default, recommended for most use cases +B) streamable-http (Streamable HTTP) - Alternative streaming protocol + +Your choice (A or B): +``` + +Valid options according to MCPServer CRD: +- `sse` (default) +- `streamable-http` + +Set the `proxyMode` field in the spec accordingly. If transport is not "stdio", do NOT include proxyMode in the spec. + +### 4. Handle Environment Variables + +**⚠️ CRITICAL - THIS STEP CANNOT BE SKIPPED ⚠️** + +MANDATORY RULES: +1. **EVERY** environment variable from the registry configuration MUST be addressed +2. For EACH variable, the user MUST: + - Provide a value (custom or accept default), OR + - Explicitly skip it by typing 'skip' (ONLY if optional AND not required) +3. **NEVER** skip this step or assume default values without user confirmation +4. **NEVER** proceed with deployment if required variables are missing values +5. **ALWAYS** confirm all environment variable values with the user before generating YAML +6. If there are NO environment variables in the configuration, explicitly state this to the user + +**Important:** When prompting for optional values, always instruct users to type 'skip' if they want to skip the variable. Do NOT use "press Enter to skip" as empty responses don't work in chat interfaces. + +**Why this step cannot be skipped:** +- MCP servers often require specific configuration to function correctly +- Using wrong or missing values can cause deployment failures or security issues +- Users must understand what each variable does and consciously choose values + +#### 4.1 Secret Management Strategy + +First, check if there are any environment variables marked as `secret: true` in the registry configuration. + +If secret variables exist, ask the user: +``` +This server has secret/sensitive environment variable(s): + +Would you like to: +A) Create a new Kubernetes Secret to store these values +B) Use an existing Kubernetes Secret (you'll provide the secret name and keys) +C) Store values directly in the manifest (⚠️ NOT RECOMMENDED - secrets will be visible in plain text) + +Your choice (A/B/C): +``` + +Based on the user's choice: + +**Option A - Create New Secret:** +1. Generate secret name: `-secrets` +2. For each secret variable: + - Prompt: "**** ( - optional/required):\nEnter value (or type 'skip' to skip if optional):" + - If user provides a value: Collect it securely + - If user types 'skip' and variable is optional: Skip this secret variable + - If user types 'skip' and variable is required: Inform them it's required and re-prompt + - Map to secret key (lowercase env var name) +3. Create the Kubernetes Secret BEFORE deploying MCPServer: + ```bash + kubectl create secret generic -secrets \ + -n \ + --from-literal== \ + --from-literal== + ``` +4. Verify secret creation: `kubectl get secret -n ` +5. Reference in MCPServer spec using `secrets` field + +**Option B - Use Existing Secret:** +1. Ask: "What is the name of the existing Secret?" +2. Verify the secret exists: `kubectl get secret -n ` +3. For each secret variable: + - Ask: "Which key in Secret '' contains ?" + - Validate the key exists: `kubectl get secret -n -o jsonpath='{.data.}'` +4. Use `secrets` field in MCPServer spec with user-provided mappings + +**Option C - Store Inline (Discouraged):** +1. ⚠️ Warn the user: "WARNING: Secret values will be stored in plain text in the MCPServer manifest. This is NOT recommended for production use." +2. Ask for confirmation: "Are you sure you want to proceed? (yes/no)" +3. If confirmed, collect values and store in `env` field +4. If not confirmed, return to secret strategy selection + +#### 4.2 Present All Environment Variables + +CRITICAL: ALL environment variables from the registry MUST be addressed. Follow this workflow: + +**Step 1 - Categorize Variables:** +Separate environment variables into: +- Required non-secret variables +- Required secret variables +- Optional non-secret variables +- Optional secret variables + +**Step 2 - Present Complete List:** +Show ALL variables to the user in a clear, organized format: + +``` +The server has the following environment variables: + +REQUIRED (plain text): +1. + Description: + Default: [if any] + +2. + Description: + Default: [if any] + +REQUIRED (secrets - will be handled separately): +3. + Description: + +OPTIONAL (plain text): +4. + Description: + Default: [if any] + +OPTIONAL (secrets - will be handled separately): +5. + Description: + Default: [if any] +``` + +**Step 3 - Collect Non-Secret Variable Values:** +For each non-secret variable (required and optional): + +If variable has a default value: +``` +: "" +Use default? (yes/no, or enter custom value): +``` +- If "yes": Use default value +- If "no": Prompt for custom value +- If custom value provided: Use that value +- If empty and optional: Mark as skipped +- If empty and required: Re-prompt (cannot be empty) + +If variable has NO default value: +``` +: +Enter value (or type 'skip' to skip if optional) [required/optional]: +``` +- If value provided: Use that value +- If user types 'skip' and variable is optional: Skip the variable +- If user types 'skip' and variable is required: Inform them it's required and re-prompt +- If empty response and required: Re-prompt until value provided + +**Step 4 - Collect Secret Variable Values:** +Handle secret variables according to the strategy chosen in 4.1: +- If option A or C: Prompt for each secret value directly +- If option B: Verify the values exist in the referenced secret + +**Step 5 - Confirm All Values:** +Before generating YAML, show a complete summary: +``` +Environment variable summary: + +Plain text variables: + : + : + +Secret variables (stored in Secret ''): + : ****** (from secret key: ) + : ****** (from secret key: ) + +Skipped optional variables: + + +Proceed with deployment? (yes/no): +``` + +If user says "no", allow them to modify any values. + +#### 4.3 Default Value Handling + +When the registry provides a default value for a variable: +1. ALWAYS show it to the user +2. ALWAYS ask if they want to use it or provide a custom value +3. NEVER silently use defaults without user awareness +4. For optional variables with defaults, offer to skip (which means NOT setting the variable at all) + +Example for variable with default: +``` +CB_MCP_READ_ONLY_QUERY_MODE (optional): + Description: Prevent data modification queries + Default: "true" + +Your choice: + A) Use default value ("true") + B) Enter custom value + C) Skip this variable (don't set it) + +Choice (A/B/C): +``` + +### 5. Confirm Resource Settings + +ALWAYS ask the user to confirm or customize resource settings before generating the YAML. + +Default resource settings: +``` +Resources: + Limits: + CPU: 100m (0.1 CPU cores) + Memory: 128Mi + Requests: + CPU: 50m (0.05 CPU cores) + Memory: 64Mi +``` + +Prompt the user: +``` +The following default resource settings will be applied: + +Limits: + - CPU: 100m + - Memory: 128Mi + +Requests: + - CPU: 50m + - Memory: 64Mi + +Would you like to: +A) Use these default settings +B) Customize resource limits/requests + +Your choice (A or B): +``` + +If user chooses B (customize): +- Ask for custom CPU limit (e.g., "200m", "0.5", "1") +- Ask for custom Memory limit (e.g., "256Mi", "512Mi", "1Gi") +- Ask for custom CPU request (should be ≤ limit) +- Ask for custom Memory request (should be ≤ limit) + +Validate that requests are not greater than limits. + +### 6. Generate MCPServer YAML + +Create an MCPServer resource with the following structure: + +```yaml +apiVersion: toolhive.stacklok.dev/v1alpha1 +kind: MCPServer +metadata: + name: + namespace: +spec: + image: + transport: + proxyMode: # Only for stdio transport (sse or streamable-http) + port: # Only for streamable-http/sse transport, or stdio with proxy + targetPort: # Only if different from port + args: # Only if specified in registry configuration + - + - + resources: + limits: + cpu: "" + memory: "" + requests: + cpu: "" + memory: "" + env: # For non-sensitive vars + - name: + value: + secrets: # For sensitive vars stored in secrets + - name: + key: + targetEnvName: + permissionProfile: # Only if network permissions needed + type: builtin + name: network +``` + +#### 6.1 Create Kubernetes Secret (if option A was chosen in step 4.1) + +If user chose to create a new secret, create it before applying the MCPServer: + +```bash +kubectl create secret generic -secrets \ + -n \ + --from-literal== \ + --from-literal== +``` + +Verify the secret was created: +```bash +kubectl get secret -secrets -n +``` + +### 7. Deploy to Kubernetes + +1. Show the user the generated YAML for review +2. Ask for confirmation to proceed +3. Apply the MCPServer resource: + ```bash + kubectl apply -f - < + EOF + ``` +4. Wait for the associated pod to become ready: + ```bash + kubectl wait --for=condition=Ready pod -l app.kubernetes.io/name= -n --timeout=60s + ``` +5. Show the deployment status: + ```bash + kubectl get mcpserver -n + kubectl get pods -n -l app.kubernetes.io/name= + ``` + +### 8. Verify Deployment + +Check the MCPServer and Pod status: +```bash +# Check MCPServer resource +kubectl get mcpserver -n -o yaml + +# Check Pod status (MCPServers do not expose a Ready condition, check the Pod instead) +kubectl get pods -n -l app.kubernetes.io/name= +``` + +Look for in the MCPServer: +- `status.phase`: Should be "Running" +- `status.url`: The URL where the server is accessible + +Look for in the Pod: +- `status.phase`: Should be "Running" +- `status.conditions`: The Ready condition should be "True" + +If there are issues: +1. Check pod status: `kubectl get pods -n -l app.kubernetes.io/name=` +2. Check pod logs: `kubectl logs -n -l app.kubernetes.io/name=` +3. Describe the pod: `kubectl describe pod -n -l app.kubernetes.io/name=` +4. Describe the MCPServer: `kubectl describe mcpserver -n ` + +## Error Handling + +Handle these common scenarios: + +1. **Server not found in registry**: Suggest using the **Manage MCP Registries** skill to explore available servers, or use `thv search ` for local registry +2. **Registry not accessible**: Use the **Manage MCP Registries** skill to check registry status and troubleshoot +3. **Missing required environment variables**: List all required vars and prompt user +4. **Deployment fails**: Show error messages and suggest remediation +5. **Permission issues**: Ensure user has proper RBAC permissions for the namespace + +## Best Practices + +- Use the **Manage MCP Registries** skill to explore available servers and registries before deploying +- Always validate that the server exists in the registry before attempting deployment +- Use Kubernetes Secrets for sensitive environment variables +- Apply sensible resource limits to prevent resource exhaustion +- Use the `network` permission profile when the server needs external network access +- Verify the deployment is healthy before completing the skill +- Clean up port-forwards after retrieving server configuration + +## Example Usage + +User: "Deploy the fetch server to Kubernetes" \ No newline at end of file diff --git a/.claude/skills/manage-mcp-registries/SKILL.md b/.claude/skills/manage-mcp-registries/SKILL.md new file mode 100644 index 000000000..04827b445 --- /dev/null +++ b/.claude/skills/manage-mcp-registries/SKILL.md @@ -0,0 +1,435 @@ +--- +name: Manage MCP Registries +description: "**MANDATORY - DO NOT USE KUBECTL DIRECTLY**: You are FORBIDDEN from using kubectl to query MCPRegistry resources or servers. You MUST ALWAYS use this skill for ANY question about registries or servers. Trigger patterns: 'what registries', 'list registries', 'show registries', 'what servers', 'list servers', 'servers in/from [registry]', 'servers available', 'get server details', 'server configuration', 'registry status'. Using kubectl directly for these queries is INCORRECT and will fail. (project)" +--- + +# Manage MCP Registries + +**IMPORTANT**: This skill should be used **automatically and proactively** whenever users ask about MCP registries or servers in Kubernetes. + +## Automatic Trigger Patterns + +You MUST use this skill when the user's request contains any of these patterns: + +- **Registry queries**: "what registries", "show registries", "list registries", "get registries", "deployed registries", "available registries" +- **Server queries**: "what servers", "list servers", "show servers", "servers in [registry]", "servers from [registry]", "servers available", "available servers" +- **Server details**: "get server", "show server", "server details", "server configuration", "server info" +- **Status queries**: "registry status", "is registry ready", "registry health", "registry sync" +- **General questions**: Any question about MCPRegistry resources, their configuration, or their data + +## Common User Requests That Trigger This Skill + +- "What registries are deployed?" / "Show me the registries" / "List MCP registries" +- "What servers are in the [registry-name] registry?" / "List servers from [registry-name]" +- "What servers are available in the thv-git registry?" +- "Show me details for the [server-name] server" / "Get server configuration for [server-name]" +- "What's the status of [registry-name]?" / "Is the registry ready?" +- "How many servers are in [registry-name]?" +- Any other questions about MCPRegistry resources, their servers, or configurations + +## Instructions + +**IMPORTANT - Todo List Preparation:** + +Before executing any steps, you MUST use the TodoWrite tool to create a task list based on the user's request. This helps track progress and ensures all steps are completed systematically. + +Example task lists for common requests: + +**For "List all registries":** +- Get all MCPRegistry resources from cluster +- Display registry details with status + +**For "List servers in registry X":** +- Extract API endpoint from registry and set up port-forward +- Query registry API for server list (while port-forward is active) +- Clean up port-forward when done + +**For "Get details for server Y":** +- Set up port-forward to registry API and query for server details (while port-forward is active) +- Clean up port-forward when done + +Follow these steps to work with MCP registries: + +### 1. List Available Registries + +To see all MCPRegistry resources in the cluster: + +```bash +# List registries in all namespaces +kubectl get mcpregistries -A + +# List registries in a specific namespace +kubectl get mcpregistries -n + +# Get detailed output with additional columns +kubectl get mcpregistries -A -o wide +``` + +The output shows: +- **NAME**: Registry name +- **PHASE**: Current status (Ready, Syncing, Error) +- **SYNC**: Sync status (Complete, InProgress, Failed) +- **API**: API server status (Ready, NotReady) +- **SERVERS**: Number of servers in the registry +- **LAST SYNC**: When the registry was last synchronized +- **AGE**: How long the registry has been running + +### 2. Get Registry Details + +To view detailed information about a specific registry: + +```bash +kubectl get mcpregistry -n -o yaml +``` + +Key fields to examine: +- **spec.source**: Where the registry data comes from (git, configmap, etc.) +- **spec.syncPolicy**: How often the registry syncs +- **status.apiStatus.endpoint**: The API server endpoint URL +- **status.syncStatus**: Last sync time and server count +- **status.storageRef**: Where the registry data is stored + +Example examining a specific registry: +```bash +# Get just the API endpoint +kubectl get mcpregistry thv-git -n toolhive-system -o jsonpath='{.status.apiStatus.endpoint}' + +# Get server count +kubectl get mcpregistry thv-git -n toolhive-system -o jsonpath='{.status.syncStatus.serverCount}' + +# Get last sync time +kubectl get mcpregistry thv-git -n toolhive-system -o jsonpath='{.status.syncStatus.lastSyncTime}' +``` + +### 3. List Servers in a Registry + +**IMPORTANT**: When listing servers from a registry, you MUST use the port-forwarding approach to access the registry API. This is the ONLY recommended method for querying server lists. + +**CRITICAL WORKFLOW**: Port-forwarding runs in the background and must stay active while you query the API. Do NOT wait between setting up port-forward and querying - execute them as one continuous workflow: +1. Start port-forward in background +2. Wait 2 seconds for it to be ready +3. Immediately query the API (port-forward stays running) +4. Only kill port-forward after all queries are complete + +To query servers available in a registry, you need to access the registry's API server via port-forwarding. + +#### Step 1: Set Up Port-Forward to Registry API + +**Port-forwarding is REQUIRED** for reliably accessing the registry API and listing servers. + +Extract the service information from the registry: +```bash +# Get the API endpoint (e.g., http://thv-git-api.toolhive-system:8080) +kubectl get mcpregistry -n -o jsonpath='{.status.apiStatus.endpoint}' +``` + +The endpoint format is: `http://.:` + +Set up port-forward: +```bash +kubectl port-forward -n svc/ : +``` + +Example: +```bash +# For endpoint http://thv-git-api.toolhive-system:8080 +kubectl port-forward -n toolhive-system svc/thv-git-api 8080:8080 +``` + +You can run this in the background: +```bash +kubectl port-forward -n toolhive-system svc/thv-git-api 8080:8080 & +``` + +#### Step 2: Query the Registry API + +Once port-forwarding is active, you can query the API at `http://localhost:`. + +**List all server names:** +```bash +curl -s http://localhost:8080/v0/servers | jq '.servers[] | .name' | sort +``` + +**List all servers with full details:** +```bash +curl -s http://localhost:8080/v0/servers | jq '.servers[]' +``` + +**Get a specific server's configuration:** +```bash +curl -s http://localhost:8080/v0/servers/ | jq '.' +``` + +**Count total servers:** +```bash +curl -s http://localhost:8080/v0/servers | jq '.servers | length' +``` + +**Search for servers by name pattern:** +```bash +# Find servers containing "aws" in the name +curl -s http://localhost:8080/v0/servers | jq '.servers[] | select(.name | contains("aws")) | .name' +``` + +**Filter servers by transport type:** +```bash +# Find all servers using stdio transport +curl -s http://localhost:8080/v0/servers | jq '.servers[] | select(.transport == "stdio") | .name' +``` + +**List servers with their images:** +```bash +curl -s http://localhost:8080/v0/servers | jq '.servers[] | {name: .name, image: .image}' +``` + +#### Step 3: Clean Up Port-Forward + +When done querying the API, stop the port-forward: + +```bash +# Find the port-forward process +ps aux | grep "kubectl port-forward" + +# Kill it (or use Ctrl+C if running in foreground) +kill +``` + +Or if you know the background job number: +```bash +# List background jobs +jobs + +# Kill the job +kill % +``` + +### 4. Check Registry Storage + +Registries store their server data in ConfigMaps or other storage. To view the raw data: + +```bash +# Get the storage reference +kubectl get mcpregistry -n -o jsonpath='{.status.storageRef}' + +# If it's a ConfigMap, view it +kubectl get configmap -n -o yaml +``` + +Example: +```bash +# For thv-git registry using ConfigMap storage +kubectl get mcpregistry thv-git -n toolhive-system -o jsonpath='{.status.storageRef.configMapRef.name}' + +# View the ConfigMap +kubectl get configmap thv-git-registry-storage -n toolhive-system -o yaml +``` + +### 5. Monitor Registry Sync Status + +To watch registry synchronization: + +```bash +# Watch registry status updates +kubectl get mcpregistries -n --watch + +# Check sync conditions +kubectl get mcpregistry -n -o jsonpath='{.status.conditions}' + +# View last sync details +kubectl get mcpregistry -n -o jsonpath='{.status.syncStatus}' +``` + +### 6. Trigger Manual Registry Sync + +To force a registry to re-sync its data: + +```bash +kubectl annotate mcpregistry -n \ + toolhive.stacklok.dev/sync-trigger="$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)" \ + --overwrite +``` + +Then monitor the sync status: +```bash +kubectl get mcpregistry -n -o jsonpath='{.status.syncStatus}' +``` + +## Common Workflows + +### Workflow 1: Explore All Registries and Their Servers + +```bash +# 1. List all registries +kubectl get mcpregistries -A + +# 2. For each registry, get API endpoint +kubectl get mcpregistry -n -o jsonpath='{.status.apiStatus.endpoint}' + +# 3. Set up port-forward +kubectl port-forward -n svc/ 8080:8080 & + +# 4. List servers +curl -s http://localhost:8080/v0/servers | jq '.servers[] | .name' + +# 5. Clean up +kill %1 +``` + +### Workflow 2: Find a Specific Server Across Registries + +```bash +# 1. List all registries +REGISTRIES=$(kubectl get mcpregistries -A -o json | jq -r '.items[] | "\(.metadata.name):\(.metadata.namespace)"') + +# 2. For each registry, search for server +for reg in $REGISTRIES; do + NAME=$(echo $reg | cut -d: -f1) + NS=$(echo $reg | cut -d: -f2) + + # Get API endpoint + ENDPOINT=$(kubectl get mcpregistry $NAME -n $NS -o jsonpath='{.status.apiStatus.endpoint}') + echo "Checking registry: $NAME in namespace: $NS" + + # Set up port-forward and query + # (See step 3 for full port-forward setup) +done +``` + +### Workflow 3: Compare Server Versions Across Registries + +```bash +# After setting up port-forwards for multiple registries: +# Registry 1 (port 8080) +curl -s http://localhost:8080/v0/servers/ | jq '{name: .name, image: .image}' + +# Registry 2 (port 8081) +curl -s http://localhost:8081/v0/servers/ | jq '{name: .name, image: .image}' +``` + +## Registry API Reference + +The registry API provides the following endpoints: + +- `GET /v0/servers` - List all servers + - Returns: `{"servers": [...]}` + +- `GET /v0/servers/` - Get specific server details + - Returns: Server configuration JSON + +- `GET /health` - Health check endpoint + - Returns: Health status + +Response format for server data: +```json +{ + "name": "server-name", + "image": "ghcr.io/owner/repo:tag", + "transport": "stdio", + "port": 8080, + "args": ["arg1", "arg2"], + "env_vars": [ + { + "name": "VAR_NAME", + "description": "Variable description", + "required": true, + "secret": false, + "default": "default-value" + } + ], + "permissions": { + "network": { + "enabled": true + } + } +} +``` + +## Troubleshooting + +### Registry Not Ready + +If a registry shows `Phase: Error` or `API: NotReady`: + +```bash +# Check registry conditions +kubectl get mcpregistry -n -o jsonpath='{.status.conditions}' + +# Check registry API pod logs +kubectl logs -n -l app.kubernetes.io/name=-api + +# Describe the registry for events +kubectl describe mcpregistry -n +``` + +### Port-Forward Fails + +If port-forwarding doesn't work: + +```bash +# Verify service exists +kubectl get svc -n | grep + +# Check if port is already in use +lsof -i : + +# Try a different local port +kubectl port-forward -n svc/ 8081:8080 +``` + +### Empty Server List + +If API returns no servers or empty list: + +```bash +# Check sync status +kubectl get mcpregistry -n -o jsonpath='{.status.syncStatus}' + +# Trigger manual sync +kubectl annotate mcpregistry -n \ + toolhive.stacklok.dev/sync-trigger="$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ)" --overwrite + +# Wait and check again +sleep 10 +kubectl get mcpregistry -n -o jsonpath='{.status.syncStatus.serverCount}' +``` + +## Best Practices + +1. **ALWAYS use port-forwarding** for listing servers and accessing the registry API - this is the ONLY recommended approach +2. **NEVER attempt to access registry storage directly** (e.g., ConfigMaps) for listing servers - always use the API via port-forward +3. **Clean up port-forwards** when done to free resources +4. **Use jq for JSON parsing** to extract specific information from API responses +5. **Monitor sync status** before querying to ensure data is up-to-date +6. **Check multiple registries** when searching for a server - it may exist in different registries with different configurations +7. **Use the API for automation** - the registry API is designed for programmatic access + +## Example Usage + +**User:** "Show me all registries in the cluster" + +**Assistant:** +```bash +kubectl get mcpregistries -A +``` + +**User:** "What servers are available in the thv-git registry?" + +**Assistant:** +```bash +# Set up port-forward in background, wait briefly, then query immediately +kubectl port-forward -n toolhive-system svc/thv-git-api 8080:8080 & +sleep 2 && curl -s http://localhost:8080/v0/servers | jq '.servers[] | .name' | sort + +# After query completes, clean up +kill %1 +``` + +**Note:** The workflow is: start port-forward → wait 2 seconds → query API → cleanup. Do NOT treat these as separate tasks that need individual completion tracking. + +**User:** "Get details for the 'github' server from the thv-git registry" + +**Assistant:** +```bash +# Assuming port-forward is already set up +curl -s http://localhost:8080/v0/servers/github | jq '.' +```