Table of Content
What? Just by speaking, you can let a large model help you organize your computer desktop?!

Updated on:June-25th-2025
Recommendation
Use AI technology to simplify desktop management and free your hands from tedious file organization.
Core content:
1. Combining MCP protocol with Golang to realize the desktop intelligent cleaning system
2. MCP Server and Client architecture design and communication process
3. Code example: Implement desktop path acquisition and file management tool definition
Yang Fangxian
Founder of 53A/Most Valuable Expert of Tencent Cloud (TVP)
Many people's desktops are often filled with shortcuts, temporary files, test logs,
Debugging screenshots and so on take up space, and manual cleaning is time-consuming and laborious.
This article will build an intelligent
Cleaning the system :
MCP Server provides file management tools .
MCP Client triggers automated operations through natural language commands.
Living in the AI age, we must learn to use AI tools.
1. MCP Architecture Design
1.1 Technical Solution
We use Golang to implement MCP Client and Server. MCP is the Model Context Protocol, which is used to connect large language models and external tools. It adopts a client-server architecture.MCP Server : Resident in the background, providing three tools: scan_temp_files (scan), delete_files (delete), and organize_desktop (organize).
MCP Client: Parses natural language instructions (such as " search the desktop for files ending with .log") and calls the Server tool chain.
1.2 Communication process
2. MCP Server Implementation
2.1 Tool Definition
package main
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"os"
"path/filepath"
"strings"
"time"
)
// Get the desktop path (cross-platform compatibility)
func getDesktopPath () string {
home, _ := os.UserHomeDir()
// Create the working directory if it does not exist
path := filepath.Join(home, "Desktop" )
if _, err := os.Stat(path); os.IsNotExist(err) {
os.MkdirAll(path, 0755 )
}
return path
}
func main () {
s := server.NewMCPServer( "DesktopCleaner" , "1.0" ,
server.WithLogging(),
server.WithRecovery(),
)
// Tool 1: Scan temporary files
scanTool := mcp.NewTool( "scan_temp_files" ,
mcp.WithDescription( "Scan temporary files with specified suffix on the desktop" ),
mcp.WithString( "suffix" , mcp.Required(),
mcp.Description( "File suffix such as .log/.tmp" ),
mcp.Pattern( `^\.[a-zA-Z0-9]+$` )),
mcp.WithNumber( "days" , mcp.Description( "Search for files within the last N days" )),
)
s.AddTool(scanTool, scanHandler)
// Tool 2: Batch Delete
delTool := mcp.NewTool( "delete_files" ,
mcp.WithDescription( "Delete the file in the specified path" ),
mcp.WithArray( "paths" , mcp.Required(),
mcp.Description( "File path array" )),
)
s.AddTool(delTool, deleteHandler)
// Tool 3: Desktop Organization
orgTool := mcp.NewTool( "organize_desktop" ,
mcp.WithDescription( "Organize files by type" ),
mcp.WithString( "strategy" ,
mcp.Enum( "type" , "date" ), // Classify by type/date
mcp.Description( "Organization strategy" )),
)
s.AddTool(orgTool, organizeHandler)
if err := server.ServeStdio(s); err != nil {
fmt.Printf( "Server error: %v\n" , err)
}
}
2.1 Core Processor Implementation
// Scan processor
func scanHandler (ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error ) {
suffix := req.Params.Arguments[ "suffix" ].( string )
// Get the days parameter. If it does not exist, the default value is 0 and no date filtering is performed.
var days int
if daysVal, ok := req.Params.Arguments[ "days" ]; ok {
days, _ = daysVal.( int )
}
desktopPath := getDesktopPath()
fmt.Printf( "Scanning directory: %s, suffix: %s, days: %d\n" , desktopPath, suffix, days)
var files [] string
err := filepath.Walk(desktopPath, func (path string , info os.FileInfo, err error ) error {
// Handle error conditions to prevent null pointers
if err != nil {
fmt.Printf( "Error accessing path: %s, Error: %v\n" , path, err)
return nil // Continue scanning other files
}
if info == nil {
fmt.Printf( "File information is empty: %s\n" , path)
return nil
}
// Check the file extension, ignoring case
if info.IsDir() {
return nil
}
ext := filepath.Ext(path)
if strings.ToLower(ext) != strings.ToLower(suffix) {
return nil
}
// If the number of days is specified, check the file modification time
if days > 0 {
if time.Since(info.ModTime()) > time.Duration(days)* 24 *time.Hour {
return nil // The file is too old, skip it
}
}
// The file meets the conditions and is added to the results
files = append (files, path)
fmt.Printf( "File found: %s\n" , path)
return nil
})
if err != nil {
fmt.Printf( "Scanning error: %v\n" , err)
return mcp.NewToolResultErrorFromErr( "Scan failed" , err), nil
}
result := "Found" + fmt.Sprintf( "%d" , len (files)) + "Files: \n"
for _, f := range files {
result += f + "\n"
}
return mcp.NewToolResultText(result), nil
}
// Delete the handler
func deleteHandler (ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error ) {
paths := req.Params.Arguments[ "paths" ].([] interface {})
results := make ( map [ string ] string )
for _, p := range paths {
path := p.( string )
if !isUnderDesktop(path) { // Security check
return mcp.NewToolResultError( "Illegal path: " + path), nil
}
err := os.Remove(path)
if err != nil {
results[path] = "Delete failed: " + err.Error()
} else {
results[path] = "Deleted successfully"
}
}
result := "Delete result:\n"
for path, status := range results {
result += path + ": " + status + "\n"
}
return mcp.NewToolResultText(result), nil
}
// Arrange desktop processor
func organizeHandler (ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error ) {
strategy, _ := req.Params.Arguments[ "strategy" ].( string )
// The actual sorting logic can be implemented here
return mcp.NewToolResultText( "Desktop files have been pressed" + strategy + "Organization completed" ), nil
}
// Path validity check
func isUnderDesktop (path string ) bool {
rel, err := filepath.Rel(getDesktopPath(), path)
return err == nil && !strings.HasPrefix(rel, ".." )
}
3. MCP Client Implementation
3.1 Client Initialization
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/mark3labs/mcp-go/client"
"github.com/mark3labs/mcp-go/mcp"
"strings"
"time"
)
func main () {
// Connect to the local Server
mcpClient, err := client.NewStdioMCPClient( "./desktop_cleaner" , nil )
if err != nil {
panic (err)
}
defer mcpClient.Close()
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30 *time.Second)
defer cancel()
// Initialize handshake
fmt.Println( "Initializing client..." )
initRequest := mcp.InitializeRequest{}
initRequest.Params.ProtocolVersion = mcp.LATEST_PROTOCOL_VERSION
initRequest.Params.ClientInfo = mcp.Implementation{
Name: "CleanBot" ,
Version: "1.0" ,
}
if _, err := mcpClient.Initialize(ctx, initRequest); err != nil {
panic (err)
}
// Execute toolchain
if err := cleanTempFiles(ctx, mcpClient); err != nil {
fmt.Printf( "Cleanup failed: %v\n" , err)
}
}
3.2 Tool Call
func cleanTempFiles(ctx context.Context, client *client.Client) error { // Step 1: Scan .log files scanReq := mcp.CallToolRequest{ Request: mcp.Request{ Method: "tools/call", }, } scanReq.Params.Name = "scan_temp_files" scanReq.Params.Arguments = map[string]interface{}{ "suffix": ".log", "days": 7, } scanRes, err := client.CallTool(ctx, scanReq) if err != nil { return err } printToolResult(scanRes) fmt.Println() // 解析扫描结果 files := parseFiles(scanRes) // Step 2: Delete files delReq := mcp.CallToolRequest{ Request: mcp.Request{ Method: "tools/call", }, } delReq.Params.Name = "delete_files" delReq.Params.Arguments = map[string]interface{}{ "paths": files, } if _, err := client.CallTool(ctx, delReq); err != nil { return err } fmt.Printf("Cleaned %d files successfully\n", len(files)) return nil}// Helper function to print tool resultsfunc printToolResult(result *mcp.CallToolResult) { for _, content := range result.Content { if textContent, ok := content.(mcp.TextContent); ok { fmt.Println(textContent.Text) } else { jsonBytes, _ := json.MarshalIndent(content, "", " ") fmt.Println(string(jsonBytes)) } }}//Parse calltoolresultfunc parseFiles(result *mcp.CallToolResult) (files []string) { for _, content := range result.Content { if textContent, ok := content.(mcp.TextContent); ok { for _, line := range strings.Split(textContent.Text, "\n") { if strings.HasPrefix(line, "/") { files = append(files, line) } } } else { jsonBytes, _ := json.MarshalIndent(content, "", " ") // Parsed into []string var result []string if err := json.Unmarshal(jsonBytes, &result); err != nil { fmt.Println("Parse failed:", err) } files = append(files, result...) } } return}
4. Scene Demonstration
Combine LLM to achieve intelligent decision-making:
First we need to install the mcphost tool and Ollama
# Install the mcphost tool go install github.com/mark3labs/mcphost@latest
# Start AI coordination mode mcphost --config mcp-systemfile/clean_config.json --model ollama:qwen2.5:3b
Ollama installs qwen2.5:3b large model, size 1.9G
Final result
Thinking...
Assistant:
# Install the mcphost tool go install github.com/mark3labs/mcphost@latest
# Start AI coordination mode mcphost --config mcp-systemfile/clean_config.json --model ollama:qwen2.5:3b