use super::manager::PromptManager;
use super::template::parse_template;
use kodegen_mcp_tool::{Tool, ToolExecutionContext, ToolArgs, ToolResponse};
use kodegen_mcp_tool::error::McpError;
use kodegen_mcp_schema::prompt::{EditPromptArgs, EditPromptPromptArgs, PromptEditOutput, PROMPT_EDIT};
use rmcp::model::{PromptArgument, PromptMessage, PromptMessageContent, PromptMessageRole};
#[derive(Clone)]
pub struct EditPromptTool {
manager: PromptManager,
}
impl EditPromptTool {
pub fn with_manager(manager: PromptManager) -> Self {
Self { manager }
}
pub async fn new() -> Result<Self, McpError> {
let manager = PromptManager::new();
manager.init().await?;
Ok(Self { manager })
}
}
impl Tool for EditPromptTool {
type Args = EditPromptArgs;
type PromptArgs = EditPromptPromptArgs;
fn name() -> &'static str {
PROMPT_EDIT
}
fn description() -> &'static str {
"Edit an existing prompt template. Provide the prompt name and complete new content \
(including YAML frontmatter). The content is validated before saving. Use get_prompt \
to retrieve current content before editing."
}
fn read_only() -> bool {
false
}
fn destructive() -> bool {
true }
fn idempotent() -> bool {
true }
async fn execute(&self, args: Self::Args, _ctx: ToolExecutionContext) -> Result<ToolResponse<<Self::Args as ToolArgs>::Output>, McpError> {
self.manager
.edit_prompt(&args.name, &args.content)
.await
.map_err(McpError::Other)?;
let filename = format!("{}.j2.md", args.name);
let template = parse_template(&filename, &args.content)
.map_err(McpError::Other)?;
let template_length = args.content.len();
let parameter_count = template.metadata.parameters.len();
let summary = format!(
"\x1b[33m Prompt Updated: {}\x1b[0m\n\
Template length: {} · Parameters: {}",
args.name,
template_length,
parameter_count
);
let output = PromptEditOutput {
success: true,
name: args.name.clone(),
message: format!("Prompt '{}' updated successfully ({} bytes, {} parameters)", args.name, template_length, parameter_count),
path: None,
};
Ok(ToolResponse::new(summary, output))
}
fn prompt_arguments() -> Vec<PromptArgument> {
vec![
PromptArgument {
name: "focus_area".to_string(),
title: None,
description: Some(
"Which aspect of edit_prompt to focus on: \
'syntax' (Jinja2 template syntax), \
'validation' (validation process and errors), \
'examples' (real-world template examples), \
'best_practices' (tips and gotchas)"
.to_string(),
),
required: Some(false),
},
PromptArgument {
name: "template_complexity".to_string(),
title: None,
description: Some(
"Complexity level of template examples: 'simple' for basic templates, \
'advanced' for complex templates with many parameters"
.to_string(),
),
required: Some(false),
},
PromptArgument {
name: "include_common_mistakes".to_string(),
title: None,
description: Some(
"Include examples of common mistakes and how to avoid them when editing prompts"
.to_string(),
),
required: Some(false),
},
]
}
async fn prompt(&self, _args: Self::PromptArgs) -> Result<Vec<PromptMessage>, McpError> {
Ok(vec![
PromptMessage {
role: PromptMessageRole::User,
content: PromptMessageContent::text("How do I edit an existing prompt?"),
},
PromptMessage {
role: PromptMessageRole::Assistant,
content: PromptMessageContent::text(
"Use prompt_edit to update an existing prompt template:\n\n\
1. First, get the current content:\n\
```\n\
prompt_get({\"action\": \"get\", \"name\": \"my_prompt\"})\n\
```\n\n\
2. Then edit it:\n\
```\n\
prompt_edit({\n\
\"name\": \"my_prompt\",\n\
\"content\": \"---\\n\
title: \\\"Updated Title\\\"\\n\
description: \\\"Updated description\\\"\\n\
categories: [\\\"custom\\\"]\\n\
author: \\\"your-name\\\"\\n\
---\\n\
\\n\
Updated template content here\\n\
\\\"\n\
})\n\
```\n\n\
The new content completely replaces the old content. \
Template syntax is validated before saving.",
),
},
])
}
}