use rmcp::schemars;
use schemars::JsonSchema;
use serde::Deserialize;
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct SearchInput {
#[schemars(description = "Text to search for across issues, pages, and comments")]
pub query: String,
#[schemars(description = "Filter to a specific project (e.g. LIF)")]
pub project: Option<String>,
#[schemars(description = "Restrict results to one type: issue, page, or comment")]
pub result_type: Option<String>,
#[schemars(
description = "Sort mode: relevance (default, best match first) or recent (most recently updated first)"
)]
pub sort: Option<String>,
#[schemars(
description = "Match mode: 'fts' (default, tokenized with prefix matching) or 'literal' (case-insensitive substring, for punctuation-heavy needles that FTS tokenizes away)."
)]
pub mode: Option<String>,
#[schemars(description = "Max results (default 20)")]
pub limit: Option<i64>,
#[schemars(description = "Zero-indexed offset for paging")]
pub offset: Option<i64>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct ListIssuesInput {
#[schemars(description = "Project ID (e.g. LIF)")]
pub project: String,
#[schemars(description = "Filter by status: backlog, todo, active, done, cancelled")]
pub status: Option<String>,
#[schemars(description = "Filter by priority: urgent, high, medium, low, none")]
pub priority: Option<String>,
#[schemars(description = "Filter by module name")]
pub module: Option<String>,
#[schemars(description = "Filter by label name")]
pub label: Option<String>,
#[schemars(description = "Only return issues with no unresolved blockers")]
pub workable: Option<bool>,
#[schemars(description = "Return issues with at least one blocker.")]
pub blocked: Option<bool>,
#[schemars(description = "Created at/after ISO date or datetime (e.g. 2026-06-01)")]
pub created_since: Option<String>,
#[schemars(description = "Created before ISO date or datetime (exclusive)")]
pub created_until: Option<String>,
#[schemars(description = "Updated at/after ISO date or datetime.")]
pub updated_since: Option<String>,
#[schemars(description = "Updated before ISO date or datetime (exclusive)")]
pub updated_until: Option<String>,
#[schemars(
description = "Sort Order: sort_order (default), sequence, created, updated, priority"
)]
pub order_by: Option<String>,
#[schemars(description = "Sort direction: asc (default) or desc")]
pub order: Option<String>,
#[schemars(description = "Max results (default 50)")]
pub limit: Option<i64>,
#[schemars(description = "Zero-indexed offset for paging")]
pub offset: Option<i64>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct GetIssueInput {
#[schemars(description = "Issue ID like PRO-42 or ADA-7")]
pub identifier: String,
#[schemars(description = "Comment trail: 'recent' (default, last 3), 'all', or 'none'.")]
pub include_comments: Option<String>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct GetActivityInput {
#[schemars(description = "Issue ID (PRO-42), page ID (PRO-DOC-3), or bare project ID (PRO)")]
pub identifier: String,
#[schemars(description = "Max entries (default 30, cap 200)")]
pub limit: Option<i64>,
#[schemars(description = "Zero-indexed offset for paging")]
pub offset: Option<i64>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct CreateIssueInput {
#[schemars(description = "Project ID (e.g. LIF)")]
pub project: String,
#[schemars(description = "Issue title")]
pub title: String,
#[schemars(description = "Markdown description")]
pub description: Option<String>,
#[schemars(description = "Status: backlog, todo, active, done, cancelled (default: backlog)")]
pub status: Option<String>,
#[schemars(description = "Priority: urgent, high, medium, low, none (default: none)")]
pub priority: Option<String>,
#[schemars(description = "Module name to assign to")]
pub module: Option<String>,
#[schemars(description = "Label names to attach")]
pub labels: Option<Vec<String>>,
#[schemars(description = "Start date (ISO 8601 date, e.g. 2026-06-01)")]
pub start_date: Option<String>,
#[schemars(description = "Target/due date (ISO 8601 date, e.g. 2026-06-15)")]
pub target_date: Option<String>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct UpdateIssueInput {
#[schemars(description = "Issue ID like PRO-42")]
pub identifier: String,
#[schemars(description = "New title")]
pub title: Option<String>,
#[schemars(description = "New description (markdown)")]
pub description: Option<String>,
#[schemars(description = "New status: backlog, todo, active, done, cancelled")]
pub status: Option<String>,
#[schemars(description = "New priority: urgent, high, medium, low, none")]
pub priority: Option<String>,
#[schemars(
description = "New module name. Omit to leave unchanged; pass an empty string \"\" to unassign."
)]
pub module: Option<String>,
#[schemars(description = "Replace labels")]
pub labels: Option<Vec<String>>,
#[schemars(description = "New start date (ISO 8601 date, e.g. 2026-06-01)")]
pub start_date: Option<String>,
#[schemars(description = "New target/due date (ISO 8601 date, e.g. 2026-06-15)")]
pub target_date: Option<String>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct BulkUpdateInput {
#[schemars(description = "Project ID (e.g. LIF)")]
pub project: String,
#[schemars(
description = "Only affect issues with this status: backlog, todo, active, done, cancelled"
)]
pub filter_status: Option<String>,
#[schemars(
description = "Only affect issues with this priority: urgent, high, medium, low, none"
)]
pub filter_priority: Option<String>,
#[schemars(description = "Only affect issues in this module (by name)")]
pub filter_module: Option<String>,
#[schemars(description = "Only affect issues carrying this label (by name)")]
pub filter_label: Option<String>,
#[schemars(description = "New status to set: backlog, todo, active, done, cancelled")]
pub set_status: Option<String>,
#[schemars(description = "New priority to set: urgent, high, medium, low, none")]
pub set_priority: Option<String>,
#[schemars(description = "New module (by name) to set")]
pub set_module: Option<String>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct GetBoardInput {
#[schemars(description = "Project ID (e.g. LIF)")]
pub project: String,
#[schemars(description = "Group by: status, priority, or module (default: status)")]
pub group_by: Option<String>,
#[schemars(
description = "Include done and cancelled issues (default false). By default closed columns appear as count-only stubs."
)]
pub include_closed: Option<bool>,
#[schemars(description = "Cap issues rendered per column; output notes the remainder")]
pub max_per_column: Option<i64>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct LinkIssuesInput {
#[schemars(description = "Source issue ID (e.g. PRO-1)")]
pub source: String,
#[schemars(description = "Target issue ID (e.g. PRO-2)")]
pub target: String,
#[schemars(description = "Relation type: blocks, relates_to, or duplicate")]
pub relation_type: String,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct UnlinkIssuesInput {
#[schemars(description = "First issue ID")]
pub source: String,
#[schemars(description = "Second issue ID")]
pub target: String,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct GetPageInput {
#[schemars(description = "Page ID like LIF-DOC-1")]
pub identifier: String,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct CreatePageInput {
#[schemars(description = "Project ID (e.g. LIF). Omit for workspace-level page.")]
pub project: Option<String>,
#[schemars(description = "Page title")]
pub title: String,
#[schemars(description = "Markdown content")]
pub content: Option<String>,
#[schemars(description = "Folder name to place page in")]
pub folder: Option<String>,
#[schemars(description = "Status: draft, active, complete, archived")]
pub status: Option<String>,
#[schemars(
description = "Label names to attach (project-scoped; ignored on workspace pages)"
)]
pub labels: Option<Vec<String>>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct UpdatePageInput {
#[schemars(description = "Page ID like LIF-DOC-1")]
pub identifier: String,
#[schemars(description = "New title")]
pub title: Option<String>,
#[schemars(description = "New markdown content")]
pub content: Option<String>,
#[schemars(
description = "Move to folder name. Omit to leave unchanged; pass an empty string \"\" for project root."
)]
pub folder: Option<String>,
#[schemars(description = "Status: draft, active, complete, archived")]
pub status: Option<String>,
#[schemars(description = "Pin (true) or unpin (false) the page to the top of the page list.")]
pub pinned: Option<bool>,
#[schemars(description = "Replace labels; [] clears all (project-scoped)")]
pub labels: Option<Vec<String>>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct EditIssueInput {
#[schemars(description = "Issue ID like PRO-42")]
pub identifier: String,
#[schemars(description = "Exact string to find. Must be unique unless replace_all is true.")]
pub old_string: String,
#[schemars(description = "Replacement string (must differ from old_string)")]
pub new_string: String,
#[schemars(description = "Field to edit: 'description' (default) or 'title'")]
pub field: Option<String>,
#[schemars(description = "Replace all occurrences (default false)")]
pub replace_all: Option<bool>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct EditPageInput {
#[schemars(description = "Page ID like LIF-DOC-1")]
pub identifier: String,
#[schemars(description = "Exact string to find. Must be unique unless replace_all is true.")]
pub old_string: String,
#[schemars(description = "Replacement string (must differ from old_string)")]
pub new_string: String,
#[schemars(description = "Field to edit: 'content' (default) or 'title'")]
pub field: Option<String>,
#[schemars(description = "Replace all occurrences (default false)")]
pub replace_all: Option<bool>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct DeleteInput {
#[schemars(
description = "Type of thing to delete: issue, page, plan, project, module, label, or folder"
)]
pub resource_type: String,
#[schemars(
description = "ID or name (e.g. LIF-1, LIF-DOC-1, LIF for projects, or name for modules/labels/folders)"
)]
pub identifier: String,
#[schemars(description = "Project ID (required for deleting module/label/folder by name)")]
pub project: Option<String>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct ListResourcesInput {
#[schemars(description = "Resource type: project, module, label, folder, page, issue, or plan")]
pub resource_type: String,
#[schemars(description = "Project ID (required for issues, plans, modules, labels, and folders; optional for pages and projects)")]
pub project: Option<String>,
#[schemars(description = "Folder name (for pages)")]
pub folder: Option<String>,
#[schemars(description = "Label name (for issues or pages)")]
pub label: Option<String>,
#[schemars(
description = "Status filter for pages (draft, active, complete, archived) or plans"
)]
pub status: Option<String>,
#[schemars(
description = "Sort column (for page lists): sort_order (default), title, status, created, or updated"
)]
pub order_by: Option<String>,
#[schemars(description = "Sort direction (for page lists): asc (default) or desc")]
pub order: Option<String>,
#[schemars(description = "Max results (plans default to 50 and cap at 500; issues and pages default to 100; other lists ignore this field)")]
pub limit: Option<i64>,
#[schemars(description = "Zero-indexed offset for issue, page, or plan paging")]
pub offset: Option<i64>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct ManageResourceInput {
#[schemars(description = "Resource type: project, module, label, or folder")]
pub resource_type: String,
#[schemars(description = "Action: create or update")]
pub action: String,
#[schemars(
description = "Required for module, label, or folder updates; projects use `project` instead"
)]
pub current_name: Option<String>,
#[schemars(
description = "Project ID (e.g. LIF), required for module/label/folder operations and for project updates"
)]
pub project: Option<String>,
#[schemars(description = "Name (required when creating a project, module, label, or folder)")]
pub name: Option<String>,
#[schemars(description = "Identifier (required for project create, e.g. PRO)")]
pub identifier: Option<String>,
#[schemars(description = "Description")]
pub description: Option<String>,
#[schemars(
description = "Status (for module: backlog, planned, active, paused, done, cancelled)"
)]
pub status: Option<String>,
#[schemars(description = "Color hex (for label, e.g. #EF4444)")]
pub color: Option<String>,
#[schemars(
description = "Icon for project or module: 'lucide:<Name>' or a literal emoji. Omit to leave unchanged; pass an empty string \"\" to clear."
)]
pub emoji: Option<String>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct AddCommentInput {
#[schemars(description = "Issue ID (e.g. LIF-1), project page ID (e.g. LIF-DOC-1), or workspace page ID (e.g. DOC-1)")]
pub identifier: String,
#[schemars(description = "Comment content (markdown)")]
pub content: String,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct ListCommentsInput {
#[schemars(description = "Issue ID (e.g. LIF-1), project page ID (e.g. LIF-DOC-1), or workspace page ID (e.g. DOC-1)")]
pub identifier: String,
#[schemars(description = "Filter to comments by this author username")]
pub author: Option<String>,
#[schemars(
description = "Sort direction by creation time: asc (default, oldest first) or desc (newest first)"
)]
pub order: Option<String>,
#[schemars(
description = "Optional maximum comments to return (cap 500). Omit to return the full thread."
)]
pub limit: Option<i64>,
#[schemars(description = "Zero-indexed offset for paging")]
pub offset: Option<i64>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct EditCommentInput {
#[schemars(description = "Comment id (from add_comment or list_comments)")]
pub comment_id: i64,
#[schemars(description = "New comment content (markdown)")]
pub content: String,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct DeleteCommentInput {
#[schemars(description = "Comment id (from add_comment or list_comments)")]
pub comment_id: i64,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct PlanStepInput {
#[schemars(description = "Step title, short and imperative")]
pub title: String,
#[schemars(description = "Optional longer notes/description for this step")]
pub description: Option<String>,
#[schemars(description = "Issue ID this step mirrors (e.g. LIF-42)")]
pub issue: Option<String>,
#[schemars(description = "Pre-mark this step done (default false)")]
pub done: Option<bool>,
#[schemars(description = "Nested child steps (any depth)")]
pub steps: Option<Vec<PlanStepInput>>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct CreatePlanInput {
#[schemars(description = "Project ID (e.g. LIF)")]
pub project: String,
#[schemars(description = "Plan title")]
pub title: String,
#[schemars(
description = "Optional anchor issue (e.g. LIF-42). Closing it auto-archives the plan."
)]
pub anchor_issue: Option<String>,
#[schemars(
description = "Full nested step tree. Each step: {title, description?, issue?, done?, steps?[]}"
)]
pub steps: Option<Vec<PlanStepInput>>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct GetPlanInput {
#[schemars(description = "Plan ID like LIF-PLAN-3")]
pub plan: String,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct EditPlanStepInput {
#[schemars(description = "Plan ID like LIF-PLAN-3")]
pub plan: String,
#[schemars(description = "Numeric step id (the #N shown by get_plan)")]
pub step_id: i64,
#[schemars(description = "Exact string to find. Must be unique unless replace_all is true.")]
pub old_string: String,
#[schemars(description = "Replacement string")]
pub new_string: String,
#[schemars(description = "Field to edit: 'description' (default) or 'title'")]
pub field: Option<String>,
#[schemars(description = "Replace all occurrences (default false)")]
pub replace_all: Option<bool>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct UpdatePlanStepInput {
#[schemars(description = "Plan ID like LIF-PLAN-3")]
pub plan: String,
#[schemars(
description = "Step ID to operate on (#N from get_plan). OMIT operates on the plan itself."
)]
pub step_id: Option<i64>,
#[schemars(description = "New title for the target")]
pub title: Option<String>,
#[schemars(description = "Plan status: active done or archived")]
pub status: Option<String>,
#[schemars(description = "Set the plan's anchor issue")]
pub anchor_issue: Option<String>,
#[schemars(description = "Clear the plan's anchor issue")]
pub clear_anchor: Option<bool>,
#[schemars(description = "Mark the step done/undone (a linked issue syncs)")]
pub done: Option<bool>,
#[schemars(description = "Attach an issue (e.g. LIF-42) to the step")]
pub attach_issue: Option<String>,
#[schemars(description = "Detach the step's issue reference")]
pub detach_issue: Option<bool>,
#[schemars(description = "Add a child step with this title under the target step")]
pub add_child_title: Option<String>,
#[schemars(description = "Description for the added child step")]
pub add_child_description: Option<String>,
#[schemars(description = "Issue ID for the added child step")]
pub add_child_issue: Option<String>,
#[schemars(description = "Reparent the step under this step id")]
pub move_parent_step_id: Option<i64>,
#[schemars(description = "Reparent the step to the plan root")]
pub move_to_root: Option<bool>,
#[schemars(description = "New position among siblings (0-based)")]
pub move_position: Option<i64>,
#[schemars(description = "Delete the step and its subtree")]
pub delete: Option<bool>,
#[schemars(description = "Return the full re-rendered tree instead of the delta (default false)")]
pub echo_tree: Option<bool>,
}
#[derive(Debug, Default, Deserialize, JsonSchema)]
pub struct ExportInput {
#[schemars(
description = "What to export: an issue ID (PRO-42), a page ID (PRO-DOC-3), or a bare project ID (PRO) for the whole project"
)]
pub identifier: String,
}