mirror of
https://github.com/tailscale/tailscale.git
synced 2025-07-29 15:23:45 +00:00
cmd/tsmcp: add a MCP implementation
Change-Id: I6e2a391dfe0929e6c44a537456fb2ea4c06b603b Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
7b29d39f45
commit
afd7eebf91
94
cmd/tsmcp/tsmcp.go
Normal file
94
cmd/tsmcp/tsmcp.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
|
"github.com/mark3labs/mcp-go/server"
|
||||||
|
"tailscale.com/client/local"
|
||||||
|
"tailscale.com/ipn"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var s Server
|
||||||
|
s.lc = new(local.Client)
|
||||||
|
|
||||||
|
// Create MCP server
|
||||||
|
s.ms = server.NewMCPServer(
|
||||||
|
"Tailscale",
|
||||||
|
"1.0.0",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add tool
|
||||||
|
toolStatus := mcp.NewTool("get_connection_status",
|
||||||
|
mcp.WithDescription("Check Tailscale's connection status"),
|
||||||
|
// mcp.WithString("name",
|
||||||
|
// mcp.Required(),
|
||||||
|
// mcp.Description("Name of the person to greet"),
|
||||||
|
// ),
|
||||||
|
)
|
||||||
|
|
||||||
|
s.ms.AddTool(toolStatus, s.statusHandler)
|
||||||
|
|
||||||
|
toolUp := mcp.NewTool("up",
|
||||||
|
mcp.WithDescription("Turn Tailscale on (run 'tailscale up')"),
|
||||||
|
)
|
||||||
|
s.ms.AddTool(toolUp, s.upHandler)
|
||||||
|
|
||||||
|
toolDown := mcp.NewTool("down",
|
||||||
|
mcp.WithDescription("Turn Tailscale off (run 'tailscale down')"),
|
||||||
|
)
|
||||||
|
s.ms.AddTool(toolDown, s.downHandler)
|
||||||
|
|
||||||
|
// Start the stdio server
|
||||||
|
if err := server.ServeStdio(s.ms); err != nil {
|
||||||
|
fmt.Printf("Server error: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
lc *local.Client
|
||||||
|
ms *server.MCPServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) statusHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
|
status, err := s.lc.StatusWithoutPeers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get connection status: %w", err)
|
||||||
|
}
|
||||||
|
switch status.BackendState {
|
||||||
|
case "NoState":
|
||||||
|
return mcp.NewToolResultText("In 'NoState', meaning it's broken or wedged or hung or maybe very early in its startup life cycle. But probably broken."), nil
|
||||||
|
case "Starting":
|
||||||
|
return mcp.NewToolResultText("In 'Starting', meaning it's starting up, but not yet fully connected. In particular, the control plane connection might be up, but no DERP yet."), nil
|
||||||
|
default:
|
||||||
|
return mcp.NewToolResultText(status.BackendState), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) upHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
|
_, err := s.lc.EditPrefs(ctx, &ipn.MaskedPrefs{
|
||||||
|
WantRunningSet: true,
|
||||||
|
Prefs: ipn.Prefs{
|
||||||
|
WantRunning: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to turn on Tailscale: %w", err)
|
||||||
|
}
|
||||||
|
return mcp.NewToolResultText("done"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) downHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
|
_, err := s.lc.EditPrefs(ctx, &ipn.MaskedPrefs{
|
||||||
|
WantRunningSet: true,
|
||||||
|
Prefs: ipn.Prefs{
|
||||||
|
WantRunning: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to turn off Tailscale: %w", err)
|
||||||
|
}
|
||||||
|
return mcp.NewToolResultText("done"), nil
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -57,6 +57,7 @@ require (
|
|||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||||
github.com/klauspost/compress v1.17.11
|
github.com/klauspost/compress v1.17.11
|
||||||
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a
|
github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a
|
||||||
|
github.com/mark3labs/mcp-go v0.18.0
|
||||||
github.com/mattn/go-colorable v0.1.13
|
github.com/mattn/go-colorable v0.1.13
|
||||||
github.com/mattn/go-isatty v0.0.20
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mdlayher/genetlink v1.3.2
|
github.com/mdlayher/genetlink v1.3.2
|
||||||
@ -156,6 +157,7 @@ require (
|
|||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
|
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
|
||||||
github.com/xen0n/gosmopolitan v1.2.2 // indirect
|
github.com/xen0n/gosmopolitan v1.2.2 // indirect
|
||||||
github.com/ykadowak/zerologlint v0.1.5 // indirect
|
github.com/ykadowak/zerologlint v0.1.5 // indirect
|
||||||
|
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||||
go-simpler.org/musttag v0.9.0 // indirect
|
go-simpler.org/musttag v0.9.0 // indirect
|
||||||
go-simpler.org/sloglint v0.5.0 // indirect
|
go-simpler.org/sloglint v0.5.0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
|
4
go.sum
4
go.sum
@ -656,6 +656,8 @@ github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s
|
|||||||
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
|
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
|
||||||
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
|
github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
|
||||||
github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
|
github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
|
||||||
|
github.com/mark3labs/mcp-go v0.18.0 h1:YuhgIVjNlTG2ZOwmrkORWyPTp0dz1opPEqvsPtySXao=
|
||||||
|
github.com/mark3labs/mcp-go v0.18.0/go.mod h1:KmJndYv7GIgcPVwEKJjNcbhVQ+hJGJhrCCB/9xITzpE=
|
||||||
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE=
|
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE=
|
||||||
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||||
@ -989,6 +991,8 @@ github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y
|
|||||||
github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA=
|
github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA=
|
||||||
github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw=
|
github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw=
|
||||||
github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg=
|
github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg=
|
||||||
|
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||||
|
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user