fix(mcp): disambiguate same-name connections
This commit is contained in:
1 parent
3b1a9cb98b
commit
0674433eea
7 files changed
+483
-90
No files matched your search
@@ -15,6 +15,7 @@ const MCP_BRIDGE_PORT_FILE: &str = "mcp-bridge-port";
|
||||
#[derive(Deserialize)]
|
||||
struct OpenTableRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
schema: Option<String>,
|
||||
table: String,
|
||||
@@ -23,6 +24,7 @@ struct OpenTableRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct ExecuteQueryRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
sql: String,
|
||||
schema: Option<String>,
|
||||
@@ -33,6 +35,7 @@ struct ExecuteQueryRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct ListTablesRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
schema: Option<String>,
|
||||
}
|
||||
@@ -40,6 +43,7 @@ struct ListTablesRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct DescribeTableRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
schema: Option<String>,
|
||||
table: String,
|
||||
@@ -48,6 +52,7 @@ struct DescribeTableRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoFindDocumentsRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
skip: Option<u64>,
|
||||
@@ -60,12 +65,14 @@ struct MongoFindDocumentsRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoServerVersionRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct MongoCollectionStatsRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
scale: Option<serde_json::Number>,
|
||||
@@ -74,6 +81,7 @@ struct MongoCollectionStatsRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoAggregateDocumentsRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
pipeline_json: String,
|
||||
@@ -83,6 +91,7 @@ struct MongoAggregateDocumentsRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoCreateIndexRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
keys_json: String,
|
||||
@@ -92,6 +101,7 @@ struct MongoCreateIndexRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoDropIndexesRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
indexes_json: Option<String>,
|
||||
@@ -101,6 +111,7 @@ struct MongoDropIndexesRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoDropCollectionRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
}
|
||||
@@ -108,6 +119,7 @@ struct MongoDropCollectionRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoInsertDocumentsRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
docs_json: String,
|
||||
@@ -116,6 +128,7 @@ struct MongoInsertDocumentsRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoUpdateDocumentsRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
filter_json: String,
|
||||
@@ -126,6 +139,7 @@ struct MongoUpdateDocumentsRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct MongoDeleteDocumentsRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
database: Option<String>,
|
||||
collection: String,
|
||||
filter_json: String,
|
||||
@@ -135,6 +149,7 @@ struct MongoDeleteDocumentsRequest {
|
||||
#[derive(Deserialize)]
|
||||
struct RedisCommandRequest {
|
||||
connection_name: String,
|
||||
connection_id: Option<String>,
|
||||
db: u32,
|
||||
command: String,
|
||||
skip_safety_check: Option<bool>,
|
||||
@@ -295,17 +310,21 @@ async fn respond_error(stream: &mut tokio::net::TcpStream, status: &str, message
|
||||
|
||||
async fn resolve_connection(
|
||||
state: &Arc<AppState>,
|
||||
connection_id: Option<&str>,
|
||||
connection_name: &str,
|
||||
) -> Result<crate::models::connection::ConnectionConfig, String> {
|
||||
let configs = state.storage.load_connections().await.map_err(|e| e.to_string())?;
|
||||
let config =
|
||||
find_config_by_name(&configs, connection_name).ok_or_else(|| "Connection not found".to_string())?.clone();
|
||||
let config = if let Some(id) = connection_id.filter(|s| !s.is_empty()) {
|
||||
configs.iter().find(|c| c.id == id).ok_or_else(|| format!("Connection with id '{}' not found", id))?
|
||||
} else {
|
||||
find_config_by_name(&configs, connection_name).ok_or_else(|| "Connection not found".to_string())?
|
||||
};
|
||||
let mut state_configs = state.configs.write().await;
|
||||
if !state_configs.contains_key(&config.id) {
|
||||
state_configs.insert(config.id.clone(), config.clone());
|
||||
}
|
||||
drop(state_configs);
|
||||
Ok(config)
|
||||
Ok(config.clone())
|
||||
}
|
||||
|
||||
fn check_visible_database(config: &crate::models::connection::ConnectionConfig, database: &str) -> Result<(), String> {
|
||||
@@ -319,11 +338,12 @@ fn check_visible_database(config: &crate::models::connection::ConnectionConfig,
|
||||
|
||||
async fn resolve_mongo_pool_key(
|
||||
state: &Arc<AppState>,
|
||||
connection_id: Option<&str>,
|
||||
connection_name: &str,
|
||||
database: Option<String>,
|
||||
stream: &mut tokio::net::TcpStream,
|
||||
) -> Option<(String, String, String)> {
|
||||
let config = match resolve_connection(state, connection_name).await {
|
||||
let config = match resolve_connection(state, connection_id, connection_name).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
respond_error(stream, "404 Not Found", &e).await;
|
||||
@@ -350,17 +370,13 @@ async fn handle_open_table(app: &AppHandle, state: &Arc<AppState>, body: &str, s
|
||||
return;
|
||||
}
|
||||
};
|
||||
let configs = match state.storage.load_connections().await {
|
||||
let config = match resolve_connection(state, req.connection_id.as_deref(), &req.connection_name).await {
|
||||
Ok(c) => c,
|
||||
Err(_) => {
|
||||
respond(stream, "500 Internal Server Error", "").await;
|
||||
Err(e) => {
|
||||
respond(stream, "404 Not Found", &e).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
let Some(config) = find_config_by_name(&configs, &req.connection_name) else {
|
||||
respond(stream, "404 Not Found", "Connection not found").await;
|
||||
return;
|
||||
};
|
||||
let event = McpOpenTableEvent {
|
||||
connection_id: config.id.clone(),
|
||||
database: req.database.unwrap_or_else(|| config.database.clone().unwrap_or_default()),
|
||||
@@ -379,17 +395,13 @@ async fn handle_execute_query(app: &AppHandle, state: &Arc<AppState>, body: &str
|
||||
return;
|
||||
}
|
||||
};
|
||||
let configs = match state.storage.load_connections().await {
|
||||
let config = match resolve_connection(state, req.connection_id.as_deref(), &req.connection_name).await {
|
||||
Ok(c) => c,
|
||||
Err(_) => {
|
||||
respond(stream, "500 Internal Server Error", "").await;
|
||||
Err(e) => {
|
||||
respond(stream, "404 Not Found", &e).await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
let Some(config) = find_config_by_name(&configs, &req.connection_name) else {
|
||||
respond(stream, "404 Not Found", "Connection not found").await;
|
||||
return;
|
||||
};
|
||||
let event = McpExecuteQueryEvent {
|
||||
connection_id: config.id.clone(),
|
||||
database: req.database.unwrap_or_else(|| config.database.clone().unwrap_or_default()),
|
||||
@@ -409,7 +421,7 @@ async fn handle_list_tables_data(state: &Arc<AppState>, body: &str, stream: &mut
|
||||
return;
|
||||
}
|
||||
};
|
||||
let config = match resolve_connection(state, &req.connection_name).await {
|
||||
let config = match resolve_connection(state, req.connection_id.as_deref(), &req.connection_name).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
respond_error(stream, "404 Not Found", &e).await;
|
||||
@@ -436,7 +448,7 @@ async fn handle_describe_table_data(state: &Arc<AppState>, body: &str, stream: &
|
||||
return;
|
||||
}
|
||||
};
|
||||
let config = match resolve_connection(state, &req.connection_name).await {
|
||||
let config = match resolve_connection(state, req.connection_id.as_deref(), &req.connection_name).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
respond_error(stream, "404 Not Found", &e).await;
|
||||
@@ -464,7 +476,7 @@ async fn handle_mongo_list_collections_data(state: &Arc<AppState>, body: &str, s
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, _connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -483,7 +495,7 @@ async fn handle_mongo_find_documents_data(state: &Arc<AppState>, body: &str, str
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, _connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -514,7 +526,7 @@ async fn handle_mongo_server_version_data(state: &Arc<AppState>, body: &str, str
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, _connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -533,7 +545,7 @@ async fn handle_mongo_collection_stats_data(state: &Arc<AppState>, body: &str, s
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, _connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -554,7 +566,7 @@ async fn handle_mongo_aggregate_documents_data(state: &Arc<AppState>, body: &str
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, _connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -582,7 +594,7 @@ async fn handle_mongo_create_index_data(state: &Arc<AppState>, body: &str, strea
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -614,7 +626,7 @@ async fn handle_mongo_drop_indexes_data(state: &Arc<AppState>, body: &str, strea
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -646,7 +658,7 @@ async fn handle_mongo_drop_collection_data(state: &Arc<AppState>, body: &str, st
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -669,7 +681,7 @@ async fn handle_mongo_insert_documents_data(state: &Arc<AppState>, body: &str, s
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -694,7 +706,7 @@ async fn handle_mongo_update_documents_data(state: &Arc<AppState>, body: &str, s
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -727,7 +739,7 @@ async fn handle_mongo_delete_documents_data(state: &Arc<AppState>, body: &str, s
|
||||
}
|
||||
};
|
||||
let Some((pool_key, database, connection_id)) =
|
||||
resolve_mongo_pool_key(state, &req.connection_name, req.database, stream).await
|
||||
resolve_mongo_pool_key(state, req.connection_id.as_deref(), &req.connection_name, req.database, stream).await
|
||||
else {
|
||||
return;
|
||||
};
|
||||
@@ -758,7 +770,7 @@ async fn handle_redis_execute_command_data(state: &Arc<AppState>, body: &str, st
|
||||
return;
|
||||
}
|
||||
};
|
||||
let config = match resolve_connection(state, &req.connection_name).await {
|
||||
let config = match resolve_connection(state, req.connection_id.as_deref(), &req.connection_name).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
respond_error(stream, "404 Not Found", &e).await;
|
||||
@@ -809,7 +821,7 @@ async fn handle_execute_query_data(state: &Arc<AppState>, body: &str, stream: &m
|
||||
return;
|
||||
}
|
||||
};
|
||||
let config = match resolve_connection(state, &req.connection_name).await {
|
||||
let config = match resolve_connection(state, req.connection_id.as_deref(), &req.connection_name).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
respond_error(stream, "404 Not Found", &e).await;
|
||||
|
||||
Reference in new issue
Block a user