Gemini Code Assist 'agent' mode without `npx mcp-remote` (2/3)
- 4 minutes read - 653 wordsSolved!
Ugh.
Before I continue, one important detail from yesterday’s experience which I think I didn’t clarify is that, unlike the Copilot agent, it appears (!?) that Gemini agent only supports integration with MCP servers via stdio. As a result, the only way to integrate with HTTP-based MCP servers (local or remote) is to proxy traffic through stdio as mcp-remote
and the Rust example herein.
The most helpful change was to take a hint from the NPM mcp-remote
and create a log file. This helps because, otherwise the mcp-remote
process, because it’s launched by Visual Studio Code, well Gemini Code Assist agent, isn’t trivial to debug.
The solution involves not double-printing the request and filtering empty responses. As I progressed through the solution, I began receiving the following error and I learned that JSON-RPC notification messages should not receive a response. mcp-remote
was sending an empty body:
MCP ERROR (wrapper): SyntaxError: Unexpected end of JSON input
Add chrono
to write log timestamps:
Cargo.toml
:
[package]
name = "mcp-remote"
version = "0.0.1"
edition = "2024"
[dependencies]
chrono = "0.4.41"
reqwest = { version = "0.11", features = ["json", "rustls-tls"], default-features = false }
tokio = { version = "1", features = ["full"] }
main.rs
:
use chrono::Utc;
use std::collections::hash_map::DefaultHasher;
use std::env;
use std::fs::OpenOptions;
use std::hash::{Hash, Hasher};
use std::io::{self, BufRead, BufReader, Write};
use reqwest;
use tokio;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: {} <remote-mcp-url> [--insecure]", args[0]);
std::process::exit(1);
}
let remote_url = &args[1];
let insecure = args.len() > 2 && args[2] == "--insecure";
// Create a log file name from a hash of the remote_url
let mut hasher = DefaultHasher::new();
remote_url.hash(&mut hasher);
let hash = hasher.finish();
let log_filename = format!("mcp-remote-{}.log", hash);
// Open the log file in append mode
let mut log_file = OpenOptions::new()
.create(true)
.append(true)
.open(&log_filename)?;
eprintln!("Logging requests and responses to {}", log_filename);
let client = reqwest::Client::builder()
.danger_accept_invalid_certs(insecure)
.build()?;
let stdin = io::stdin();
let reader = BufReader::new(stdin.lock());
for line in reader.lines() {
let line = line?;
// Write the request to the log
writeln!(log_file, "[{}] Request:\n{}", Utc::now(), &line)?;
// The request has been printed to stdio by the user
// No need to write it again
// print!("{}", line);
// Forward the JSON-RPC message to the remote server
let response = client
.post(remote_url)
.header("Content-Type", "application/json")
.body(line)
.send()
.await?;
let body = response.text().await?;
// Write the response to the log
writeln!(log_file, "[{}] Response:\n{}", Utc::now(), &body)?;
// But only write non-empty trimmed responses to stdio
if !body.trim().is_empty() {
println!("{}", body);
}
}
Ok(())
}
And then:
~/.gemini/settings.json
:
{
"mcpServers": {
"ackal-mcp-server": {
"command": "/path/to/mcp-remote",
"args": [
"http://localhost:7777/mcp"
]
}
}
And, this now works!! Well, I continue to receive the following error but it doesn’t appear (!?) to inhibit the proxy from functioning:
MCP ERROR (prometheus-mcp-server): SyntaxError: Unexpected end of JSON input
A second problem was more subtle and possibly compounded by my insistence on not wanting to install Node.JS on my host.
On a Chromebook (running Linux), I was able to get Node.JS running under Podman working as a proxy:
~/.gemini/settings.json
"
{
"mcpServers": {
"prometheus-mcp-server": {
"command": "podman",
"args": [
"run",
"--rm","--interactive",
"node:24.3.0-alpine",
"npx",
"--yes",
"mcp-remote",
"http://localhost:7777/mcp",
"--allow-http"
]
}
}
}
But, when I tried this on my (Ubuntu) machine, it continued to fail:
[CoderAgentExecutor] Overriding workspace path to: /path/to/ackal-mcp-server
failed to start or connect to MCP server 'ackal-mcp-server' {"command":"podman"};
McpError: MCP error -32000: Connection closed
And I could not understand the difference until I tracked down CoderAgentExecutor
as agent.mjs
:
ps aux | grep [a]gent
/snap/code-insiders/2014/usr/share/code-insiders/code-insiders /path/to/google.geminicodeassist-2.38.0-insiders.3/agent/agent.mjs
/snap/code-insiders/2014/usr/share/code-insiders/code-insiders /path/to/google.geminicodeassist-2.39.0-insiders.0/agent/agent.mjs
/snap/code-insiders/2014/usr/share/code-insiders/code-insiders /path/to/google.geminicodeassist-2.39.0-insiders.0/agent/agent.mjs
The critical element here is /snap/code-insiders/...
because I’m running Visual Studio Code as a Snap and, having experienced security challenges with Snap in the past, I suspect this is the cause; Visual Studio Code is not permitted to invoke Podman.
In good news, Visual Studio Code is able to invoke the Rust binary generated from the above.
And so I may now: