Skip to content

Commit

Permalink
formatting fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Kvadratni committed Jan 8, 2025
1 parent 4e7fac4 commit 108384c
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 52 deletions.
2 changes: 1 addition & 1 deletion crates/goose-cli/src/commands/mcp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use goose_mcp::{DeveloperRouter, JetBrainsRouter};
use mcp_server::router::RouterService;
use mcp_server::{ByteTransport, Server, BoundedService};
use mcp_server::{BoundedService, ByteTransport, Server};
use tokio::io::{stdin, stdout};

pub async fn run_server(name: &str) -> Result<()> {
Expand Down
1 change: 0 additions & 1 deletion crates/goose-cli/src/commands/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ pub async fn build_session<'a>(
.await
.expect("should start jetbrains server");


let prompt = match std::env::var("GOOSE_INPUT") {
Ok(val) => match val.as_str() {
"rustyline" => Box::new(RustylinePrompt::new()) as Box<dyn Prompt>,
Expand Down
4 changes: 2 additions & 2 deletions crates/goose-mcp/src/jetbrains/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl JetBrainsRouter {
return Ok(());
}
drop(tools); // Release the lock before sleeping

sleep(retry_delay).await;
retry_count += 1;
}
Expand Down Expand Up @@ -214,4 +214,4 @@ mod tests {
let capabilities = router.capabilities();
assert!(capabilities.tools);
}
}
}
92 changes: 59 additions & 33 deletions crates/goose-mcp/src/jetbrains/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use anyhow::{anyhow, Result};
use mcp_core::{Content, Tool};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::env;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::RwLock;
use reqwest::Client;
use anyhow::{Result, anyhow};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use tracing::{info, error, debug};
use mcp_core::{Content, Tool};
use tracing::{debug, error, info};

