Skip to content

Commit 8f447a8

Browse files
authored
mcp refactor (knative#3155)
1 parent c9d4c54 commit 8f447a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2728
-1006
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
/pkg/functions/testdata/default_home/go
1515
/pkg/functions/testdata/default_home/.cache
1616
/pkg/functions/testdata/migrations/*/.gitignore
17+
/pkg/creds/auth.json
18+
/pkg/oci/testdata/test-links/absoluteLink
19+
/pkg/oci/testdata/test-links/absoluteLinkWindows
1720

1821
# Go
1922
/templates/go/cloudevents/go.sum

cmd/mcp.go

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,121 @@
11
package cmd
22

33
import (
4-
"log"
4+
"fmt"
5+
"os"
6+
"strconv"
57

68
"github.com/spf13/cobra"
79
"knative.dev/func/pkg/mcp"
10+
11+
fn "knative.dev/func/pkg/functions"
812
)
913

10-
func NewMCPServerCmd() *cobra.Command {
14+
func NewMCPCmd(newClient ClientFactory) *cobra.Command {
1115
cmd := &cobra.Command{
1216
Use: "mcp",
13-
Short: "Start MCP server",
17+
Short: "Model Context Protocol (MCP) server",
1418
Long: `
1519
NAME
16-
{{rootCmdUse}} mcp - start a Model Context Protocol (MCP) server
20+
{{rootCmdUse}} mcp - Model Context Protocol (MCP) server
1721
1822
SYNOPSIS
19-
{{rootCmdUse}} mcp [flags]
20-
23+
{{rootCmdUse}} mcp [command] [flags]
2124
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.
25+
The Functions Model Context Protocol (MCP) server can be used to give
26+
agents the power of Functions.
27+
28+
Configure your agentic client to use the MCP server with command
29+
"{{rootCmdUse}} mcp start". Then get the conversation started with
30+
31+
"Let's create a Function!".
32+
33+
By default the MCP server operates in read-only mode, allowing Function
34+
creation, building, and inspection, but preventing deployment and deletion.
35+
To enable full write access (deploy and delete operations), set the
36+
environment variable FUNC_ENABLE_MCP_WRITE=true.
37+
38+
This is an experimental feature, and using an LLM to create and deploy
39+
code running on your cluster requires careful supervision. Functions is
40+
an inherently "mutative" tool, so enabling write mode for your LLM is
41+
essentially giving (sometimes unpredictable) AI the ability to create,
42+
modify, deploy, and delete Function instances on your currently connected
43+
cluster.
44+
45+
The command "{{rootCmdUse}} mcp start" is meant to be invoked by your MCP
46+
client (such as Claude Code, Cursor, VS Code, Windsurf, etc.); not run
47+
directly. Configure your client of choice with a new MCP server which runs
48+
this command. For example, in Claude Code this can be accomplished with:
49+
claude mcp add func func mcp start
50+
Instructions for other clients can be found at:
51+
https://github.com/knative/func/blob/main/docs/mcp-integration/integration.md
52+
53+
AVAILABLE COMMANDS
54+
start Start the MCP server (for use by your agent)
2655
2756
EXAMPLES
2857
29-
o Run an MCP server:
30-
{{rootCmdUse}} mcp
58+
o View this help:
59+
{{rootCmdUse}} mcp --help
60+
`,
61+
}
62+
63+
cmd.AddCommand(NewMCPStartCmd(newClient))
64+
65+
return cmd
66+
}
67+
68+
func NewMCPStartCmd(newClient ClientFactory) *cobra.Command {
69+
cmd := &cobra.Command{
70+
Use: "start",
71+
Short: "Start the MCP server",
72+
Long: `
73+
NAME
74+
{{rootCmdUse}} mcp start - start the Model Context Protocol (MCP) server
75+
76+
SYNOPSIS
77+
{{rootCmdUse}} mcp start [flags]
78+
79+
DESCRIPTION
80+
Starts the Model Context Protocol (MCP) server.
81+
82+
This command is designed to be invoked by MCP clients directly
83+
(such as Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, etc.);
84+
not run directly.
85+
86+
Please see '{{rootCmdUse}} mcp --help' for more information.
3187
`,
3288
RunE: func(cmd *cobra.Command, args []string) error {
33-
return runMCPServer(cmd, args)
89+
return runMCPStart(cmd, args, newClient)
3490
},
3591
}
92+
// no flags at this time; future enhancements may be to allow configuring
93+
// HTTP Stream vs stdio, single vs multiuser modes, etc. For now
94+
// we just use a simple gathering of options in runMCPServer.
3695
return cmd
3796
}
3897

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
98+
func runMCPStart(cmd *cobra.Command, args []string, newClient ClientFactory) error {
99+
// Configure write mode
100+
writeEnabled := false
101+
if val := os.Getenv("FUNC_ENABLE_MCP_WRITE"); val != "" {
102+
parsed, err := strconv.ParseBool(val)
103+
if err != nil {
104+
return fmt.Errorf("FUNC_ENABLE_MCP_WRITE shuold be a boolean (true/false, 1/0, etc). Received %q", val)
105+
}
106+
writeEnabled = parsed
44107
}
45-
return nil
108+
109+
// Configure 'func' or 'kn func'?
110+
rootCmd := cmd.Root()
111+
cmdPrefix := rootCmd.Use
112+
113+
// Instantiate
114+
client, done := newClient(ClientConfig{},
115+
fn.WithMCPServer(mcp.New(mcp.WithPrefix(cmdPrefix))))
116+
defer done()
117+
118+
// Start
119+
return client.StartMCPServer(cmd.Context(), writeEnabled)
120+
46121
}

cmd/mcp_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"os"
6+
"testing"
7+
8+
fn "knative.dev/func/pkg/functions"
9+
"knative.dev/func/pkg/mock"
10+
. "knative.dev/func/pkg/testing"
11+
)
12+
13+
// TestMCP_Start ensures the "mcp start" command starts the MCP server.
14+
func TestMCP_Start(t *testing.T) {
15+
_ = FromTempDirectory(t)
16+
17+
server := mock.NewMCPServer()
18+
19+
cmd := NewMCPCmd(NewTestClient(fn.WithMCPServer(server)))
20+
cmd.SetArgs([]string{"start"})
21+
if err := cmd.Execute(); err != nil {
22+
t.Fatal(err)
23+
}
24+
25+
if !server.StartInvoked {
26+
// Indicates a failure of the command to correctly map the request
27+
// for "mcp start" to an actual invocation of the client's
28+
// StartMCPServer method, or something more fundamental like failure
29+
// to register the subcommand, etc.
30+
t.Fatal("MCP server's start method not invoked")
31+
}
32+
}
33+
34+
// TestMCP_StartWriteable ensures that the server is started with write
35+
// enabled only when the environment variable FUNC_ENABLE_MCP_WRITE is set.
36+
func TestMCP_StartWriteable(t *testing.T) {
37+
_ = FromTempDirectory(t)
38+
39+
// Ensure it defaults to off.
40+
server := mock.NewMCPServer()
41+
server.StartFn = func(_ context.Context, writeEnabled bool) error {
42+
if writeEnabled {
43+
t.Fatal("MCP server started write-enabled by default")
44+
}
45+
return nil
46+
}
47+
cmd := NewMCPCmd(NewTestClient(fn.WithMCPServer(server)))
48+
cmd.SetArgs([]string{"start"})
49+
if err := cmd.Execute(); err != nil {
50+
t.Fatal(err)
51+
}
52+
53+
// Ensure it is set to true on proper truthy value
54+
_ = os.Setenv("FUNC_ENABLE_MCP_WRITE", "true")
55+
server = mock.NewMCPServer()
56+
server.StartFn = func(_ context.Context, writeEnabled bool) error {
57+
if !writeEnabled {
58+
t.Fatal("MCP server was not enabled")
59+
}
60+
return nil
61+
}
62+
cmd = NewMCPCmd(NewTestClient(fn.WithMCPServer(server)))
63+
cmd.SetArgs([]string{"start"})
64+
if err := cmd.Execute(); err != nil {
65+
t.Fatal(err)
66+
}
67+
}

cmd/root.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,18 +107,13 @@ 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-
},
116110
{
117111
Header: "Other Commands:",
118112
Commands: []*cobra.Command{
119113
NewCompletionCmd(),
120114
NewVersionCmd(cfg.Version),
121115
NewTektonClusterTasksCmd(),
116+
NewMCPCmd(newClient),
122117
},
123118
},
124119
}

docs/reference/func.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +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
37+
* [func mcp](func_mcp.md) - Model Context Protocol (MCP) server
3838
* [func repository](func_repository.md) - Manage installed template repositories
3939
* [func run](func_run.md) - Run the function locally
4040
* [func subscribe](func_subscribe.md) - Subscribe a function to events

docs/reference/func_mcp.md

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,52 @@
11
## func mcp
22

3-
Start MCP server
3+
Model Context Protocol (MCP) server
44

55
### Synopsis
66

77

88
NAME
9-
func mcp - start a Model Context Protocol (MCP) server
9+
func mcp - Model Context Protocol (MCP) server
1010

1111
SYNOPSIS
12-
func mcp [flags]
13-
12+
func mcp [command] [flags]
1413
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.
14+
The Functions Model Context Protocol (MCP) server can be used to give
15+
agents the power of Functions.
1716

18-
Note: This command is still under development.
17+
Configure your agentic client to use the MCP server with command
18+
"func mcp start". Then get the conversation started with
1919

20-
EXAMPLES
20+
"Let's create a Function!".
2121

22-
o Run an MCP server:
23-
func mcp
22+
By default the MCP server operates in read-only mode, allowing Function
23+
creation, building, and inspection, but preventing deployment and deletion.
24+
To enable full write access (deploy and delete operations), set the
25+
environment variable FUNC_ENABLE_MCP_WRITE=true.
2426

27+
This is an experimental feature, and using an LLM to create and deploy
28+
code running on your cluster requires careful supervision. Functions is
29+
an inherently "mutative" tool, so enabling write mode for your LLM is
30+
essentially giving (sometimes unpredictable) AI the ability to create,
31+
modify, deploy, and delete Function instances on your currently connected
32+
cluster.
33+
34+
The command "func mcp start" is meant to be invoked by your MCP
35+
client (such as Claude Code, Cursor, VS Code, Windsurf, etc.); not run
36+
directly. Configure your client of choice with a new MCP server which runs
37+
this command. For example, in Claude Code this can be accomplished with:
38+
claude mcp add func func mcp start
39+
Instructions for other clients can be found at:
40+
https://github.com/knative/func/blob/main/docs/mcp-integration/integration.md
41+
42+
AVAILABLE COMMANDS
43+
start Start the MCP server (for use by your agent)
44+
45+
EXAMPLES
46+
47+
o View this help:
48+
func mcp --help
2549

26-
```
27-
func mcp
28-
```
2950

3051
### Options
3152

@@ -36,4 +57,5 @@ func mcp
3657
### SEE ALSO
3758

3859
* [func](func.md) - func manages Knative Functions
60+
* [func mcp start](func_mcp_start.md) - Start the MCP server
3961

docs/reference/func_mcp_start.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
## func mcp start
2+
3+
Start the MCP server
4+
5+
### Synopsis
6+
7+
8+
NAME
9+
func mcp start - start the Model Context Protocol (MCP) server
10+
11+
SYNOPSIS
12+
func mcp start [flags]
13+
14+
DESCRIPTION
15+
Starts the Model Context Protocol (MCP) server.
16+
17+
This command is designed to be invoked by MCP clients directly
18+
(such as Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, etc.);
19+
not run directly.
20+
21+
Please see 'func mcp --help' for more information.
22+
23+
24+
```
25+
func mcp start
26+
```
27+
28+
### Options
29+
30+
```
31+
-h, --help help for start
32+
```
33+
34+
### SEE ALSO
35+
36+
* [func mcp](func_mcp.md) - Model Context Protocol (MCP) server
37+

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ require (
3939
github.com/hinshun/vt10x v0.0.0-20220228203356-1ab2cad5fd82
4040
github.com/manifestival/client-go-client v0.6.0
4141
github.com/manifestival/manifestival v0.7.2
42-
github.com/mark3labs/mcp-go v0.30.0
42+
github.com/modelcontextprotocol/go-sdk v1.1.0
4343
github.com/opencontainers/image-spec v1.1.1
4444
github.com/openshift-pipelines/pipelines-as-code v0.31.0
4545
github.com/openshift/source-to-image v1.6.0
@@ -171,6 +171,7 @@ require (
171171
github.com/google/gnostic-models v0.6.9 // indirect
172172
github.com/google/go-intervals v0.0.2 // indirect
173173
github.com/google/go-querystring v1.1.0 // indirect
174+
github.com/google/jsonschema-go v0.3.0 // indirect
174175
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
175176
github.com/gorilla/mux v1.8.1 // indirect
176177
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect

0 commit comments

Comments
 (0)