Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 15 additions & 17 deletions crates/goose-mcp/src/developer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ use indoc::formatdoc;
use serde_json::Value;
use std::{
collections::HashMap,
fs::File,
future::Future,
io::Cursor,
io::{Cursor, Read},
path::{Path, PathBuf},
pin::Pin,
};
Expand Down Expand Up @@ -975,9 +976,12 @@ impl DeveloperRouter {
if path.is_file() {
// Check file size first (400KB limit)
const MAX_FILE_SIZE: u64 = 400 * 1024; // 400KB in bytes
const MAX_CHAR_COUNT: usize = 400_000; // 409600 chars = 400KB

let file_size = std::fs::metadata(path)
let f = File::open(path)
.map_err(|e| ToolError::ExecutionError(format!("Failed to open file: {}", e)))?;

let file_size = f
.metadata()
.map_err(|e| {
ToolError::ExecutionError(format!("Failed to get file metadata: {}", e))
})?
Expand All @@ -990,24 +994,18 @@ impl DeveloperRouter {
file_size as f64 / 1024.0
)));
}
// Ensure we never read over that limit even if the file is being concurrently mutated
// (e.g. it's a log file)
let mut f = f.take(MAX_FILE_SIZE);

let uri = Url::from_file_path(path)
.map_err(|_| ToolError::ExecutionError("Invalid file path".into()))?
.to_string();

let content = std::fs::read_to_string(path)
let mut content = String::new();
f.read_to_string(&mut content)
.map_err(|e| ToolError::ExecutionError(format!("Failed to read file: {}", e)))?;

let char_count = content.chars().count();
if char_count > MAX_CHAR_COUNT {
return Err(ToolError::ExecutionError(format!(
"File '{}' has too many characters ({}). Maximum character count is {}.",
path.display(),
char_count,
MAX_CHAR_COUNT
)));
}

let lines: Vec<&str> = content.lines().collect();
let total_lines = lines.len();

Expand Down Expand Up @@ -1909,8 +1907,8 @@ mod tests {
let many_chars_path = temp_dir.path().join("many_chars.txt");
let many_chars_str = many_chars_path.to_str().unwrap();

// Create a file with more than 400K characters but less than 400KB
let content = "x".repeat(405_000);
// This is above MAX_FILE_SIZE
let content = "x".repeat(500_000);
std::fs::write(&many_chars_path, content).unwrap();

let result = router
Expand All @@ -1927,7 +1925,7 @@ mod tests {
assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ToolError::ExecutionError(_)));
assert!(err.to_string().contains("too many characters"));
assert!(err.to_string().contains("is too large"));
}

// Let temp_dir drop naturally at end of scope
Expand Down
Loading