Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ port: 8080
base_url: https://your-domain.com
authorization_server_url: https://your-auth-server.com
api_base_url: https://api.createos.nodeops.network
sandbox_api_base_url: https://your-fc-control-api.example.com
transport: http # "http" or "stdio"
log_level: debug

Expand Down Expand Up @@ -220,6 +221,9 @@ The server exposes **85+ tools** organized into the following categories:
| **GitHub** | `InstallGithubApp`, `ListConnectedGithubAccounts`, `ListGithubRepositories`, `ListGithubRepositoryBranches`, `GetGithubRepositoryContent` | GitHub integration for repo-based deployments |
| **Account** | `GetCurrentUser`, `GetQuotas`, `GetSupportedProjectTypes` | User info, quotas, and platform capabilities |
| **Transfers** | `TransferProject`, `GetProjectTransferUri`, `ListProjectTransferHistory` | Transfer project ownership between accounts |
| **Sandboxes** | `CreateSandbox`, `UpdateSandbox`, `ExecSandbox`, `DeleteSandbox` | Create, update, execute commands in, and destroy sandbox VMs |
| **Sandbox Disks** | `CreateDisk`, `ListDisks`, `GetDisk`, `DeleteDisk`, `AttachSandboxDisk`, `DetachSandboxDisk`, `ListSandboxDisks` | Register S3 disks and attach them to sandboxes |
| **Sandbox Networks** | `CreateNetwork`, `ListNetworks`, `GetNetwork`, `DeleteNetwork`, `AttachSandboxNetwork`, `DetachSandboxNetwork` | Create private sandbox networks and manage membership |

---

Expand Down
1 change: 1 addition & 0 deletions config-files/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ port: 8080
base_url:
authorization_server_url:
api_base_url:
sandbox_api_base_url:
transport: http
log_level: debug

Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Config struct {
BaseURL string `yaml:"base_url"`
AuthorizationServerUrl string `yaml:"authorization_server_url"`
APIBaseUrl string `yaml:"api_base_url"`
SandboxAPIBaseUrl string `yaml:"sandbox_api_base_url"`
Transport string `yaml:"transport"`
LogLevel string `yaml:"log_level"`

Expand Down
28 changes: 28 additions & 0 deletions handlers/AttachSandboxDisk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type AttachSandboxDiskParams struct {
ID string `json:"id"`
Body map[string]interface{} `json:"body"`
}

func AttachSandboxDiskHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[AttachSandboxDiskParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxPostRequest(fmt.Sprintf("/v1/sandboxes/%s/disks", params.ID), params.Body, authInfo)
}
28 changes: 28 additions & 0 deletions handlers/AttachSandboxNetwork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type AttachSandboxNetworkParams struct {
ID string `json:"id"`
Body map[string]interface{} `json:"body"`
}

func AttachSandboxNetworkHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[AttachSandboxNetworkParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxPostRequest(fmt.Sprintf("/v1/sandboxes/%s/networks", params.ID), params.Body, authInfo)
}
27 changes: 27 additions & 0 deletions handlers/CreateDisk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type CreateDiskParams struct {
Body map[string]interface{} `json:"body"`
}

func CreateDiskHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[CreateDiskParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxPostRequest("/v1/disks", params.Body, authInfo)
}
27 changes: 27 additions & 0 deletions handlers/CreateNetwork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type CreateNetworkParams struct {
Body map[string]interface{} `json:"body"`
}

func CreateNetworkHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[CreateNetworkParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxPostRequest("/v1/networks", params.Body, authInfo)
}
27 changes: 27 additions & 0 deletions handlers/CreateSandbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type CreateSandboxParams struct {
Body map[string]interface{} `json:"body"`
}

func CreateSandboxHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[CreateSandboxParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxPostRequest("/v1/sandboxes", params.Body, authInfo)
}
27 changes: 27 additions & 0 deletions handlers/DeleteDisk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type DeleteDiskParams struct {
IDOrName string `json:"id_or_name"`
}

func DeleteDiskHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[DeleteDiskParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxDeleteRequest(fmt.Sprintf("/v1/disks/%s", params.IDOrName), authInfo)
}
27 changes: 27 additions & 0 deletions handlers/DeleteNetwork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type DeleteNetworkParams struct {
ID string `json:"id"`
}

func DeleteNetworkHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[DeleteNetworkParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxDeleteRequest(fmt.Sprintf("/v1/networks/%s", params.ID), authInfo)
}
27 changes: 27 additions & 0 deletions handlers/DeleteSandbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type DeleteSandboxParams struct {
ID string `json:"id"`
}

func DeleteSandboxHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[DeleteSandboxParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxDeleteRequest(fmt.Sprintf("/v1/sandboxes/%s", params.ID), authInfo)
}
37 changes: 37 additions & 0 deletions handlers/DetachSandboxDisk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type DetachSandboxDiskParams struct {
ID string `json:"id"`
DiskID string `json:"disk_id"`
MountPath string `json:"mount_path"`
}

func DetachSandboxDiskHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[DetachSandboxDiskParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

queryParams := map[string]string{
"mount_path": params.MountPath,
}

return makeSandboxDeleteRequestWithQuery(
fmt.Sprintf("/v1/sandboxes/%s/disks/%s", params.ID, params.DiskID),
queryParams,
authInfo,
)
}
28 changes: 28 additions & 0 deletions handlers/DetachSandboxNetwork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type DetachSandboxNetworkParams struct {
ID string `json:"id"`
Network string `json:"network"`
}

func DetachSandboxNetworkHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[DetachSandboxNetworkParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxDeleteRequest(fmt.Sprintf("/v1/sandboxes/%s/networks/%s", params.ID, params.Network), authInfo)
}
31 changes: 31 additions & 0 deletions handlers/ExecSandbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type ExecSandboxParams struct {
ID string `json:"id"`
Body map[string]interface{} `json:"body"`
}

func ExecSandboxHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[ExecSandboxParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}
if stream, ok := params.Body["stream"].(bool); ok && stream {
return nil, fmt.Errorf("streaming exec is not supported by ExecSandbox yet; omit stream or set it to false")
}

return makeSandboxPostRequest(fmt.Sprintf("/v1/sandboxes/%s/exec", params.ID), params.Body, authInfo)
}
27 changes: 27 additions & 0 deletions handlers/GetDisk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"
"fmt"

mcputils "github.com/NodeOps-app/createos-mcp/helpers"
"github.com/mark3labs/mcp-go/mcp"
)

type GetDiskParams struct {
IDOrName string `json:"id_or_name"`
}

func GetDiskHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
authInfo, args, err := handleRequest(ctx, request)
if err != nil {
return nil, err
}

params, err := mcputils.ParamsParser[GetDiskParams](args)
if err != nil {
return nil, fmt.Errorf("failed to parse parameters: %w", err)
}

return makeSandboxGetRequest(fmt.Sprintf("/v1/disks/%s", params.IDOrName), nil, authInfo)
}
Loading
Loading