server_format.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: LicenseRef-MutuaL-1.2
  4
  5package mcp
  6
  7import (
  8	"fmt"
  9	"strconv"
 10	"strings"
 11
 12	"git.secluded.site/cooked-mcp/internal/cooked"
 13)
 14
 15func formatRecipes(recipes []cooked.RecipeCard) string {
 16	if len(recipes) == 0 {
 17		return "No saved recipes found."
 18	}
 19
 20	var builder strings.Builder
 21	builder.WriteString("Saved recipes:\n")
 22	for _, recipe := range recipes {
 23		builder.WriteString("- ")
 24		builder.WriteString(recipe.Title)
 25		builder.WriteString(" (id: ")
 26		builder.WriteString(recipe.ID)
 27		builder.WriteString(")\n")
 28	}
 29
 30	return strings.TrimRight(builder.String(), "\n")
 31}
 32
 33func formatRecipeNextPageHint(query string, nextPage, limit int) string {
 34	if query == "" {
 35		return fmt.Sprintf(
 36			"More recipes may be available. Call read with target recipes, page %d, limit %d to continue.",
 37			nextPage,
 38			limit,
 39		)
 40	}
 41
 42	return fmt.Sprintf(
 43		"More matching recipes may be available. Call read with target recipes, query %q, page %d, limit %d to continue.",
 44		query,
 45		nextPage,
 46		limit,
 47	)
 48}
 49
 50func formatRecipeSearchLimitHint(query string, page, nextPage, limit int) string {
 51	return fmt.Sprintf(
 52		"More matching recipes may be available. Call read with target recipes, query %q, page %d, limit %d to include more results from this page before trying page %d.",
 53		query,
 54		page,
 55		limit,
 56		nextPage,
 57	)
 58}
 59
 60func formatRecipe(recipe RecipeDetail) string {
 61	title := recipe.Title
 62	if title == "" {
 63		title = "(untitled recipe)"
 64	}
 65
 66	var builder strings.Builder
 67	builder.WriteString("Recipe: ")
 68	builder.WriteString(title)
 69	builder.WriteString(" (id: ")
 70	builder.WriteString(recipe.ID)
 71	builder.WriteString(")\n")
 72	if recipe.Owner != "" {
 73		builder.WriteString("Owner: ")
 74		builder.WriteString(recipe.Owner)
 75		builder.WriteByte('\n')
 76	}
 77	fmt.Fprintf(&builder, "Portions: %s\n", formatPortions(recipe.Portions))
 78
 79	content := strings.TrimSpace(recipe.Content)
 80	if content == "" {
 81		builder.WriteString("\nNo recipe content returned.")
 82	} else {
 83		builder.WriteString("\n")
 84		builder.WriteString(content)
 85	}
 86
 87	return strings.TrimRight(builder.String(), "\n")
 88}
 89
 90func formatRecipeTextPreview(preview ExtractIntoRecipeOutput) string {
 91	title := preview.Title
 92	if title == "" {
 93		title = "(untitled extraction)"
 94	}
 95
 96	var builder strings.Builder
 97	builder.WriteString("Extracted recipe text: ")
 98	builder.WriteString(title)
 99	builder.WriteByte('\n')
100	fmt.Fprintf(&builder, "Portions: %s\n", formatPortions(preview.Portions))
101
102	markdown := strings.TrimSpace(preview.Markdown)
103	if markdown == "" {
104		builder.WriteString("\nNo preview markdown returned.")
105	} else {
106		builder.WriteString("\n")
107		builder.WriteString(markdown)
108	}
109
110	return strings.TrimRight(builder.String(), "\n")
111}
112
113func formatPortions(portions float64) string { return strconv.FormatFloat(portions, 'f', -1, 64) }
114
115func formatRecipeSave(output SaveRecipeOutput) string {
116	return "Saved recipe (id: " + output.RecipeID + ")."
117}
118
119func formatRecipeOverwrite(output SaveRecipeOutput) string {
120	return "Saved draft into existing recipe (id: " + output.RecipeID + ")."
121}
122
123func formatRecipeURLImportDraft(output SaveRecipeOutput) string {
124	title := output.Title
125	if strings.TrimSpace(title) == "" {
126		title = "(untitled draft)"
127	}
128
129	var builder strings.Builder
130	builder.WriteString("Imported recipe URL as draft: ")
131	builder.WriteString(title)
132	builder.WriteString(" (draft_id: ")
133	builder.WriteString(output.DraftID)
134	builder.WriteString("). Review the markdown and portions before saving.")
135	if output.Portions > 0 {
136		fmt.Fprintf(&builder, "\nPortions: %s", formatPortions(output.Portions))
137	}
138	if strings.TrimSpace(output.Markdown) != "" {
139		builder.WriteString("\n\n")
140		builder.WriteString(output.Markdown)
141	}
142
143	return strings.TrimRight(builder.String(), "\n")
144}
145
146func formatRecipeDelete(output DeleteRecipeOutput) string {
147	return "Deleted recipe (id: " + output.RecipeID + ")."
148}