Skip to main content

git_paw/mcp/tools/
coordination.rs

1//! Coordination tools: `get_intents`, `get_intent`, `get_conflicts`.
2//!
3//! These read live agent-coordination state from the broker. Every tool here
4//! degrades to empty arrays / null (never an error) when no broker is running.
5
6use rmcp::handler::server::wrapper::{Json, Parameters};
7use rmcp::{schemars, tool, tool_router};
8use serde::{Deserialize, Serialize};
9
10use crate::mcp::query;
11use crate::mcp::server::GitPawMcpServer;
12
13/// Parameters for [`GitPawMcpServer::get_intent`].
14#[derive(Debug, Deserialize, schemars::JsonSchema)]
15pub struct GetIntentParams {
16    /// Branch id (agent id) whose active intent to look up.
17    pub branch_id: String,
18}
19
20/// Response for `get_intents`.
21#[derive(Serialize, schemars::JsonSchema)]
22pub struct IntentsResponse {
23    /// Active intents.
24    pub intents: Vec<query::intents::Intent>,
25}
26
27/// Response for `get_intent`.
28#[derive(Serialize, schemars::JsonSchema)]
29pub struct IntentResponse {
30    /// Matching active intent, or null.
31    pub intent: Option<query::intents::Intent>,
32}
33
34/// Response for `get_conflicts`.
35#[derive(Serialize, schemars::JsonSchema)]
36pub struct ConflictsResponse {
37    /// Detected conflicts.
38    pub conflicts: Vec<query::conflicts::Conflict>,
39}
40
41#[tool_router(router = coordination_router, vis = "pub(crate)")]
42impl GitPawMcpServer {
43    /// `get_intents` — every active intent for this repo's session.
44    #[tool(
45        description = "List all active agent coordination intents for this repository's session. \
46                       Each intent carries branch_id, files, summary, published_at, and \
47                       valid_for_seconds. Returns an empty list when no broker/session is active."
48    )]
49    pub(crate) fn get_intents(&self) -> Json<IntentsResponse> {
50        Json(IntentsResponse {
51            intents: query::intents::active_intents(&self.ctx),
52        })
53    }
54
55    /// `get_intent` — a single agent's active intent by branch id.
56    #[tool(description = "Look up a single agent's active intent by branch_id. \
57                       Returns { \"intent\": null } when no matching active intent exists.")]
58    pub(crate) fn get_intent(
59        &self,
60        Parameters(p): Parameters<GetIntentParams>,
61    ) -> Json<IntentResponse> {
62        Json(IntentResponse {
63            intent: query::intents::intent_for(&self.ctx, &p.branch_id),
64        })
65    }
66
67    /// `get_conflicts` — all currently-detected coordination conflicts.
68    #[tool(
69        description = "List all currently-detected coordination conflicts between agents (forward \
70                       overlaps on declared files/regions). Each carries shape, branches, files, \
71                       and detected_at. Returns an empty list when no broker/session is active."
72    )]
73    pub(crate) fn get_conflicts(&self) -> Json<ConflictsResponse> {
74        Json(ConflictsResponse {
75            conflicts: query::conflicts::conflicts(&self.ctx),
76        })
77    }
78}