Skip to content

To implement MCP functionality and chat functionality, libvault is used.#6

Closed
wujian0327 wants to merge 41 commits intogitmono-dev:mainfrom
wujian0327:main
Closed

To implement MCP functionality and chat functionality, libvault is used.#6
wujian0327 wants to merge 41 commits intogitmono-dev:mainfrom
wujian0327:main

Conversation

@wujian0327
Copy link
Contributor

Start mcp server

To start a MegaEngine node with MCP enabled, launch the node as usual and add the --mcp flag, for example:

cargo run -- node start --alias node1 --addr 127.0.0.1:9000 --cert-path cert --mcp

if you also want an MCP SSE endpoint, add --mcp-sse-port 3001 (or another port), such as:

cargo run -- node start --alias node1 --addr 127.0.0.1:9000 --cert-path cert --mcp --mcp-sse-port 3001

Send a message to node1:

cargo run -- chat send --to <node1_did> --msg "hello from node2"

Use libvault

Generate certificates using libvault

wujian0327 and others added 30 commits November 14, 2025 18:47
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 13, 2026 08:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces MCP (stdio + SSE) endpoints and an encrypted P2P chat feature on top of the existing MegaEngine node/gossip/QUIC stack, while also migrating certificate generation to libvault and expanding repository metadata persisted in SQLite.

Changes:

  • Add MCP server support (stdio JSON-RPC and SSE/HTTP) with repo tools (list/details/clone).
  • Add encrypted P2P chat messages over gossip + local persistence (chat_messages) and CLI commands (chat send/list).
  • Update storage schema/models for richer repo metadata and refs; switch certificate generation from rcgen to libvault/OpenSSL.

Reviewed changes

Copilot reviewed 36 out of 38 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
tests/gossip_three_nodes.rs Updates test cert file names and adds cert cleanup.
tests/git_pack.rs Minor Command::args idiom updates.
tests/bundle_two_nodes.rs Small Rust idiom cleanups and cert cleanup at end of test.
src/transport/quic.rs Improves close logging and serializes tests to avoid cert/test collisions; adds cleanup helper and new test.
src/transport/config.rs Uses rustls crypto provider schemes and adds QUIC transport keepalive/idle timeout config for clients.
src/transport/cert.rs Replaces rcgen with libvault + OpenSSL for CA/server cert generation; adds unit tests.
src/storage/repo_model.rs Switches DB init to pooled getter and expands repo model fields (language/size/latest_commit_at); adjusts tests.
src/storage/ref_model.rs Changes refs table to composite primary key and adds created_at; updates CRUD queries accordingly.
src/storage/node_model.rs Switches DB access from init_db to get_db_conn.
src/storage/mod.rs Replaces init_db with get_db_conn, adds chat_messages table creation, updates schema DDL.
src/storage/chat_message.rs New SeaORM entity + helpers for persisted chat message queue/status updates.
src/repo/repo_manager.rs Updates tests for new repo description fields.
src/repo/repo.rs Updates P2PDescription to include language/size/latest_commit_at and updates tests.
src/node/node_manager.rs Removes NodeManager module and its tests.
src/node/node_id.rs Minor test cleanup (borrow elision).
src/node/node.rs Minor assertion idiom cleanup in tests.
src/node/mod.rs Removes node_manager module export.
src/mcp/sse_server.rs Adds Axum-based SSE server + /messages JSON-RPC bridge for MCP tools.
src/mcp/mod.rs New MCP module exports (stdio + SSE server starters).
src/mcp/mcp_server.rs Adds stdio JSON-RPC MCP server and repo tool implementations.
src/main.rs Adds chat and mcp CLI commands and routes tracing output to stderr.
src/lib.rs Exposes new chat and mcp modules from the library crate.
src/identity/keypair.rs Adds ECIES-like encryption/decryption for chat using Ed25519→X25519 conversion and ChaCha20-Poly1305.
src/gossip/service.rs Integrates chat + chat ack processing; moves Envelope type to message module; adds verbose ref update logging.
src/gossip/message.rs Adds chat message/ack types and a shared Envelope; changes hashing canonicalization.
src/git/pack.rs Adds post-clone checkout/reset steps to better materialize working tree from bundles.
src/git/git_repo.rs Reads both local and remote refs; adds helper to read latest commit time.
src/cli/repo.rs Adds language/size/latest_commit_at computation, improves listing output, and improves error reporting.
src/cli/node.rs Adds node flags to start MCP stdio server and optional MCP SSE server; starts chat sender background task.
src/cli/mod.rs Wires new chat command handler.
src/cli/chat.rs New CLI for queuing chat messages and listing chat history from DB.
src/chat/service.rs New chat sender task (DB-backed queue) + incoming chat/ack handlers over gossip.
src/chat/mod.rs New chat module export.
src/bundle/transfer.rs Improves chunked transfer to support out-of-order writes via seek and truncation on start.
README.md Documents chat usage.
Cargo.toml Adds dependencies: libvault/openssl/axum/tower-http/uuid/futures/tokio-stream/chacha20poly1305/curve25519-dalek; removes rcgen.
Cargo.lock Updates lockfile for new dependencies.
.gitignore Fixes tmp ignore path and adds dist/.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 151 to 160
pub async fn update_repo_bundle(repo_id: &str, bundle_path: &str) -> Result<()> {
let db = init_db().await?;
let now = chrono::Local::now().timestamp();
let db = get_db_conn().await?;

// 查询是否存在
if let Some(model) = Entity::find_by_id(repo_id).one(&db).await? {
let active_model = ActiveModel {
id: Unchanged(model.id),
bundle: Set(bundle_path.to_string()),
updated_at: Set(now),
updated_at: Unchanged(model.updated_at),
// Keep other fields unchanged
ttl: DEFAULT_TTL,
};
tracing::debug!("Broadcasting NodeAnnouncement: {:?}", env);
tracing::debug!("Broadcasting NodeAnnouncement: {:?}", env);
}

tokio::time::sleep(Duration::from_secs(30)).await;
tokio::time::sleep(Duration::from_secs(30)).await;
Comment on lines +116 to +123
tracing::info!("MCP server enabled, starting alongside node");
println!("MCP server is enabled");
std::thread::spawn(|| {
let rt = tokio::runtime::Runtime::new().unwrap();
if let Err(e) = rt.block_on(start_mcp_server()) {
tracing::error!("MCP server error: {}", e);
}
});
ttl: DEFAULT_TTL,
};
tracing::debug!("Broadcasting RepoAnnouncement: {:?}", env);
tracing::debug!("Broadcasting RepoAnnouncement: {:?}", env);
Comment on lines +35 to +39
let app = Router::new()
.route("/sse", get(sse_handler))
.route("/messages", post(message_handler))
.layer(CorsLayer::permissive())
.with_state(state);
Comment on lines +54 to +60
// Store the sender
state
.sessions
.write()
.await
.insert(session_id.clone(), tx.clone());

