Skip to content

Commit 0615adb

Browse files
dcodesdevcursoragentjohanjonaro00
authored
feat(mcp): limit max tokens for docs search and logs (#2114)
* Upgrade rmcp to v0.6.1 and refactor MCP server with new macros Co-authored-by: johan <[email protected]> * Refactor mcp.00 code style: improve formatting and line breaks Co-authored-by: johan <[email protected]> * Specify max lines for mcp logs * clippy fix * logs limit fix * max tokens for docs search --------- Co-authored-by: Cursor Agent <[email protected]> Co-authored-by: johan <[email protected]> Co-authored-by: jonaro00 <[email protected]>
1 parent 2d8a2bd commit 0615adb

File tree

5 files changed

+35
-17
lines changed

5 files changed

+35
-17
lines changed

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,7 @@ syn = "2"
8282
tempfile = "3"
8383
thiserror = "2"
8484
tokio = "1.40.0"
85-
tokio-tungstenite = { version = "0.27", features = [
86-
"rustls-tls-webpki-roots",
87-
] }
85+
tokio-tungstenite = { version = "0.27", features = ["rustls-tls-webpki-roots"] }
8886
toml = "0.9"
8987
toml_edit = "0.23"
9088
tracing = { version = "0.1.37", default-features = false }

mcp/src/mcp.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,6 @@ use tracing::instrument;
88
use crate::tools::{deployment::*, docs::*, logs::*, project::*};
99
use crate::utils::run_tool;
1010

11-
#[derive(Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
12-
struct SearchDocsArgs {
13-
#[schemars(description = "Search query for documentation")]
14-
query: String,
15-
}
16-
1711
#[derive(Clone)]
1812
pub struct ShuttleMcpServer {
1913
pub(crate) tool_router: ToolRouter<Self>,
@@ -80,7 +74,7 @@ impl ShuttleMcpServer {
8074
&self,
8175
Parameters(args): Parameters<SearchDocsArgs>,
8276
) -> Result<String, String> {
83-
run_tool(search_docs(args.query)).await
77+
run_tool(search_docs(args)).await
8478
}
8579
}
8680

mcp/src/tools/docs.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
use crate::{constants::SHUTTLE_DOCS_SEARCH_BASE_URL, utils::build_client};
22

3-
pub async fn search_docs(query: String) -> Result<String, String> {
3+
#[derive(Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
4+
pub struct SearchDocsArgs {
5+
#[schemars(description = "Search query for documentation")]
6+
query: String,
7+
#[schemars(description = "Maximum number of tokens to retrieve (default: 4000)")]
8+
max_tokens: Option<u32>,
9+
}
10+
11+
pub async fn search_docs(params: SearchDocsArgs) -> Result<String, String> {
412
let url = format!(
5-
"{SHUTTLE_DOCS_SEARCH_BASE_URL}/search?q={}",
6-
urlencoding::encode(&query)
13+
"{SHUTTLE_DOCS_SEARCH_BASE_URL}/search?q={}&maxTokens={}",
14+
urlencoding::encode(&params.query),
15+
params.max_tokens.unwrap_or(4000)
716
);
817

918
let client = build_client()?;
@@ -12,13 +21,13 @@ pub async fn search_docs(query: String) -> Result<String, String> {
1221
.get(&url)
1322
.send()
1423
.await
15-
.map_err(|e| format!("Request failed: {}", e))?;
24+
.map_err(|e| format!("Request failed: {e}"))?;
1625

1726
if response.status().is_success() {
1827
response
1928
.text()
2029
.await
21-
.map_err(|e| format!("Failed to read response: {}", e))
30+
.map_err(|e| format!("Failed to read response: {e}"))
2231
} else {
2332
Err(format!("Request failed with status: {}", response.status()))
2433
}

mcp/src/tools/logs.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
use crate::utils::execute_command;
22

3+
fn limit_to_last_n_lines(text: &str, max_lines: u32) -> String {
4+
let lines: Vec<&str> = text.lines().collect();
5+
6+
if lines.len() <= max_lines as usize {
7+
return text.to_string();
8+
}
9+
10+
let start_index = lines.len() - max_lines as usize;
11+
lines[start_index..].join("\n")
12+
}
13+
314
#[derive(Debug, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
415
pub struct LogsArgs {
516
#[schemars(description = "Specify the working directory")]
@@ -12,6 +23,8 @@ pub struct LogsArgs {
1223
name: Option<String>,
1324
#[schemars(description = "Specify the id of the project")]
1425
project_id: Option<String>,
26+
#[schemars(description = "Maximum number of lines to return")]
27+
lines: Option<u32>,
1528
}
1629

1730
pub async fn logs(params: LogsArgs) -> Result<String, String> {
@@ -35,5 +48,9 @@ pub async fn logs(params: LogsArgs) -> Result<String, String> {
3548
args.push(id);
3649
}
3750

38-
execute_command("shuttle", args, &params.cwd).await
51+
let output = execute_command("shuttle", args, &params.cwd).await?;
52+
53+
// Limit the output to the last N lines (default 50)
54+
let max_lines = params.lines.unwrap_or(50);
55+
Ok(limit_to_last_n_lines(&output, max_lines))
3956
}

mcp/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,5 @@ pub fn build_client() -> Result<reqwest::Client, String> {
4646
reqwest::Client::builder()
4747
.default_headers(headers)
4848
.build()
49-
.map_err(|e| format!("Failed to build client: {}", e))
49+
.map_err(|e| format!("Failed to build client: {e}"))
5050
}

0 commit comments

Comments
 (0)