Skip to content

Commit b709f7f

Browse files
[release-v1.17] pick mcp (#1368)
* mcp: adds func mcp command (knative#2836) Signed-off-by: KapilSareen <[email protected]> * mcp: adds create and deploy tools (knative#2859) Signed-off-by: kapil <[email protected]> * mcp: adds list tool (knative#2861) Signed-off-by: kapil <[email protected]> * mcp: adds build tool (knative#2865) Signed-off-by: kapil <[email protected]> * mcp: adds resource provider and prompt for root cmd docs (knative#2875) Signed-off-by: kapil <[email protected]> * mcp: adds delete tool and adds remote flag to deploy tool (knative#2863) * rebases * adds remote flag to deploy tool Signed-off-by: kapil <[email protected]> --------- Signed-off-by: kapil <[email protected]> * mcp: extends flags support for existing tools (knative#2889) Signed-off-by: kapil <[email protected]> * mcp: adds resources and prompts for func subcommands (knative#2890) Signed-off-by: kapil <[email protected]> * mcp: adds tool and resource for config volumes (knative#2925) Signed-off-by: kapil <[email protected]> * mcp: refactors pkg for easy maintainability (knative#2928) Signed-off-by: kapil <[email protected]> * mcp: adds labels and envs config tools and resources (knative#2931) Signed-off-by: kapil <[email protected]> * mcp: adds remote template support (knative#2951) Signed-off-by: kapil <[email protected]> --------- Signed-off-by: KapilSareen <[email protected]> Signed-off-by: kapil <[email protected]> Co-authored-by: Kapil Sareen <[email protected]>
1 parent 85f6a82 commit b709f7f

File tree

10 files changed

+1107
-4
lines changed

10 files changed

+1107
-4
lines changed

cmd/mcp.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cmd
2+
3+
import (
4+
"log"
5+
6+
"github.com/spf13/cobra"
7+
"knative.dev/func/pkg/mcp"
8+
)
9+
10+
func NewMCPServerCmd() *cobra.Command {
11+
cmd := &cobra.Command{
12+
Use: "mcp",
13+
Short: "Start MCP server",
14+
Long: `
15+
NAME
16+
{{rootCmdUse}} mcp - start a Model Context Protocol (MCP) server
17+
18+
SYNOPSIS
19+
{{rootCmdUse}} mcp [flags]
20+
21+
DESCRIPTION
22+
Starts a Model Context Protocol (MCP) server over standard input/output (stdio) transport.
23+
This implementation aims to support tools for deploying and creating serverless functions.
24+
25+
Note: This command is still under development.
26+
27+
EXAMPLES
28+
29+
o Run an MCP server:
30+
{{rootCmdUse}} mcp
31+
`,
32+
RunE: func(cmd *cobra.Command, args []string) error {
33+
return runMCPServer(cmd, args)
34+
},
35+
}
36+
return cmd
37+
}
38+
39+
func runMCPServer(cmd *cobra.Command, args []string) error {
40+
s := mcp.NewServer()
41+
if err := s.Start(); err != nil {
42+
log.Fatalf("Server error: %v", err)
43+
return err
44+
}
45+
return nil
46+
}

cmd/root.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ Learn more about Knative at: https://knative.dev`, cfg.Name),
107107
NewEnvironmentCmd(newClient, &cfg.Version),
108108
},
109109
},
110+
{
111+
Header: "MCP Commands:",
112+
Commands: []*cobra.Command{
113+
NewMCPServerCmd(),
114+
},
115+
},
110116
{
111117
Header: "Other Commands:",
112118
Commands: []*cobra.Command{

docs/reference/func.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Learn more about Knative at: https://knative.dev
3434
* [func invoke](func_invoke.md) - Invoke a local or remote function
3535
* [func languages](func_languages.md) - List available function language runtimes
3636
* [func list](func_list.md) - List deployed functions
37+
* [func mcp](func_mcp.md) - Start MCP server
3738
* [func repository](func_repository.md) - Manage installed template repositories
3839
* [func run](func_run.md) - Run the function locally
3940
* [func subscribe](func_subscribe.md) - Subscribe a function to events

docs/reference/func_mcp.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## func mcp
2+
3+
Start MCP server
4+
5+
### Synopsis
6+
7+
8+
NAME
9+
func mcp - start a Model Context Protocol (MCP) server
10+
11+
SYNOPSIS
12+
func mcp [flags]
13+
14+
DESCRIPTION
15+
Starts a Model Context Protocol (MCP) server over standard input/output (stdio) transport.
16+
This implementation aims to support tools for deploying and creating serverless functions.
17+
18+
Note: This command is still under development.
19+
20+
EXAMPLES
21+
22+
o Run an MCP server:
23+
func mcp
24+
25+
26+
```
27+
func mcp
28+
```
29+
30+
### Options
31+
32+
```
33+
-h, --help help for mcp
34+
```
35+
36+
### SEE ALSO
37+
38+
* [func](func.md) - func manages Knative Functions
39+

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ require (
3434
github.com/hinshun/vt10x v0.0.0-20220301184237-5011da428d02
3535
github.com/manifestival/client-go-client v0.5.0
3636
github.com/manifestival/manifestival v0.7.2
37+
github.com/mark3labs/mcp-go v0.30.0
3738
github.com/opencontainers/image-spec v1.1.0
3839
github.com/openshift-pipelines/pipelines-as-code v0.31.0
3940
github.com/openshift/source-to-image v1.5.0
@@ -244,7 +245,7 @@ require (
244245
github.com/skeema/knownhosts v1.3.0 // indirect
245246
github.com/sourcegraph/conc v0.3.0 // indirect
246247
github.com/spf13/afero v1.11.0 // indirect
247-
github.com/spf13/cast v1.6.0 // indirect
248+
github.com/spf13/cast v1.7.1 // indirect
248249
github.com/spf13/jwalterweatherman v1.1.0 // indirect
249250
github.com/spf13/viper v1.18.2 // indirect
250251
github.com/stoewer/go-strcase v1.3.0 // indirect
@@ -262,6 +263,7 @@ require (
262263
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
263264
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
264265
github.com/xlab/treeprint v1.2.0 // indirect
266+
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
265267
go.opencensus.io v0.24.0 // indirect
266268
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
267269
go.opentelemetry.io/otel v1.31.0 // indirect

go.sum

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,8 @@ github.com/manifestival/client-go-client v0.5.0/go.mod h1:sDehep6aHdIEdUKnRSvueG
705705
github.com/manifestival/manifestival v0.6.0/go.mod h1:3Qq9cnPy7sv7FVhg2Kvw0ebb35R4OdctS4UjTjHlHm4=
706706
github.com/manifestival/manifestival v0.7.2 h1:l4uFdWX/xQK4QcRfqGoMtBvaZeWPEuwD6hVsCwUqZY4=
707707
github.com/manifestival/manifestival v0.7.2/go.mod h1:nl3T6HlfHCeidooWVTMI9vYNTBkQ1GdhLNb+smozbdk=
708+
github.com/mark3labs/mcp-go v0.30.0 h1:Taz7fiefkxY/l8jz1nA90V+WdM2eoMtlvwfWforVYbo=
709+
github.com/mark3labs/mcp-go v0.30.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
708710
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
709711
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
710712
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -945,8 +947,8 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
945947
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
946948
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
947949
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
948-
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
949-
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
950+
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
951+
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
950952
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
951953
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
952954
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
@@ -1051,6 +1053,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
10511053
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
10521054
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
10531055
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
1056+
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
1057+
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
10541058
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
10551059
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
10561060
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

hack/install-tekton.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ install_tekton() {
4242
}
4343

4444
# Invoke only when run directly
45-
# Be a library when sourced
45+
# Be a library when sourced
4646
if [ "$0" = "${BASH_SOURCE[0]}" ]; then
4747
set -o errexit
4848
set -o nounset

pkg/mcp/help.go

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package mcp
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"os/exec"
10+
"strings"
11+
12+
"github.com/mark3labs/mcp-go/mcp"
13+
)
14+
15+
type template struct {
16+
Repository string `json:"repository"`
17+
Language string `json:"language"`
18+
TemplateName string `json:"template"`
19+
}
20+
21+
func fetchTemplates() ([]template, error) {
22+
var out []template
23+
seen := make(map[string]bool)
24+
25+
for _, repoURL := range TEMPLATE_RESOURCE_URIS {
26+
owner, repo := parseGitHubURL(repoURL)
27+
api := fmt.Sprintf("https://api.github.com/repos/%s/%s/git/trees/main?recursive=1", owner, repo)
28+
29+
resp, err := http.Get(api)
30+
if err != nil {
31+
return nil, err
32+
}
33+
defer resp.Body.Close()
34+
35+
body, err := io.ReadAll(resp.Body)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
var tree struct {
41+
Tree []struct {
42+
Path string `json:"path"`
43+
} `json:"tree"`
44+
}
45+
if err := json.Unmarshal(body, &tree); err != nil {
46+
return nil, err
47+
}
48+
49+
for _, item := range tree.Tree {
50+
parts := strings.Split(item.Path, "/")
51+
if len(parts) >= 2 && !strings.HasPrefix(parts[0], ".") {
52+
lang, name := parts[0], parts[1]
53+
key := lang + "/" + name
54+
if !seen[key] {
55+
out = append(out, template{
56+
Language: lang,
57+
TemplateName: name,
58+
Repository: repoURL,
59+
})
60+
seen[key] = true
61+
}
62+
}
63+
}
64+
}
65+
return out, nil
66+
}
67+
68+
func parseGitHubURL(url string) (owner, repo string) {
69+
trim := strings.TrimPrefix(url, "https://github.com/")
70+
parts := strings.Split(trim, "/")
71+
return parts[0], parts[1]
72+
}
73+
74+
func handleRootHelpResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
75+
content, err := exec.Command("func", "--help").Output()
76+
if err != nil {
77+
return nil, err
78+
}
79+
80+
return []mcp.ResourceContents{
81+
mcp.TextResourceContents{
82+
URI: "func://docs",
83+
MIMEType: "text/plain",
84+
Text: string(content),
85+
},
86+
}, nil
87+
}
88+
89+
func runHelpCommand(args []string, uri string) ([]mcp.ResourceContents, error) {
90+
args = append(args, "--help")
91+
content, err := exec.Command("func", args...).Output()
92+
if err != nil {
93+
return nil, err
94+
}
95+
return []mcp.ResourceContents{
96+
mcp.TextResourceContents{
97+
URI: uri,
98+
MIMEType: "text/plain",
99+
Text: string(content),
100+
},
101+
}, nil
102+
}
103+
104+
func handleListTemplatesResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
105+
templates, err := fetchTemplates()
106+
if err != nil {
107+
return nil, err
108+
}
109+
content, err := json.MarshalIndent(templates, "", " ")
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
return []mcp.ResourceContents{
115+
mcp.TextResourceContents{
116+
URI: "func://templates",
117+
MIMEType: "text/plain",
118+
Text: string(content),
119+
},
120+
}, nil
121+
}
122+
123+
func handleCmdHelpPrompt(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
124+
cmd := request.Params.Arguments["cmd"]
125+
if cmd == "" {
126+
return nil, fmt.Errorf("cmd is required")
127+
}
128+
129+
parts := strings.Fields(cmd)
130+
if len(parts) == 0 {
131+
return nil, fmt.Errorf("invalid cmd: %s", cmd)
132+
}
133+
134+
return mcp.NewGetPromptResult(
135+
"Cmd Help Prompt",
136+
[]mcp.PromptMessage{
137+
mcp.NewPromptMessage(
138+
mcp.RoleUser,
139+
mcp.NewTextContent("What can I do with this func command? Please provide help for the command: "+cmd),
140+
),
141+
mcp.NewPromptMessage(
142+
mcp.RoleAssistant,
143+
mcp.NewEmbeddedResource(mcp.TextResourceContents{
144+
URI: fmt.Sprintf("func://%s/docs", strings.Join(parts, "/")),
145+
MIMEType: "text/plain",
146+
}),
147+
),
148+
},
149+
), nil
150+
}
151+
152+
func handleRootHelpPrompt(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
153+
return mcp.NewGetPromptResult(
154+
"Help Prompt",
155+
[]mcp.PromptMessage{
156+
mcp.NewPromptMessage(
157+
mcp.RoleUser,
158+
mcp.NewTextContent("What can I do with the func command?"),
159+
),
160+
mcp.NewPromptMessage(
161+
mcp.RoleAssistant,
162+
mcp.NewEmbeddedResource(mcp.TextResourceContents{
163+
URI: "func://docs",
164+
MIMEType: "text/plain",
165+
}),
166+
),
167+
},
168+
), nil
169+
}
170+
171+
func handleListTemplatesPrompt(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
172+
return mcp.NewGetPromptResult(
173+
"List Templates Prompt",
174+
[]mcp.PromptMessage{
175+
mcp.NewPromptMessage(
176+
mcp.RoleUser,
177+
mcp.NewTextContent("List available function templates"),
178+
),
179+
mcp.NewPromptMessage(
180+
mcp.RoleAssistant,
181+
mcp.NewEmbeddedResource(mcp.TextResourceContents{
182+
URI: "func://templates",
183+
MIMEType: "text/plain",
184+
}),
185+
),
186+
},
187+
), nil
188+
}

0 commit comments

Comments
 (0)