const PORT_RANGE_START: u16 = 63342;
const PORT_RANGE_END: u16 = 63352;
Expand Down Expand Up @@ -49,8 +49,13 @@ impl JetBrainsProxy {

async fn test_list_tools(&self, endpoint: &str) -> Result<bool> {
debug!("Sending test request to {}/mcp/list_tools", endpoint);

let response = match self.client.get(&format!("{}/mcp/list_tools", endpoint)).send().await {

let response = match self
.client
.get(&format!("{}/mcp/list_tools", endpoint))
.send()
.await
{
Ok(resp) => {
debug!("Got response with status: {}", resp.status());
resp
Expand Down Expand Up @@ -99,26 +104,34 @@ impl JetBrainsProxy {
return Ok(test_endpoint);
}
debug!("IDE_PORT {} is not responding correctly", port);
return Err(anyhow!("Specified IDE_PORT={} is not responding correctly", port));
return Err(anyhow!(
"Specified IDE_PORT={} is not responding correctly",
port
));
}

debug!("No IDE_PORT environment variable, scanning port range {}-{}",
PORT_RANGE_START, PORT_RANGE_END);
debug!(
"No IDE_PORT environment variable, scanning port range {}-{}",
PORT_RANGE_START, PORT_RANGE_END
);

// Scan port range
for port in PORT_RANGE_START..=PORT_RANGE_END {
let candidate_endpoint = format!("http://127.0.0.1:{}/api", port);
debug!("Testing port {}...", port);

if self.test_list_tools(&candidate_endpoint).await? {
debug!("Found working IDE endpoint at {}", candidate_endpoint);
return Ok(candidate_endpoint);
}
}

debug!("No working IDE endpoint found in port range");
Err(anyhow!("No working IDE endpoint found in range {}-{}",
PORT_RANGE_START, PORT_RANGE_END))
Err(anyhow!(
"No working IDE endpoint found in range {}-{}",
PORT_RANGE_START,
PORT_RANGE_END
))
}

async fn update_ide_endpoint(&self) {
Expand Down Expand Up @@ -153,10 +166,11 @@ impl JetBrainsProxy {
};

debug!("Sending list_tools request to {}/mcp/list_tools", endpoint);
let response = match self.client
let response = match self
.client
.get(&format!("{}/mcp/list_tools", endpoint))
.send()
.await
.await
{
Ok(resp) => {
debug!("Got response with status: {}", resp.status());
Expand All @@ -170,17 +184,19 @@ impl JetBrainsProxy {

if !response.status().is_success() {
debug!("Request failed with status: {}", response.status());
return Err(anyhow!("Failed to fetch tools with status {}", response.status()));
return Err(anyhow!(
"Failed to fetch tools with status {}",
response.status()
));
}

let response_text = response.text().await?;
debug!("Got response text: {}", response_text);

let tools_response: Value = serde_json::from_str(&response_text)
.map_err(|e| {
debug!("Failed to parse response as JSON: {}", e);
anyhow!("Failed to parse response as JSON: {}", e)
})?;
let tools_response: Value = serde_json::from_str(&response_text).map_err(|e| {
debug!("Failed to parse response as JSON: {}", e);
anyhow!("Failed to parse response as JSON: {}", e)
})?;

debug!("Parsed JSON response: {:?}", tools_response);

Expand All @@ -192,24 +208,27 @@ impl JetBrainsProxy {
})?
.iter()
.filter_map(|t| {
if let (Some(name), Some(description)) = (
t["name"].as_str(),
t["description"].as_str()
) {
if let (Some(name), Some(description)) =
(t["name"].as_str(), t["description"].as_str())
{
// Get just the first sentence of the description
let first_sentence = description
.split('.')
.next()
.unwrap_or(description)
.trim()
.to_string() + ".";
.to_string()
+ ".";

// Handle input_schema as either a string or an object
let input_schema = match &t["inputSchema"] {
Value::String(s) => Value::String(s.clone()),
Value::Object(o) => Value::Object(o.clone()),
_ => {
debug!("Invalid inputSchema format for tool {}: {:?}", name, t["inputSchema"]);
debug!(
"Invalid inputSchema format for tool {}: {:?}",
name, t["inputSchema"]
);
return None;
}
};
Expand All @@ -231,13 +250,20 @@ impl JetBrainsProxy {
}

pub async fn call_tool(&self, name: &str, args: Value) -> Result<CallToolResult> {
let endpoint = self.cached_endpoint.read().await
let endpoint = self
.cached_endpoint
.read()
.await
.clone()
.ok_or_else(|| anyhow!("No working IDE endpoint available"))?;

debug!("ENDPOINT: {} | Tool name: {} | args: {}", endpoint, name, args);
debug!(
"ENDPOINT: {} | Tool name: {} | args: {}",
endpoint, name, args
);

let response = self.client
let response = self
.client
.post(&format!("{}/mcp/{}", endpoint, name))
.json(&args)
.send()
Expand All @@ -253,7 +279,7 @@ impl JetBrainsProxy {
Value::Object(map) => {
let status = map.get("status").and_then(|v| v.as_str());
let error = map.get("error").and_then(|v| v.as_str());

match (status, error) {
(Some(s), None) => (false, s.to_string()),
(None, Some(e)) => (true, e.to_string()),
Expand Down Expand Up @@ -283,7 +309,7 @@ impl JetBrainsProxy {
pub async fn start(&self) -> Result<()> {
debug!("Initializing JetBrains Proxy...");
info!("Initializing JetBrains Proxy...");

// Initial endpoint check
debug!("Performing initial endpoint check...");
self.update_ide_endpoint().await;
Expand Down
2 changes: 1 addition & 1 deletion crates/goose-mcp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ mod developer;
mod jetbrains;

pub use developer::DeveloperRouter;
pub use jetbrains::JetBrainsRouter;
pub use jetbrains::JetBrainsRouter;
2 changes: 1 addition & 1 deletion crates/goose-server/src/commands/mcp.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use goose_mcp::{DeveloperRouter, JetBrainsRouter};
use mcp_server::router::RouterService;
use mcp_server::{ByteTransport, Server, BoundedService};
use mcp_server::{BoundedService, ByteTransport, Server};
use tokio::io::{stdin, stdout};

pub async fn run(name: &str) -> Result<()> {
Expand Down
29 changes: 16 additions & 13 deletions crates/mcp-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,24 +237,27 @@ where
}
}


// Define a specific service implementation that we need for any
// Any router implements this
pub trait BoundedService: Service<
pub trait BoundedService:
Service<
JsonRpcRequest,
Response = JsonRpcResponse,
Error = BoxError,
Future = Pin<Box<dyn Future<Output = Result<JsonRpcResponse, BoxError>> + Send>>
> + Send + 'static
{}
Future = Pin<Box<dyn Future<Output = Result<JsonRpcResponse, BoxError>> + Send>>,
> + Send
+ 'static
{
}

// Implement it for any type that meets the bounds
impl<T> BoundedService for T
where
impl<T> BoundedService for T where
T: Service<
JsonRpcRequest,
Response = JsonRpcResponse,
Error = BoxError,
Future = Pin<Box<dyn Future<Output = Result<JsonRpcResponse, BoxError>> + Send>>
> + Send + 'static
{}
JsonRpcRequest,
Response = JsonRpcResponse,
Error = BoxError,
Future = Pin<Box<dyn Future<Output = Result<JsonRpcResponse, BoxError>> + Send>>,
> + Send
+ 'static
{
}

0 comments on commit 108384c

Please sign in to comment.