read_tool.rs

 1use acp_thread::AcpThread;
 2use anyhow::Result;
 3use context_server::{
 4    listener::{McpServerTool, ToolResponse},
 5    types::{ToolAnnotations, ToolResponseContent},
 6};
 7use gpui::{AsyncApp, WeakEntity};
 8
 9use crate::tools::ReadToolParams;
10
11#[derive(Clone)]
12pub struct ReadTool {
13    thread_rx: watch::Receiver<WeakEntity<AcpThread>>,
14}
15
16impl ReadTool {
17    pub fn new(thread_rx: watch::Receiver<WeakEntity<AcpThread>>) -> Self {
18        Self { thread_rx }
19    }
20}
21
22impl McpServerTool for ReadTool {
23    type Input = ReadToolParams;
24    type Output = ();
25
26    const NAME: &'static str = "Read";
27
28    fn annotations(&self) -> ToolAnnotations {
29        ToolAnnotations {
30            title: Some("Read file".to_string()),
31            read_only_hint: Some(true),
32            destructive_hint: Some(false),
33            open_world_hint: Some(false),
34            idempotent_hint: None,
35        }
36    }
37
38    async fn run(
39        &self,
40        input: Self::Input,
41        cx: &mut AsyncApp,
42    ) -> Result<ToolResponse<Self::Output>> {
43        let mut thread_rx = self.thread_rx.clone();
44        let Some(thread) = thread_rx.recv().await?.upgrade() else {
45            anyhow::bail!("Thread closed");
46        };
47
48        let content = thread
49            .update(cx, |thread, cx| {
50                thread.read_text_file(input.abs_path, input.offset, input.limit, false, cx)
51            })?
52            .await?;
53
54        Ok(ToolResponse {
55            content: vec![ToolResponseContent::Text { text: content }],
56            structured_content: (),
57        })
58    }
59}