MCPのRust SDKを使ってみた
MCPのRust SDKでDocComment生成ツールを作ってみた
背景
関数や構造体、enum を作ったり修正したときに「あとでちゃんと doc comment 書こう」と思っても、PR作る直前になって、まあいっかとなってしまうことがよくあります。
それなら自動で書いてくれたら助かるなと思って、今回その仕組みを Rust SDK + MCP で作ってみました。とはいえ、正直これ Cursor の .cursorrules
使えばもっと簡単にできると思います。
今回はあくまで MCP や公式 Rust SDK の使い方を勉強してみたかったのが主な目的です。
MCP には Prompts / Tools / Resources
といった機能があって、最初は Prompts
を使おうとしてたんですが、挙動がよくわからなかったので、最終的には example を参考にして Tools
機能だけで組んでます。
実装
リポジトリ
実装コードは以下で公開しています。
ファイル構成
scribe-crab/
├── src/
│ ├── main.rs
│ └── doc_generator.rs
├── .format.md
├── Cargo.toml
doc_generator.rs
use std::{env, fs};
use rmcp::{
Error as McpError,
ServerHandler,
const_string,
model::{*, tool::{CallToolResult}},
tool,
};
#[derive(Debug, Clone)]
pub struct DocGenerator;
#[tool(tool_box)]
impl DocGenerator {
pub fn new() -> Self {
Self {}
}
#[tool(description = "Generate a documentation comment using the format in FORMAT_PATH")]
fn generate_doc_comment(
&self,
#[tool(param, description = "The Rust function code to document")] code: String,
) -> Result<CallToolResult, McpError> {
let format_path = env::var("FORMAT_PATH")
.map_err(|_| McpError::internal_error("FORMAT_PATH is not set", None))?;
let format = fs::read_to_string(&format_path)
.map_err(|e| McpError::internal_error("Failed to read format file", Some(e.to_string().into())))?;
let prompt = format!(
"Use the following documentation format:\n\n{}\n\nNow write a documentation comment for this function:\n\n{}",
format, code
);
Ok(CallToolResult::success(vec![Content::text(prompt)]))
}
}
const_string!(GenerateDocComment = "generate_doc_comment");
#[tool(tool_box)]
impl ServerHandler for DocGenerator {
fn get_info(&self) -> ServerInfo {
ServerInfo {
protocol_version: ProtocolVersion::V_2024_11_05,
capabilities: ServerCapabilities::builder()
.enable_tools()
.build(),
server_info: Implementation::from_build_env(),
instructions: Some("Generates doc comments for Rust functions using a format file".into()),
}
}
}
main.rs
use scribe_crab::doc_generator::DocGenerator;
use rmcp::transport::stdio;
use tracing_subscriber::fmt::init;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
init();
let server = DocGenerator::new();
let transport = stdio::stdio();
server.serve(transport).await?.waiting().await?;
Ok(())
}
.format.md
/// 概要
///
/// # 引数
///
/// # 戻り値
///
/// # 主な利用シーン
///
開発中のつまずきポイント
.env
が読み込まれない問題
最初 dotenvy
で .env
に FORMAT_PATH=.format.md
を書いてのですが、MCPサーバーが Cursor から起動されると .env
がなぜか読み込んでくれなかったです。理由はちょっとよくわかりません。。。
mcp.json
で環境変数を指定
対処: {
"mcpServers": {
"scribe-crab": {
"command": "/path/to/scribe-crab",
"cwd": "/path/to/scribe-crab",
"env": {
"FORMAT_PATH": "/path/to/scribe-crab/.format.md"
}
}
}
}
補足
このツールは doc comment を直接生成するのではなく、「こういうフォーマットでこのコードのdocを書いてね」という Cursor Agent
に指示してあげるだけです。最終的な生成は LLM 側に任せる構成です。
そしてLLMがその結果を元にコメントを生成してくれる感じになります。
普通に .cursorrules
にフォーマット定義して、生成してもらうほうが断然いいと思います;;
まとめ
最低限の構成でも MCP サーバーを立てるだけなら割と簡単で、Rust SDK の使い方も少し学べました。Prompsとかほんとは使ってみたかったんですけどね。
完全に自分用メモですが、同じような構成で何か作る人の参考になれば嬉しいです。
Discussion