use std::path::{Path, PathBuf};
use github_mcp::data::store::{VERSION_STORE_FILES, open_store_read_write};
use github_mcp::services::embedding_service::embed;
struct EndpointRow {
operation_id: String,
path: String,
method: String,
summary: Option<String>,
description: Option<String>,
}
fn vector_to_le_bytes(vector: &[f32]) -> Vec<u8> {
vector
.iter()
.flat_map(|value| value.to_le_bytes())
.collect()
}
fn populate_one(path: &Path) -> anyhow::Result<usize> {
let conn = open_store_read_write(path)?;
let mut select =
conn.prepare("SELECT operation_id, path, method, summary, description FROM endpoints")?;
let rows: Vec<EndpointRow> = select
.query_map([], |row| {
Ok(EndpointRow {
operation_id: row.get(0)?,
path: row.get(1)?,
method: row.get(2)?,
summary: row.get(3)?,
description: row.get(4)?,
})
})?
.collect::<Result<_, _>>()?;
let mut delete = conn.prepare("DELETE FROM semantic_endpoints WHERE operation_id = ?1")?;
let mut insert =
conn.prepare("INSERT INTO semantic_endpoints (operation_id, embedding) VALUES (?1, ?2)")?;
let count = rows.len();
for row in rows {
let text = [
Some(row.method),
Some(row.path),
row.summary,
row.description,
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.join(" ");
let vector = embed(&text)?;
delete.execute(rusqlite::params![row.operation_id])?;
insert.execute(rusqlite::params![
row.operation_id,
vector_to_le_bytes(&vector)
])?;
}
Ok(count)
}
fn targets() -> Vec<PathBuf> {
let mut args = std::env::args().skip(1);
match args.next().as_deref() {
Some("--all") => VERSION_STORE_FILES
.iter()
.map(|(_, file)| PathBuf::from(file))
.collect(),
Some(path) => vec![PathBuf::from(path)],
None => vec![PathBuf::from("mcp_store.db")],
}
}
fn main() -> anyhow::Result<()> {
for path in targets() {
let count = populate_one(&path)?;
println!(
"populated embeddings for {count} operation(s) in '{}'",
path.display()
);
}
Ok(())
}