proto_cli 0.58.1

A multi-language version manager, a unified toolchain.
use crate::mcp::ProtoMcp;
use crate::session::{ProtoSession, SessionResult};
use clap::Args;
use iocraft::prelude::element;
use miette::IntoDiagnostic;
use rmcp::model::InitializeResult;
use rmcp::{ServerHandler, ServiceExt, transport::stdio};
use serde::Serialize;
use starbase_console::ui::*;
use tracing::instrument;

#[derive(Args, Clone, Debug)]
pub struct McpArgs {
    #[arg(
        long,
        help = "Display server information and list available tools and resources"
    )]
    info: bool,
}

#[derive(Serialize)]
pub struct McpOutput {
    info: InitializeResult,
    tools: Vec<rmcp::model::Tool>,
    resources: Vec<rmcp::model::Resource>,
}

#[instrument(skip(session))]
pub async fn mcp(session: ProtoSession, args: McpArgs) -> SessionResult {
    let console = session.console.clone();
    let server = ProtoMcp::new(session.clone());

    if !args.info {
        server
            .serve(stdio())
            .await
            .into_diagnostic()?
            .waiting()
            .await
            .into_diagnostic()?;

        return Ok(None);
    }

    let info = server.get_info();

    let mut tools = server.tool_router.list_all();
    tools.sort_by(|a, d| a.name.cmp(&d.name));

    let mut resources = server.list_all_resources().resources;
    resources.sort_by(|a, d| a.name.cmp(&d.name));

    if session.is_json_format() {
        console.write_json_for_format(McpOutput {
            info,
            tools,
            resources,
        })?;

        return Ok(None);
    }

    console.render(element! {
        Container {
            Section(title: "Server") {
                #(info.instructions.as_ref().map(|desc| {
                    element! {
                        View(margin_bottom: 1) {
                            StyledText(
                                content: desc,
                            )
                        }
                    }
                }))

                Entry(
                    name: "CLI version",
                    value: element! {
                        StyledText(
                            content: info.server_info.version.to_string(),
                            style: Style::Symbol
                        )
                    }.into_any()
                )
                Entry(
                    name: "Protocol version",
                    value: element! {
                        StyledText(
                            content: info.protocol_version.to_string(),
                            style: Style::Hash
                        )
                    }.into_any()
                )
            }

            Section(title: "Tools") {
                #(tools.into_iter().map(|tool| {
                    element! {
                        Entry(
                            name: tool.name.to_string(),
                            content: tool.description.unwrap_or_default().to_string(),
                        )
                    }
                }))
            }

            Section(title: "Resources") {
                #(resources.into_iter().map(|resource| {
                    element! {
                        Entry(
                            name: resource.uri.to_string(),
                            content: resource.name.to_string(),
                        )
                    }
                }))
            }
        }
    })?;

    Ok(None)
}