Skip to main content
Glama

Excel MCP Server

MIT License
1,642
537
  • Linux
  • Apple
excel_screen_capture.go3.76 kB
package tools import ( "context" "fmt" z "github.com/Oudwins/zog" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/negokaz/excel-mcp-server/internal/excel" imcp "github.com/negokaz/excel-mcp-server/internal/mcp" ) type ExcelScreenCaptureArguments struct { FileAbsolutePath string `zog:"fileAbsolutePath"` SheetName string `zog:"sheetName"` Range string `zog:"range"` } var ExcelScreenCaptureArgumentsSchema = z.Struct(z.Shape{ "fileAbsolutePath": z.String().Test(AbsolutePathTest()).Required(), "sheetName": z.String().Required(), "range": z.String(), }) func AddExcelScreenCaptureTool(server *server.MCPServer) { server.AddTool(mcp.NewTool("excel_screen_capture", mcp.WithDescription("[Windows only] Take a screenshot of the Excel sheet with pagination."), mcp.WithString("fileAbsolutePath", mcp.Required(), mcp.Description("Absolute path to the Excel file"), ), mcp.WithString("sheetName", mcp.Required(), mcp.Description("Sheet name in the Excel file"), ), mcp.WithString("range", mcp.Description("Range of cells to read in the Excel sheet (e.g., \"A1:C10\"). [default: first paging range]"), ), ), handleScreenCapture) } func handleScreenCapture(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { args := ExcelScreenCaptureArguments{} issues := ExcelScreenCaptureArgumentsSchema.Parse(request.Params.Arguments, &args) if len(issues) != 0 { return imcp.NewToolResultZogIssueMap(issues), nil } return readSheetImage(args.FileAbsolutePath, args.SheetName, args.Range) } func readSheetImage(fileAbsolutePath string, sheetName string, rangeStr string) (*mcp.CallToolResult, error) { workbook, releaseWorkbook, err := excel.NewExcelOle(fileAbsolutePath) defer releaseWorkbook() if err != nil { workbook, releaseWorkbook, err = excel.NewExcelOleWithNewObject(fileAbsolutePath) defer releaseWorkbook() if err != nil { return imcp.NewToolResultInvalidArgumentError(fmt.Errorf("failed to open workbook: %w", err).Error()), nil } } worksheet, err := workbook.FindSheet(sheetName) if err != nil { return imcp.NewToolResultInvalidArgumentError(err.Error()), nil } defer worksheet.Release() pagingStrategy, err := worksheet.GetPagingStrategy(5000) if err != nil { return nil, err } pagingService := excel.NewPagingRangeService(pagingStrategy) allRanges := pagingService.GetPagingRanges() if len(allRanges) == 0 { return imcp.NewToolResultInvalidArgumentError("no range available to read"), nil } var currentRange string if rangeStr == "" && len(allRanges) > 0 { // range が指定されていない場合は最初の Range を使用 currentRange = allRanges[0] } else { // range が指定されている場合は指定された範囲を使用 currentRange = rangeStr } // Find next paging range if current range matches a paging range nextRange := pagingService.FindNextRange(allRanges, currentRange) base64image, err := worksheet.CapturePicture(currentRange) if err != nil { return nil, fmt.Errorf("failed to copy range to image: %w", err) } text := "# Metadata\n" text += fmt.Sprintf("- backend: %s\n", workbook.GetBackendName()) text += fmt.Sprintf("- sheet name: %s\n", sheetName) text += fmt.Sprintf("- read range: %s\n", currentRange) text += "# Notice\n" if nextRange != "" { text += "This sheet has more ranges.\n" text += "To read the next range, you should specify 'range' argument as follows.\n" text += fmt.Sprintf("`{ \"range\": \"%s\" }`", nextRange) } else { text += "This is the last range or no more ranges available.\n" } // 結果を返却 return mcp.NewToolResultImage( text, base64image, "image/png", ), nil }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/negokaz/excel-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server