func RepositoryResourceContentsHandler()

in pkg/github/repository_resource.go [66:206]


func RepositoryResourceContentsHandler(getClient GetClientFn) func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
	return func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
		// the matcher will give []string with one element
		// https://github.com/mark3labs/mcp-go/pull/54
		o, ok := request.Params.Arguments["owner"].([]string)
		if !ok || len(o) == 0 {
			return nil, errors.New("owner is required")
		}
		owner := o[0]

		r, ok := request.Params.Arguments["repo"].([]string)
		if !ok || len(r) == 0 {
			return nil, errors.New("repo is required")
		}
		repo := r[0]

		// path should be a joined list of the path parts
		path := ""
		p, ok := request.Params.Arguments["path"].([]string)
		if ok {
			path = strings.Join(p, "/")
		}

		opts := &github.RepositoryContentGetOptions{}

		sha, ok := request.Params.Arguments["sha"].([]string)
		if ok && len(sha) > 0 {
			opts.Ref = sha[0]
		}

		branch, ok := request.Params.Arguments["branch"].([]string)
		if ok && len(branch) > 0 {
			opts.Ref = "refs/heads/" + branch[0]
		}

		tag, ok := request.Params.Arguments["tag"].([]string)
		if ok && len(tag) > 0 {
			opts.Ref = "refs/tags/" + tag[0]
		}
		prNumber, ok := request.Params.Arguments["prNumber"].([]string)
		if ok && len(prNumber) > 0 {
			opts.Ref = "refs/pull/" + prNumber[0] + "/head"
		}

		client, err := getClient(ctx)
		if err != nil {
			return nil, fmt.Errorf("failed to get GitHub client: %w", err)
		}
		fileContent, directoryContent, _, err := client.Repositories.GetContents(ctx, owner, repo, path, opts)
		if err != nil {
			return nil, err
		}

		if directoryContent != nil {
			var resources []mcp.ResourceContents
			for _, entry := range directoryContent {
				mimeType := "text/directory"
				if entry.GetType() == "file" {
					// this is system dependent, and a best guess
					ext := filepath.Ext(entry.GetName())
					mimeType = mime.TypeByExtension(ext)
					if ext == ".md" {
						mimeType = "text/markdown"
					}
				}
				resources = append(resources, mcp.TextResourceContents{
					URI:      entry.GetHTMLURL(),
					MIMEType: mimeType,
					Text:     entry.GetName(),
				})

			}
			return resources, nil

		}
		if fileContent != nil {
			if fileContent.Content != nil {
				// download the file content from fileContent.GetDownloadURL() and use the content-type header to determine the MIME type
				// and return the content as a blob unless it is a text file, where you can return the content as text
				req, err := http.NewRequest("GET", fileContent.GetDownloadURL(), nil)
				if err != nil {
					return nil, fmt.Errorf("failed to create request: %w", err)
				}

				resp, err := client.Client().Do(req)
				if err != nil {
					return nil, fmt.Errorf("failed to send request: %w", err)
				}
				defer func() { _ = resp.Body.Close() }()

				if resp.StatusCode != http.StatusOK {
					body, err := io.ReadAll(resp.Body)
					if err != nil {
						return nil, fmt.Errorf("failed to read response body: %w", err)
					}
					return nil, fmt.Errorf("failed to fetch file content: %s", string(body))
				}

				ext := filepath.Ext(fileContent.GetName())
				mimeType := resp.Header.Get("Content-Type")
				if ext == ".md" {
					mimeType = "text/markdown"
				} else if mimeType == "" {
					// backstop to the file extension if the content type is not set
					mimeType = mime.TypeByExtension(filepath.Ext(fileContent.GetName()))
				}

				// if the content is a string, return it as text
				if strings.HasPrefix(mimeType, "text") {
					content, err := io.ReadAll(resp.Body)
					if err != nil {
						return nil, fmt.Errorf("failed to parse the response body: %w", err)
					}

					return []mcp.ResourceContents{
						mcp.TextResourceContents{
							URI:      request.Params.URI,
							MIMEType: mimeType,
							Text:     string(content),
						},
					}, nil
				}
				// otherwise, read the content and encode it as base64
				decodedContent, err := io.ReadAll(resp.Body)
				if err != nil {
					return nil, fmt.Errorf("failed to parse the response body: %w", err)
				}

				return []mcp.ResourceContents{
					mcp.BlobResourceContents{
						URI:      request.Params.URI,
						MIMEType: mimeType,
						Blob:     base64.StdEncoding.EncodeToString(decodedContent), // Encode content as Base64
					},
				}, nil
			}
		}

		return nil, errors.New("no repository resource content found")
	}
}