Files
ai-stack-deployer/docs/MCP_SERVER_GUIDE.md
Oussama Douhou 19845880e3 fix(ci): trigger workflow on main branch to enable :latest tag
Changes:
- Create Gitea workflow for ai-stack-deployer
- Trigger on main branch (default branch)
- Use oussamadouhou + REGISTRY_TOKEN for authentication
- Build from ./Dockerfile

This enables :latest tag creation via {{is_default_branch}}.

Tags created:
- git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:latest
- git.app.flexinit.nl/oussamadouhou/ai-stack-deployer:<sha>

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 23:33:39 +01:00

12 KiB

AI Stack Deployer - MCP Server Guide

Overview

This project now includes a Model Context Protocol (MCP) Server that exposes deployment functionality to Claude Code and other MCP-compatible clients.

What is MCP?

The Model Context Protocol is a standardized way for AI assistants to interact with external tools and services. By implementing an MCP server, this project allows Claude Code to:

  • Deploy new AI stacks programmatically
  • Check deployment status
  • Verify name availability
  • Test API connections
  • List all deployments

Architecture

┌──────────────────────────────────────────────────────────────┐
│                 CLAUDE CODE (MCP Client)                      │
│  - Discovers available tools                                  │
│  - Calls tools with parameters                                │
│  - Receives structured responses                              │
└────────────────────────┬─────────────────────────────────────┘
                         │
                         │ MCP Protocol (stdio)
                         │
┌────────────────────────▼─────────────────────────────────────┐
│          AI Stack Deployer MCP Server                         │
│          (src/mcp-server.ts)                                  │
│                                                               │
│  Available Tools:                                             │
│  ✓ deploy_stack                                               │
│  ✓ check_deployment_status                                    │
│  ✓ list_deployments                                           │
│  ✓ check_name_availability                                    │
│  ✓ test_api_connections                                       │
└────────────────────────┬─────────────────────────────────────┘
                         │
                         │ Uses existing API clients
                         │
┌────────────────────────▼─────────────────────────────────────┐
│         Existing Infrastructure                               │
│  - Hetzner DNS API (src/api/hetzner.ts)                       │
│  - Dokploy API (src/api/dokploy.ts)                           │
└───────────────────────────────────────────────────────────────┘

What Was Created

1. MCP Server Implementation (src/mcp-server.ts)

A fully-functional MCP server that:

  • Integrates with existing Hetzner and Dokploy API clients
  • Validates stack names according to project rules
  • Tracks deployment state in memory
  • Handles errors gracefully
  • Returns structured JSON responses

2. Project Configuration (.mcp.json)

{
  "mcpServers": {
    "ai-stack-deployer": {
      "command": "bun",
      "args": ["run", "src/mcp-server.ts"],
      "env": {}
    }
  }
}

This file tells Claude Code how to start the MCP server.

3. Package Script (package.json)

Added "mcp": "bun run src/mcp-server.ts" to scripts for easy testing.


How to Enable in Claude Code

Step 1: Restart Claude Code

After creating the .mcp.json file, you need to restart Claude Code for it to discover the MCP server.

# If Claude Code is running, exit and restart
opencode

Step 2: Approve the MCP Server

When Claude Code starts in this directory, it will detect the .mcp.json file and prompt you to approve the MCP server.

You'll see a prompt like:

Found MCP server configuration:
- ai-stack-deployer

Would you like to enable this MCP server? (y/n)

Type y to approve.

Step 3: Verify MCP Server is Running

Claude Code will automatically start the MCP server when needed. You can verify it's working by asking Claude Code:

Can you list the available MCP tools?

You should see the 5 tools from the AI Stack Deployer.


Available Tools

1. deploy_stack

Deploys a new AI coding assistant stack.

Parameters:

  • name (string, required): Username for the stack (3-20 chars, lowercase alphanumeric and hyphens)

Returns:

{
  "success": true,
  "deploymentId": "dep_1704830000000_abc123",
  "name": "john",
  "status": "completed",
  "url": "https://john.ai.flexinit.nl",
  "message": "Stack successfully deployed at https://john.ai.flexinit.nl"
}

Example usage in Claude Code:

Deploy an AI stack for user "alice"

2. check_deployment_status

Check the status of a deployment.

Parameters:

  • deploymentId (string, required): The deployment ID from deploy_stack

Returns:

{
  "success": true,
  "deployment": {
    "id": "dep_1704830000000_abc123",
    "name": "john",
    "status": "completed",
    "url": "https://john.ai.flexinit.nl",
    "createdAt": "2026-01-09T17:30:00.000Z"
  }
}

Possible statuses:

  • initializing - Starting deployment
  • creating_dns - Creating DNS records
  • creating_project - Creating Dokploy project
  • creating_application - Creating application
  • deploying - Deploying container
  • completed - Successfully deployed
  • failed - Deployment failed

3. list_deployments

List all recent deployments.

Parameters: None

Returns:

{
  "success": true,
  "deployments": [
    {
      "id": "dep_1704830000000_abc123",
      "name": "john",
      "status": "completed",
      "url": "https://john.ai.flexinit.nl",
      "createdAt": "2026-01-09T17:30:00.000Z"
    }
  ],
  "total": 1
}

