mcp: adds remote template support

Signed-off-by: kapil <kapilsareen584@gmail.com>
This commit is contained in:
kapil 2025-07-24 18:33:28 +05:30
parent d04ff0a378
commit f8f36c93f9
2 changed files with 117 additions and 1 deletions

View File

@ -2,13 +2,75 @@ package mcp
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os/exec"
"strings"
"github.com/mark3labs/mcp-go/mcp"
)
type template struct {
Repository string `json:"repository"`
Language string `json:"language"`
TemplateName string `json:"template"`
}
func fetchTemplates() ([]template, error) {
var out []template
seen := make(map[string]bool)
for _, repoURL := range TEMPLATE_RESOURCE_URIS {
owner, repo := parseGitHubURL(repoURL)
api := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/trees/main?recursive=1", owner, repo)
resp, err := http.Get(api)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var tree struct {
Tree []struct {
Path string `json:"path"`
} `json:"tree"`
}
if err := json.Unmarshal(body, &tree); err != nil {
return nil, err
}
for _, item := range tree.Tree {
parts := strings.Split(item.Path, "/")
if len(parts) >= 2 && !strings.HasPrefix(parts[0], ".") {
lang, name := parts[0], parts[1]
key := lang + "/" + name
if !seen[key] {
out = append(out, template{
Language: lang,
TemplateName: name,
Repository: repoURL,
})
seen[key] = true
}
}
}
}
return out, nil
}
func parseGitHubURL(url string) (owner, repo string) {
trim := strings.TrimPrefix(url, "https://github.com/")
parts := strings.Split(trim, "/")
return parts[0], parts[1]
}
func handleRootHelpResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
content, err := exec.Command("func", "--help").Output()
if err != nil {
@ -39,6 +101,25 @@ func runHelpCommand(args []string, uri string) ([]mcp.ResourceContents, error) {
}, nil
}
func handleListTemplatesResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
templates, err := fetchTemplates()
if err != nil {
return nil, err
}
content, err := json.MarshalIndent(templates, "", " ")
if err != nil {
return nil, err
}
return []mcp.ResourceContents{
mcp.TextResourceContents{
URI: "func://templates",
MIMEType: "text/plain",
Text: string(content),
},
}, nil
}
func handleCmdHelpPrompt(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
cmd := request.Params.Arguments["cmd"]
if cmd == "" {
@ -86,3 +167,22 @@ func handleRootHelpPrompt(ctx context.Context, request mcp.GetPromptRequest) (*m
},
), nil
}
func handleListTemplatesPrompt(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
return mcp.NewGetPromptResult(
"List Templates Prompt",
[]mcp.PromptMessage{
mcp.NewPromptMessage(
mcp.RoleUser,
mcp.NewTextContent("List available function templates"),
),
mcp.NewPromptMessage(
mcp.RoleAssistant,
mcp.NewEmbeddedResource(mcp.TextResourceContents{
URI: "func://templates",
MIMEType: "text/plain",
}),
),
},
), nil
}

View File

@ -7,6 +7,10 @@ import (
"github.com/mark3labs/mcp-go/server"
)
var TEMPLATE_RESOURCE_URIS = []string{
"https://github.com/gauron99/func-templates",
}
type MCPServer struct {
server *server.MCPServer
}
@ -43,7 +47,7 @@ func NewServer() *MCPServer {
// Optional flags
mcp.WithString("template", mcp.Description("Function template (e.g., http, cloudevents)")),
mcp.WithString("repository", mcp.Description("URI to Git repo containing the template")),
mcp.WithString("repository", mcp.Description("URI to Git repo containing the template. Overrides default template selection when provided.")),
mcp.WithBoolean("confirm", mcp.Description("Prompt to confirm options interactively")),
mcp.WithBoolean("verbose", mcp.Description("Print verbose logs")),
),
@ -325,6 +329,14 @@ func NewServer() *MCPServer {
return runHelpCommand([]string{"config", "envs", "remove"}, "func://config/envs/remove/docs")
})
// Static resource for listing available templates
mcpServer.AddResource(mcp.NewResource(
"func://templates",
"Available Templates",
mcp.WithResourceDescription("List of available function templates"),
mcp.WithMIMEType("plain/text"),
), handleListTemplatesResource)
mcpServer.AddPrompt(mcp.NewPrompt("help",
mcp.WithPromptDescription("help prompt for the root command"),
), handleRootHelpPrompt)
@ -337,6 +349,10 @@ func NewServer() *MCPServer {
),
), handleCmdHelpPrompt)
mcpServer.AddPrompt(mcp.NewPrompt("list_templates",
mcp.WithPromptDescription("prompt to list available function templates"),
), handleListTemplatesPrompt)
return &MCPServer{
server: mcpServer,
}