docs: generate MCP docs

Fix issue 4071

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda committed 2025-09-24 09:09:07 +09:00
1 parent aad73df750
commit f25baa1ff8
3 files changed
+123 -33

No files matched your search

+6 -1
View File
@@ -478,7 +478,7 @@ endif
# Set limactl.md as explicit dependency.
# It's uncertain how many docsy pages will be generated by `make`,
# because `limactl` generates them without corresponding source code for the docsy pages.
docsy: website/_output/docsy/limactl.md
docsy: website/_output/docsy/limactl.md website/_output/docsy-mcp/mcp.md
website/_output/docsy/limactl.md: _output/bin/limactl$(exe)
@mkdir -p website/_output/docsy
ifeq ($(native_compiling),true)
@@ -486,6 +486,11 @@ ifeq ($(native_compiling),true)
$< generate-doc --type docsy website/_output/docsy \
--output _output --prefix $(PREFIX)
endif
website/_output/docsy-mcp/mcp.md: _output/libexec/lima/limactl-mcp$(exe)
@mkdir -p website/_output/docsy-mcp
ifeq ($(native_compiling),true)
$< generate-doc website/_output/docsy-mcp
endif
################################################################################
default-template.yaml: _output/bin/limactl$(exe)
+113 -32
View File
@@ -4,9 +4,12 @@
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
@@ -38,6 +41,7 @@ func newApp() *cobra.Command {
cmd.AddCommand(
newMcpInfoCommand(),
newMcpServeCommand(),
newMcpGenDocCommand(),
// TODO: `limactl-mcp configure gemini` ?
)
return cmd
@@ -77,41 +81,10 @@ func newMcpInfoCommand() *cobra.Command {
func mcpInfoAction(cmd *cobra.Command, _ []string) error {
ctx := cmd.Context()
limactl, err := limactlutil.Path()
info, err := inspectInfo(ctx)
if err != nil {
return err
}
ts, err := toolset.New(limactl)
if err != nil {
return err
}
server := newServer()
if err = ts.RegisterServer(server); err != nil {
return err
}
serverTransport, clientTransport := mcp.NewInMemoryTransports()
serverSession, err := server.Connect(ctx, serverTransport, nil)
if err != nil {
return err
}
client := mcp.NewClient(&mcp.Implementation{Name: "client"}, nil)
clientSession, err := client.Connect(ctx, clientTransport, nil)
if err != nil {
return err
}
toolsResult, err := clientSession.ListTools(ctx, &mcp.ListToolsParams{})
if err != nil {
return err
}
if err = clientSession.Close(); err != nil {
return err
}
if err = serverSession.Wait(); err != nil {
return err
}
info := &Info{
Tools: toolsResult.Tools,
}
j, err := json.MarshalIndent(info, "", " ")
if err != nil {
return err
@@ -120,6 +93,41 @@ func mcpInfoAction(cmd *cobra.Command, _ []string) error {
return err
}
func inspectInfo(ctx context.Context) (*Info, error) {
ts, err := toolset.New("")
if err != nil {
return nil, err
}
server := newServer()
if err = ts.RegisterServer(server); err != nil {
return nil, err
}
serverTransport, clientTransport := mcp.NewInMemoryTransports()
serverSession, err := server.Connect(ctx, serverTransport, nil)
if err != nil {
return nil, err
}
client := mcp.NewClient(&mcp.Implementation{Name: "client"}, nil)
clientSession, err := client.Connect(ctx, clientTransport, nil)
if err != nil {
return nil, err
}
toolsResult, err := clientSession.ListTools(ctx, &mcp.ListToolsParams{})
if err != nil {
return nil, err
}
if err = clientSession.Close(); err != nil {
return nil, err
}
if err = serverSession.Wait(); err != nil {
return nil, err
}
info := &Info{
Tools: toolsResult.Tools,
}
return info, nil
}
type Info struct {
Tools []*mcp.Tool `json:"tools"`
}
@@ -170,3 +178,76 @@ func mcpServeAction(cmd *cobra.Command, args []string) error {
transport := &mcp.StdioTransport{}
return server.Run(ctx, transport)
}
func newMcpGenDocCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "generate-doc DIR",
Short: "Generate documentation pages",
Args: cobra.MinimumNArgs(1),
RunE: mcpGenDocAction,
Hidden: true,
}
return cmd
}
func mcpGenDocAction(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
dir := args[0]
if err := os.MkdirAll(dir, 0o755); err != nil {
return err
}
fName := filepath.Join(dir, "mcp.md")
f, err := os.Create(fName)
if err != nil {
return err
}
defer f.Close()
fmt.Fprint(f, `---
title: MCP tools
weight: 99
---
Lima implements the "MCP Sandbox Interface" (tentative name):
https://pkg.go.dev/github.com/lima-vm/lima/v2/pkg/mcp/msi
MCP Sandbox Interface defines MCP (Model Context Protocol) tools
that can be used for reading, writing, and executing local files
with an appropriate sandboxing technology, such as Lima.
The sandboxing technology can be more secure and/or efficient than
the default tools provided by an AI agent.
MCP Sandbox Interface was inspired by
[Google Gemini CLI's built-in tools](https://github.com/google-gemini/gemini-cli/tree/main/docs/tools).
`)
info, err := inspectInfo(ctx)
if err != nil {
return err
}
for _, tool := range info.Tools {
fmt.Fprintf(f, "## `%s`\n\n", tool.Name)
if tool.Title != "" {
fmt.Fprintf(f, "### Title\n\n%s\n\n", tool.Title)
}
if tool.Description != "" {
fmt.Fprintf(f, "### Description\n\n%s\n\n", tool.Description)
}
if tool.InputSchema != nil {
fmt.Fprint(f, "### Input Schema\n\n")
schema, err := json.MarshalIndent(tool.InputSchema, "", " ")
if err != nil {
return err
}
fmt.Fprintf(f, "```json\n%s\n```\n\n", string(schema))
}
if tool.OutputSchema != nil {
fmt.Fprint(f, "### Output Schema\n\n")
schema, err := json.MarshalIndent(tool.OutputSchema, "", " ")
if err != nil {
return err
}
fmt.Fprintf(f, "```json\n%s\n```\n\n", string(schema))
}
}
return f.Close()
}
+4
View File
@@ -204,6 +204,10 @@ enable = false
source="docsy"
target="content/docs/Reference"
language="en"
[[module.imports.mounts]]
source="docsy-mcp"
target="content/docs/config/ai/outside"
language="en"
# Import templates README.md from templates folder
[[module.imports]]
path="../.."