4. check_name_availability

Check if a stack name is available and valid.

Parameters:

  • name (string, required): The name to check

Returns:

{
  "available": true,
  "valid": true,
  "name": "john"
}

Or if invalid:

{
  "available": false,
  "valid": false,
  "error": "Name must be between 3 and 20 characters"
}

5. test_api_connections

Test connections to Hetzner DNS and Dokploy APIs.

Parameters: None

Returns:

{
  "hetzner": {
    "success": true,
    "message": "Connected to Hetzner Cloud DNS API. Zone \"flexinit.nl\" has 75 RRSets.",
    "recordCount": 75,
    "zoneName": "flexinit.nl"
  },
  "dokploy": {
    "success": true,
    "message": "Connected to Dokploy API. Found 12 projects.",
    "projectCount": 12
  },
  "overall": true
}

Testing the MCP Server

Manual Test (Direct Invocation)

You can test the MCP server directly:

# Start the MCP server
bun run mcp

# It will wait for JSON-RPC messages on stdin
# Press Ctrl+C to exit

Test via Claude Code

Once enabled in Claude Code, you can test it by asking:

Test the API connections for the AI Stack Deployer

Claude Code will invoke the test_api_connections tool and show you the results.


Troubleshooting

MCP Server Not Appearing in Claude Code

  1. Check .mcp.json exists in the project root
  2. Restart Claude Code completely
  3. Check for syntax errors in .mcp.json
  4. Ensure Bun is installed and in PATH

Tools Not Working

  1. Check environment variables in .env:

    cat .env
    
  2. Test API connections:

    bun run src/test-clients.ts
    
  3. Check Dokploy token (common issue):

Deployment Fails

  1. DNS issues: Verify Hetzner API token is valid
  2. Dokploy issues: Verify Dokploy API token and URL
  3. Name conflicts: Check if name already exists
  4. Permissions: Ensure API tokens have required permissions

Security Considerations

Environment Variables

The MCP server inherits environment variables from the parent process. The .mcp.json file has an empty env object, which means it will use:

  1. Variables from .env file (loaded by Bun)
  2. Variables from the shell environment

Never commit .env file to version control!

API Token Safety

  • Hetzner and Dokploy API tokens are read from environment variables
  • Tokens are never exposed in MCP responses
  • All API calls are authenticated

Integration Examples

Example 1: Deploy Stack from Claude Code

User: Deploy an AI stack for user "bob"

Claude: I'll deploy an AI stack for "bob" using the deploy_stack tool.
[Calls deploy_stack with name="bob"]

Result:
✓ Deployment successful!
- Deployment ID: dep_1704830000000_xyz789
- URL: https://bob.ai.flexinit.nl
- Status: completed

Example 2: Check All Deployments

User: Show me all recent deployments

Claude: I'll list all deployments using the list_deployments tool.
[Calls list_deployments]

Result:
Total: 3 deployments
1. alice - https://alice.ai.flexinit.nl (completed)
2. bob - https://bob.ai.flexinit.nl (completed)
3. charlie - https://charlie.ai.flexinit.nl (failed)

Example 3: Validate Name Before Deploying

User: Can I use the name "test" for a new stack?

Claude: Let me check if "test" is available.
[Calls check_name_availability with name="test"]

Result: ❌ Name "test" is reserved and cannot be used.
Reserved names: admin, api, www, root, system, test, demo, portal

Next Steps

Enhance the MCP Server

Consider adding these tools:

  1. delete_stack - Remove a deployed stack
  2. get_stack_logs - Retrieve application logs
  3. restart_stack - Restart a deployed stack
  4. list_available_images - Show available Docker images
  5. get_stack_metrics - Show resource usage

Production Deployment

  1. Add authentication to the MCP server
  2. Rate limiting for deployments
  3. Persistent storage for deployment state (currently in-memory)
  4. Webhooks for deployment status updates
  5. Audit logging for all operations

Technical Details

Protocol Used

  • Transport: stdio (standard input/output)
  • Message Format: JSON-RPC 2.0
  • SDK: @modelcontextprotocol/sdk v1.25.2

State Management

Currently, deployment state is stored in-memory using a Map:

  • Fast access
  • Simple implementation
  • Lost on server restart
  • Not shared across instances

For production, consider:

  • Redis for distributed state
  • PostgreSQL for persistent storage
  • File-based storage for simplicity

Error Handling

The MCP server wraps all tool calls in try-catch blocks and returns structured errors:

{
  "success": false,
  "error": "Name already taken"
}

This ensures Claude Code always receives parseable responses.


Summary

MCP Server: Fully implemented in src/mcp-server.ts Configuration: Added .mcp.json for Claude Code Tools: 5 tools for deployment management Integration: Uses existing API clients Testing: Server starts successfully Documentation: This guide

You can now use Claude Code to deploy and manage AI stacks through natural language commands!


Support

For issues or questions:

  1. Check this guide first
  2. Review TESTING.md for API connection issues
  3. Check Claude Code logs: ~/.config/claude/debug/
  4. Test API clients directly: bun run src/test-clients.ts

Built with ❤️ by Oussama Douhou