Skip to content

Commit 9d815d5

Browse files
authored
Merge pull request #4075 from AkihiroSuda/fix-4071
docs: generate MCP docs
2 parents aad73df + f25baa1 commit 9d815d5

File tree

3 files changed

+105
-15
lines changed

3 files changed

+105
-15
lines changed

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,14 +478,19 @@ endif
478478
# Set limactl.md as explicit dependency.
479479
# It's uncertain how many docsy pages will be generated by `make`,
480480
# because `limactl` generates them without corresponding source code for the docsy pages.
481-
docsy: website/_output/docsy/limactl.md
481+
docsy: website/_output/docsy/limactl.md website/_output/docsy-mcp/mcp.md
482482
website/_output/docsy/limactl.md: _output/bin/limactl$(exe)
483483
@mkdir -p website/_output/docsy
484484
ifeq ($(native_compiling),true)
485485
# The docs are generated by limactl, so the limactl binary must be native.
486486
$< generate-doc --type docsy website/_output/docsy \
487487
--output _output --prefix $(PREFIX)
488488
endif
489+
website/_output/docsy-mcp/mcp.md: _output/libexec/lima/limactl-mcp$(exe)
490+
@mkdir -p website/_output/docsy-mcp
491+
ifeq ($(native_compiling),true)
492+
$< generate-doc website/_output/docsy-mcp
493+
endif
489494

490495
################################################################################
491496
default-template.yaml: _output/bin/limactl$(exe)

cmd/limactl-mcp/main.go

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
package main
55

66
import (
7+
"context"
78
"encoding/json"
89
"errors"
910
"fmt"
11+
"os"
12+
"path/filepath"
1013
"runtime"
1114
"strings"
1215

@@ -38,6 +41,7 @@ func newApp() *cobra.Command {
3841
cmd.AddCommand(
3942
newMcpInfoCommand(),
4043
newMcpServeCommand(),
44+
newMcpGenDocCommand(),
4145
// TODO: `limactl-mcp configure gemini` ?
4246
)
4347
return cmd
@@ -77,47 +81,51 @@ func newMcpInfoCommand() *cobra.Command {
7781

7882
func mcpInfoAction(cmd *cobra.Command, _ []string) error {
7983
ctx := cmd.Context()
80-
limactl, err := limactlutil.Path()
84+
info, err := inspectInfo(ctx)
8185
if err != nil {
8286
return err
8387
}
84-
ts, err := toolset.New(limactl)
88+
j, err := json.MarshalIndent(info, "", " ")
8589
if err != nil {
8690
return err
8791
}
92+
_, err = fmt.Fprint(cmd.OutOrStdout(), string(j))
93+
return err
94+
}
95+
96+
func inspectInfo(ctx context.Context) (*Info, error) {
97+
ts, err := toolset.New("")
98+
if err != nil {
99+
return nil, err
100+
}
88101
server := newServer()
89102
if err = ts.RegisterServer(server); err != nil {
90-
return err
103+
return nil, err
91104
}
92105
serverTransport, clientTransport := mcp.NewInMemoryTransports()
93106
serverSession, err := server.Connect(ctx, serverTransport, nil)
94107
if err != nil {
95-
return err
108+
return nil, err
96109
}
97110
client := mcp.NewClient(&mcp.Implementation{Name: "client"}, nil)
98111
clientSession, err := client.Connect(ctx, clientTransport, nil)
99112
if err != nil {
100-
return err
113+
return nil, err
101114
}
102115
toolsResult, err := clientSession.ListTools(ctx, &mcp.ListToolsParams{})
103116
if err != nil {
104-
return err
117+
return nil, err
105118
}
106119
if err = clientSession.Close(); err != nil {
107-
return err
120+
return nil, err
108121
}
109122
if err = serverSession.Wait(); err != nil {
110-
return err
123+
return nil, err
111124
}
112125
info := &Info{
113126
Tools: toolsResult.Tools,
114127
}
115-
j, err := json.MarshalIndent(info, "", " ")
116-
if err != nil {
117-
return err
118-
}
119-
_, err = fmt.Fprint(cmd.OutOrStdout(), string(j))
120-
return err
128+
return info, nil
121129
}
122130

123131
type Info struct {
@@ -170,3 +178,76 @@ func mcpServeAction(cmd *cobra.Command, args []string) error {
170178
transport := &mcp.StdioTransport{}
171179
return server.Run(ctx, transport)
172180
}
181+
182+
func newMcpGenDocCommand() *cobra.Command {
183+
cmd := &cobra.Command{
184+
Use: "generate-doc DIR",
185+
Short: "Generate documentation pages",
186+
Args: cobra.MinimumNArgs(1),
187+
RunE: mcpGenDocAction,
188+
Hidden: true,
189+
}
190+
return cmd
191+
}
192+
193+
func mcpGenDocAction(cmd *cobra.Command, args []string) error {
194+
ctx := cmd.Context()
195+
dir := args[0]
196+
if err := os.MkdirAll(dir, 0o755); err != nil {
197+
return err
198+
}
199+
fName := filepath.Join(dir, "mcp.md")
200+
f, err := os.Create(fName)
201+
if err != nil {
202+
return err
203+
}
204+
defer f.Close()
205+
fmt.Fprint(f, `---
206+
title: MCP tools
207+
weight: 99
208+
---
209+
Lima implements the "MCP Sandbox Interface" (tentative name):
210+
https://pkg.go.dev/github.com/lima-vm/lima/v2/pkg/mcp/msi
211+
212+
MCP Sandbox Interface defines MCP (Model Context Protocol) tools
213+
that can be used for reading, writing, and executing local files
214+
with an appropriate sandboxing technology, such as Lima.
215+
216+
The sandboxing technology can be more secure and/or efficient than
217+
the default tools provided by an AI agent.
218+
219+
MCP Sandbox Interface was inspired by
220+
[Google Gemini CLI's built-in tools](https://github.com/google-gemini/gemini-cli/tree/main/docs/tools).
221+
222+
`)
223+
info, err := inspectInfo(ctx)
224+
if err != nil {
225+
return err
226+
}
227+
for _, tool := range info.Tools {
228+
fmt.Fprintf(f, "## `%s`\n\n", tool.Name)
229+
if tool.Title != "" {
230+
fmt.Fprintf(f, "### Title\n\n%s\n\n", tool.Title)
231+
}
232+
if tool.Description != "" {
233+
fmt.Fprintf(f, "### Description\n\n%s\n\n", tool.Description)
234+
}
235+
if tool.InputSchema != nil {
236+
fmt.Fprint(f, "### Input Schema\n\n")
237+
schema, err := json.MarshalIndent(tool.InputSchema, "", " ")
238+
if err != nil {
239+
return err
240+
}
241+
fmt.Fprintf(f, "```json\n%s\n```\n\n", string(schema))
242+
}
243+
if tool.OutputSchema != nil {
244+
fmt.Fprint(f, "### Output Schema\n\n")
245+
schema, err := json.MarshalIndent(tool.OutputSchema, "", " ")
246+
if err != nil {
247+
return err
248+
}
249+
fmt.Fprintf(f, "```json\n%s\n```\n\n", string(schema))
250+
}
251+
}
252+
return f.Close()
253+
}

website/hugo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ enable = false
204204
source="docsy"
205205
target="content/docs/Reference"
206206
language="en"
207+
[[module.imports.mounts]]
208+
source="docsy-mcp"
209+
target="content/docs/config/ai/outside"
210+
language="en"
207211
# Import templates README.md from templates folder
208212
[[module.imports]]
209213
path="../.."

0 commit comments

Comments
 (0)