feat(mcp): add stats, value props, and CTA tools for landing pages
All checks were successful
Build and Release / Lint (push) Successful in 5m21s
Build and Release / Create Release (push) Successful in 0s
Build and Release / Build Binaries (amd64, darwin, macos) (push) Successful in 4m21s
Build and Release / Build Binaries (arm64, darwin, macos) (push) Successful in 4m32s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 12m1s
Build and Release / Build Binary (linux/arm64) (push) Successful in 7m55s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Successful in 9h7m31s
Build and Release / Unit Tests (push) Successful in 14m12s
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Successful in 12m51s
All checks were successful
Build and Release / Lint (push) Successful in 5m21s
Build and Release / Create Release (push) Successful in 0s
Build and Release / Build Binaries (amd64, darwin, macos) (push) Successful in 4m21s
Build and Release / Build Binaries (arm64, darwin, macos) (push) Successful in 4m32s
Build and Release / Integration Tests (PostgreSQL) (push) Successful in 12m1s
Build and Release / Build Binary (linux/arm64) (push) Successful in 7m55s
Build and Release / Build Binaries (amd64, windows, windows-latest) (push) Successful in 9h7m31s
Build and Release / Unit Tests (push) Successful in 14m12s
Build and Release / Build Binaries (amd64, linux, linux-latest) (push) Successful in 12m51s
Implements three new MCP tools for landing page management: update_landing_stats for stat counters, update_landing_value_props for value proposition cards, and update_landing_cta for bottom call-to-action section. Each tool supports structured data with validation and integrates with existing config save flow.
This commit is contained in:
@@ -783,6 +783,12 @@ func handleToolsCall(ctx *context_service.APIContext, req *MCPRequest) {
|
||||
result, err = toolUpdateLandingSEO(ctx, params.Arguments)
|
||||
case "update_landing_theme":
|
||||
result, err = toolUpdateLandingTheme(ctx, params.Arguments)
|
||||
case "update_landing_stats":
|
||||
result, err = toolUpdateLandingStats(ctx, params.Arguments)
|
||||
case "update_landing_value_props":
|
||||
result, err = toolUpdateLandingValueProps(ctx, params.Arguments)
|
||||
case "update_landing_cta":
|
||||
result, err = toolUpdateLandingCTA(ctx, params.Arguments)
|
||||
default:
|
||||
sendMCPError(ctx, req.ID, -32602, "Unknown tool", params.Name)
|
||||
return
|
||||
|
||||
@@ -244,6 +244,69 @@ var mcpPagesTools = []MCPTool{
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "update_landing_stats",
|
||||
Description: "Update the stats counters displayed on the landing page. Each stat has a value and label.",
|
||||
InputSchema: map[string]any{
|
||||
"type": "object",
|
||||
"required": []string{"owner", "repo", "stats"},
|
||||
"properties": map[string]any{
|
||||
"owner": map[string]any{"type": "string", "description": "Repository owner"},
|
||||
"repo": map[string]any{"type": "string", "description": "Repository name"},
|
||||
"stats": map[string]any{
|
||||
"type": "array",
|
||||
"items": map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"value": map[string]any{"type": "string"},
|
||||
"label": map[string]any{"type": "string"},
|
||||
},
|
||||
},
|
||||
"description": "Array of stat counters (e.g., [{value: '15+', label: 'Tools'}])",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "update_landing_value_props",
|
||||
Description: "Update the value propositions section. Each value prop has a title, description, and icon.",
|
||||
InputSchema: map[string]any{
|
||||
"type": "object",
|
||||
"required": []string{"owner", "repo", "value_props"},
|
||||
"properties": map[string]any{
|
||||
"owner": map[string]any{"type": "string", "description": "Repository owner"},
|
||||
"repo": map[string]any{"type": "string", "description": "Repository name"},
|
||||
"value_props": map[string]any{
|
||||
"type": "array",
|
||||
"items": map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{
|
||||
"title": map[string]any{"type": "string"},
|
||||
"description": map[string]any{"type": "string"},
|
||||
"icon": map[string]any{"type": "string"},
|
||||
},
|
||||
},
|
||||
"description": "Array of value propositions",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "update_landing_cta",
|
||||
Description: "Update the call-to-action section at the bottom of the page with headline, subheadline, and button.",
|
||||
InputSchema: map[string]any{
|
||||
"type": "object",
|
||||
"required": []string{"owner", "repo"},
|
||||
"properties": map[string]any{
|
||||
"owner": map[string]any{"type": "string", "description": "Repository owner"},
|
||||
"repo": map[string]any{"type": "string", "description": "Repository name"},
|
||||
"headline": map[string]any{"type": "string", "description": "CTA headline"},
|
||||
"subheadline": map[string]any{"type": "string", "description": "CTA subheadline"},
|
||||
"button_label": map[string]any{"type": "string", "description": "Button text"},
|
||||
"button_url": map[string]any{"type": "string", "description": "Button URL"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// ── Tool Implementations ──────────────────────────────────
|
||||
@@ -573,6 +636,71 @@ func toolUpdateLandingTheme(ctx *context.APIContext, args map[string]any) (any,
|
||||
return saveAndReturn(ctx, repoObj, config, "theme")
|
||||
}
|
||||
|
||||
func toolUpdateLandingStats(ctx *context.APIContext, args map[string]any) (any, error) {
|
||||
config, repoObj, err := getConfigForUpdate(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if stats, ok := args["stats"].([]any); ok {
|
||||
config.Stats = nil
|
||||
for _, s := range stats {
|
||||
if sm, ok := s.(map[string]any); ok {
|
||||
config.Stats = append(config.Stats, pages_module.StatConfig{
|
||||
Value: strVal(sm, "value"),
|
||||
Label: strVal(sm, "label"),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return saveAndReturn(ctx, repoObj, config, "stats")
|
||||
}
|
||||
|
||||
func toolUpdateLandingValueProps(ctx *context.APIContext, args map[string]any) (any, error) {
|
||||
config, repoObj, err := getConfigForUpdate(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if vps, ok := args["value_props"].([]any); ok {
|
||||
config.ValueProps = nil
|
||||
for _, v := range vps {
|
||||
if vm, ok := v.(map[string]any); ok {
|
||||
config.ValueProps = append(config.ValueProps, pages_module.ValuePropConfig{
|
||||
Title: strVal(vm, "title"),
|
||||
Description: strVal(vm, "description"),
|
||||
Icon: strVal(vm, "icon"),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return saveAndReturn(ctx, repoObj, config, "value_props")
|
||||
}
|
||||
|
||||
func toolUpdateLandingCTA(ctx *context.APIContext, args map[string]any) (any, error) {
|
||||
config, repoObj, err := getConfigForUpdate(ctx, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if v, ok := args["headline"].(string); ok {
|
||||
config.CTASection.Headline = v
|
||||
}
|
||||
if v, ok := args["subheadline"].(string); ok {
|
||||
config.CTASection.Subheadline = v
|
||||
}
|
||||
if v, ok := args["button_label"].(string); ok {
|
||||
config.CTASection.Button.Label = v
|
||||
}
|
||||
if v, ok := args["button_url"].(string); ok {
|
||||
config.CTASection.Button.URL = v
|
||||
}
|
||||
|
||||
return saveAndReturn(ctx, repoObj, config, "cta_section")
|
||||
}
|
||||
|
||||
// ── Helpers ──────────────────────────────────
|
||||
|
||||
func getConfigForUpdate(ctx *context.APIContext, args map[string]any) (*pages_module.LandingConfig, *repo_model.Repository, error) {
|
||||
|
||||
Reference in New Issue
Block a user