Comment on lines +126 to +134
if let Some(port) = mcp_sse_port {
tracing::info!("MCP SSE server enabled on port {}", port);
println!("MCP SSE server enabled on port {}", port);
tokio::spawn(async move {
let addr = std::net::SocketAddr::from(([0, 0, 0, 0], port));
if let Err(e) = start_sse_server(addr).await {
tracing::error!("MCP SSE server error: {}", e);
}
});
Comment on lines +89 to 96
let path = db_path();

{
let map = pool.lock().await;
if let Some(db) = map.get(&path) {
return Ok(db.clone());
}
}
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e95d8f6d30

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +121 to +125
"CREATE TABLE IF NOT EXISTS repos (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
creator TEXT NOT NULL,
description TEXT NOT NULL,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add migration for existing repos schema

This change introduces new repos columns (language, size, latest_commit_at) but only executes CREATE TABLE IF NOT EXISTS repos (...). For users upgrading from the previous schema, SQLite keeps the old table definition, and later SeaORM reads/writes against the new model will fail with missing-column errors, breaking repo load/list flows after upgrade. Add an explicit migration/ALTER TABLE path before using the new fields.

Useful? React with 👍 / 👎.

Comment on lines +182 to +185
let envelope = Envelope {
payload: signed_msg,
ttl: TTL,
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Stop resetting TTL when relaying chat

When a chat message is not for the current node, this code re-wraps and rebroadcasts it with ttl: TTL (16). GossipService::handle_incoming already forwards handled messages with decremented TTL, so this extra relay path both duplicates each hop and reintroduces fresh TTL, which can cause persistent message amplification/loops in multi-hop networks.

Useful? React with 👍 / 👎.

Comment on lines +123 to +126
let _ = mgr.send_gossip_message(receiver_node_id.clone(), data.clone()).await;
} else {
for peer in peers {
let _ = mgr.send_gossip_message(peer.clone(), data.clone()).await;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Return error when gossip send fails

Both send paths ignore send_gossip_message failures (let _ = ...), but callers treat try_send_pending_msg success as delivery progress and move DB status from Sending to Sent. If connections are stale or writes fail, the message is incorrectly marked sent and is no longer retried, causing silent message loss.

Useful? React with 👍 / 👎.

Comment on lines 102 to +103
tokio::time::sleep(Duration::from_secs(30)).await;
tokio::time::sleep(Duration::from_secs(30)).await;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove duplicate sleep in gossip loop

The broadcaster loop now sleeps twice for 30 seconds each cycle, effectively doubling the announcement period from 30s to about 60s. That slows node/repository gossip convergence and delays propagation compared with the intended interval.

Useful? React with 👍 / 👎.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@wujian0327
Copy link
Contributor Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds MCP support (stdio + SSE), introduces an encrypted P2P chat feature, and switches certificate generation to libvault/OpenSSL while extending the local SQLite schema and repo metadata.

Changes:

  • Add MCP servers: stdio JSON-RPC (mcp) and an Axum-based SSE/HTTP endpoint (--mcp-sse-port).
  • Add P2P chat: CLI commands + DB-backed outgoing queue + gossip message types + encryption helpers.
  • Update transport/storage: libvault-based cert generation, QUIC client transport tweaks, repo/ref schema changes, and improved bundle chunk writing.

Reviewed changes

Copilot reviewed 36 out of 38 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
tests/gossip_three_nodes.rs Update test cert filenames and add cleanup.
tests/git_pack.rs Minor Rust idiom cleanup for Command::args.
tests/bundle_two_nodes.rs Minor iterator/strings cleanup; add cert cleanup.
src/transport/quic.rs Improve connection close logging; serialize some transport tests; add cert cleanup + new test.
src/transport/config.rs Make verifier schemes provider-driven; add QUIC client keepalive/idle timeout config.
src/transport/cert.rs Replace rcgen with libvault/OpenSSL cert generation + add tests.
src/storage/repo_model.rs Extend repo DB model (language/size/latest_commit_at) + use get_db_conn.
src/storage/ref_model.rs Change refs primary key strategy and add created_at; update queries.
src/storage/node_model.rs Switch DB access to get_db_conn.
src/storage/mod.rs Replace init_db with pooled get_db_conn; update/create tables (incl. chat_messages).
src/storage/chat_message.rs New SeaORM entity + helpers for chat message persistence.
src/repo/repo_manager.rs Update tests for new repo description fields.
src/repo/repo.rs Update repo description struct + tests for new fields.
src/node/node_manager.rs Remove NodeManager module and tests.
src/node/node_id.rs Minor API usage cleanup in tests.
src/node/node.rs Minor assertion style cleanup in tests.
src/node/mod.rs Stop exporting removed node_manager module.
src/mcp/sse_server.rs New Axum SSE MCP endpoint + message handler.
src/mcp/mod.rs New MCP module exports.
src/mcp/mcp_server.rs New stdio MCP JSON-RPC server and repo tools.
src/main.rs Add CLI commands: chat and mcp; route tracing output to stderr.
src/lib.rs Export new chat and mcp modules.
src/identity/keypair.rs Add chat encryption/decryption helpers (Curve25519 + ChaCha20Poly1305).
src/gossip/service.rs Add chat message handling; move Envelope type; add extra logging (with some duplicates).
src/gossip/message.rs Add chat/ack message types; add shared Envelope; adjust hashing canonicalization.
src/git/pack.rs Add post-clone checkout/reset steps when restoring from bundles.
src/git/git_repo.rs Include remote branch refs; add latest commit time helper.
src/cli/repo.rs Add language/size/latest_commit_at; improve repo list UX and status output.
src/cli/node.rs Start chat sender task; add --mcp and --mcp-sse-port node options.
src/cli/mod.rs Export chat CLI handler.
src/cli/chat.rs New chat send and chat list commands (DB-backed queue/history).
src/chat/service.rs New chat send/receive/ack logic integrated with gossip + DB queue processing.
src/chat/mod.rs New chat module.
src/bundle/transfer.rs Write chunks by offset (seek) and ensure file truncation at start.
README.md Document new chat command usage.
Cargo.toml Add dependencies: libvault/openssl/axum/tower-http/uuid/crypto crates.
Cargo.lock Dependency lock updates for new crates.
.gitignore Ignore dist/ and adjust tmp ignore pattern.
Comments suppressed due to low confidence (1)

src/transport/cert.rs:146

  • If the CA cert/key are missing or regenerated (e.g. CA key deleted), generate_ca_cert() will create a new CA, but ensure_certificates() will NOT regenerate an existing server cert/key pair (cert_exists && key_exists stays true). That can leave a server cert signed by an old CA while clients trust the new CA, causing TLS failures. Consider detecting CA regeneration (or missing CA key) and forcing server cert/key regeneration in that case.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 102 to +103
tokio::time::sleep(Duration::from_secs(30)).await;
tokio::time::sleep(Duration::from_secs(30)).await;
Comment on lines +189 to +209
if msg.receiver_id != *my_node.node_id() {
tracing::info!("Message not for me, forwarding to {}", msg.receiver_id);

// Construct the payload to forward
let gossip_msg = GossipMessage::Chat(msg.clone());

let mut signed_msg = SignedMessage {
node_id: my_node.node_id().clone(),
message: gossip_msg,
timestamp: timestamp_now(),
signature: "".to_string(),
};
let self_hash = signed_msg.self_hash();
let sign = my_node.sign_message(self_hash.as_slice())?;
signed_msg.signature = hex::encode(sign);

let envelope = Envelope {
payload: signed_msg,
ttl: TTL,
};
let data = serde_json::to_vec(&envelope)?;
Comment on lines +54 to +60
// Store the sender
state
.sessions
.write()
.await
.insert(session_id.clone(), tx.clone());

}
}
// Handle other JSON-RPC methods or notifications if needed
_ => None,
Comment on lines 156 to 160
let active_model = ActiveModel {
id: Unchanged(model.id),
bundle: Set(bundle_path.to_string()),
updated_at: Set(now),
updated_at: Unchanged(model.updated_at),
// Keep other fields unchanged
Comment on lines +132 to +143
// Format result as MCP CallToolResult with text content
let content_text = result_value.to_string();
Some(json!({
"jsonrpc": "2.0",
"id": request.get("id"),
"result": {
"content": [{
"type": "text",
"text": content_text
}],
"isError": false
}
Comment on lines +299 to +333
tracing::info!("ACK not for me (for {}), forwarding", ack.target_id);

// Construct the payload to forward
let gossip_msg = GossipMessage::ChatAck(ack.clone());

let mut signed_msg = SignedMessage {
node_id: my_node.node_id().clone(),
message: gossip_msg,
timestamp: timestamp_now(),
signature: "".to_string(),
};
let self_hash = signed_msg.self_hash();
let sign = my_node.sign_message(self_hash.as_slice())?;
signed_msg.signature = hex::encode(sign);

let envelope = Envelope {
payload: signed_msg,
ttl: TTL,
};
let data = serde_json::to_vec(&envelope)?;

let mgr = manager.lock().await;
let peers = mgr.list_peers().await;

if peers.contains(&ack.target_id) {
tracing::info!("Found target {} in neighbors, sending ACK directly", ack.target_id);
let _ = mgr.send_gossip_message(ack.target_id.clone(), data).await;
} else {
tracing::info!("Target {} not in neighbors, broadcasting ACK", ack.target_id);
for peer in peers {
if peer != ack.sender_id {
let _ = mgr.send_gossip_message(peer.clone(), data.clone()).await;
}
}
}
Comment on lines +35 to +39
let app = Router::new()
.route("/sse", get(sse_handler))
.route("/messages", post(message_handler))
.layer(CorsLayer::permissive())
.with_state(state);
Comment on lines +91 to 96
{
let map = pool.lock().await;
if let Some(db) = map.get(&path) {
return Ok(db.clone());
}
}
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@wujian0327 wujian0327 closed this Mar 13, 2026
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 00cd2745c0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +372 to +375
GossipMessage::Chat(c) => {
if let Err(e) = crate::chat::service::process_incoming_chat(
c.clone(),
self.manager.clone(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Validate chat sender against signed envelope

handle_incoming verifies the outer signature with signed.node_id, but this chat branch forwards c without checking that c.sender_id matches that authenticated signer. A malicious peer can sign with its own key while setting sender_id to someone else, and downstream handling will treat the spoofed sender as genuine. Add an explicit signer/sender consistency check before accepting or forwarding chat messages.

Useful? React with 👍 / 👎.

Comment on lines +339 to +342
crate::storage::chat_message::update_message_status(
&ack.msg_id,
MessageStatus::Delivered,
)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject unauthenticated ACKs before marking delivered

process_ack marks a message as Delivered using only ack.msg_id and ack.target_id, but it never verifies that the ACK actually came from the original recipient (or that ack.signature is valid). Since msg_id is visible in relayed chat envelopes, an intermediate peer can forge an ACK and force false delivery state. Validate ACK provenance against the authenticated sender and expected recipient before updating status.

Useful? React with 👍 / 👎.

tracing::info!("Received Chat from {}: {}", msg.sender_id.0, content);

// 3. Store
let db = crate::storage::get_db_conn().await.unwrap();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove panic on DB init failure in chat receive path

This unwrap() turns any transient database error into a panic during chat receive handling. Because it runs inside the gossip processing task, a DB open failure can crash that task and stop processing subsequent gossip/chat messages. Propagate the error (or handle it explicitly) instead of panicking here.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants