Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
/pkg/functions/testdata/default_home/go
/pkg/functions/testdata/default_home/.cache
/pkg/functions/testdata/migrations/*/.gitignore
/pkg/creds/auth.json
/pkg/oci/testdata/test-links/absoluteLink
/pkg/oci/testdata/test-links/absoluteLinkWindows

# Go
/templates/go/cloudevents/go.sum
Expand Down
113 changes: 94 additions & 19 deletions cmd/mcp.go
Original file line number Diff line number Diff line change
@@ -1,46 +1,121 @@
package cmd

import (
"log"
"fmt"
"os"
"strconv"

"github.com/spf13/cobra"
"knative.dev/func/pkg/mcp"

fn "knative.dev/func/pkg/functions"
)

func NewMCPServerCmd() *cobra.Command {
func NewMCPCmd(newClient ClientFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "mcp",
Short: "Start MCP server",
Short: "Model Context Protocol (MCP) server",
Long: `
NAME
{{rootCmdUse}} mcp - start a Model Context Protocol (MCP) server
{{rootCmdUse}} mcp - Model Context Protocol (MCP) server

SYNOPSIS
{{rootCmdUse}} mcp [flags]

{{rootCmdUse}} mcp [command] [flags]
DESCRIPTION
Starts a Model Context Protocol (MCP) server over standard input/output (stdio) transport.
This implementation aims to support tools for deploying and creating serverless functions.

Note: This command is still under development.
The Functions Model Context Protocol (MCP) server can be used to give
agents the power of Functions.

Configure your agentic client to use the MCP server with command
"{{rootCmdUse}} mcp start". Then get the conversation started with

"Let's create a Function!".

By default the MCP server operates in read-only mode, allowing Function
creation, building, and inspection, but preventing deployment and deletion.
To enable full write access (deploy and delete operations), set the
environment variable FUNC_ENABLE_MCP_WRITE=true.

This is an experimental feature, and using an LLM to create and deploy
code running on your cluster requires careful supervision. Functions is
an inherently "mutative" tool, so enabling write mode for your LLM is
essentially giving (sometimes unpredictable) AI the ability to create,
modify, deploy, and delete Function instances on your currently connected
cluster.

The command "{{rootCmdUse}} mcp start" is meant to be invoked by your MCP
client (such as Claude Code, Cursor, VS Code, Windsurf, etc.); not run
directly. Configure your client of choice with a new MCP server which runs
this command. For example, in Claude Code this can be accomplished with:
claude mcp add func func mcp start
Instructions for other clients can be found at:
https://github.com/knative/func/blob/main/docs/mcp-integration/integration.md

AVAILABLE COMMANDS
start Start the MCP server (for use by your agent)

EXAMPLES

o Run an MCP server:
{{rootCmdUse}} mcp
o View this help:
{{rootCmdUse}} mcp --help
`,
}

cmd.AddCommand(NewMCPStartCmd(newClient))

return cmd
}

func NewMCPStartCmd(newClient ClientFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "start",
Short: "Start the MCP server",
Long: `
NAME
{{rootCmdUse}} mcp start - start the Model Context Protocol (MCP) server

SYNOPSIS
{{rootCmdUse}} mcp start [flags]

DESCRIPTION
Starts the Model Context Protocol (MCP) server.

This command is designed to be invoked by MCP clients directly
(such as Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, etc.);
not run directly.

Please see '{{rootCmdUse}} mcp --help' for more information.
`,
RunE: func(cmd *cobra.Command, args []string) error {
return runMCPServer(cmd, args)
return runMCPStart(cmd, args, newClient)
},
}
// no flags at this time; future enhancements may be to allow configuring
// HTTP Stream vs stdio, single vs multiuser modes, etc. For now
// we just use a simple gathering of options in runMCPServer.
return cmd
}

func runMCPServer(cmd *cobra.Command, args []string) error {
s := mcp.NewServer()
if err := s.Start(); err != nil {
log.Fatalf("Server error: %v", err)
return err
func runMCPStart(cmd *cobra.Command, args []string, newClient ClientFactory) error {
// Configure write mode
writeEnabled := false
if val := os.Getenv("FUNC_ENABLE_MCP_WRITE"); val != "" {
parsed, err := strconv.ParseBool(val)
if err != nil {
return fmt.Errorf("FUNC_ENABLE_MCP_WRITE shuold be a boolean (true/false, 1/0, etc). Received %q", val)
}
writeEnabled = parsed
}
return nil

// Configure 'func' or 'kn func'?
rootCmd := cmd.Root()
cmdPrefix := rootCmd.Use

// Instantiate
client, done := newClient(ClientConfig{},
fn.WithMCPServer(mcp.New(mcp.WithPrefix(cmdPrefix))))
defer done()

// Start
return client.StartMCPServer(cmd.Context(), writeEnabled)

}
67 changes: 67 additions & 0 deletions cmd/mcp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package cmd

import (
"context"
"os"
"testing"

fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/mock"
. "knative.dev/func/pkg/testing"
)

// TestMCP_Start ensures the "mcp start" command starts the MCP server.
func TestMCP_Start(t *testing.T) {
_ = FromTempDirectory(t)

server := mock.NewMCPServer()

cmd := NewMCPCmd(NewTestClient(fn.WithMCPServer(server)))
cmd.SetArgs([]string{"start"})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}

if !server.StartInvoked {
// Indicates a failure of the command to correctly map the request
// for "mcp start" to an actual invocation of the client's
// StartMCPServer method, or something more fundamental like failure
// to register the subcommand, etc.
t.Fatal("MCP server's start method not invoked")
}
}

// TestMCP_StartWriteable ensures that the server is started with write
// enabled only when the environment variable FUNC_ENABLE_MCP_WRITE is set.
func TestMCP_StartWriteable(t *testing.T) {
_ = FromTempDirectory(t)

// Ensure it defaults to off.
server := mock.NewMCPServer()
server.StartFn = func(_ context.Context, writeEnabled bool) error {
if writeEnabled {
t.Fatal("MCP server started write-enabled by default")
}
return nil
}
cmd := NewMCPCmd(NewTestClient(fn.WithMCPServer(server)))
cmd.SetArgs([]string{"start"})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}

// Ensure it is set to true on proper truthy value
_ = os.Setenv("FUNC_ENABLE_MCP_WRITE", "true")
server = mock.NewMCPServer()
server.StartFn = func(_ context.Context, writeEnabled bool) error {
if !writeEnabled {
t.Fatal("MCP server was not enabled")
}
return nil
}
cmd = NewMCPCmd(NewTestClient(fn.WithMCPServer(server)))
cmd.SetArgs([]string{"start"})
if err := cmd.Execute(); err != nil {
t.Fatal(err)
}
}
7 changes: 1 addition & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,13 @@ Learn more about Knative at: https://knative.dev`, cfg.Name),
NewEnvironmentCmd(newClient, &cfg.Version),
},
},
{
Header: "MCP Commands:",
Commands: []*cobra.Command{
NewMCPServerCmd(),
},
},
{
Header: "Other Commands:",
Commands: []*cobra.Command{
NewCompletionCmd(),
NewVersionCmd(cfg.Version),
NewTektonClusterTasksCmd(),
NewMCPCmd(newClient),
},
},
}
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/func.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Learn more about Knative at: https://knative.dev
* [func invoke](func_invoke.md) - Invoke a local or remote function
* [func languages](func_languages.md) - List available function language runtimes
* [func list](func_list.md) - List deployed functions
* [func mcp](func_mcp.md) - Start MCP server
* [func mcp](func_mcp.md) - Model Context Protocol (MCP) server
* [func repository](func_repository.md) - Manage installed template repositories
* [func run](func_run.md) - Run the function locally
* [func subscribe](func_subscribe.md) - Subscribe a function to events
Expand Down
48 changes: 35 additions & 13 deletions docs/reference/func_mcp.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,52 @@
## func mcp

Start MCP server
Model Context Protocol (MCP) server

### Synopsis


NAME
func mcp - start a Model Context Protocol (MCP) server
func mcp - Model Context Protocol (MCP) server

SYNOPSIS
func mcp [flags]

func mcp [command] [flags]
DESCRIPTION
Starts a Model Context Protocol (MCP) server over standard input/output (stdio) transport.
This implementation aims to support tools for deploying and creating serverless functions.
The Functions Model Context Protocol (MCP) server can be used to give
agents the power of Functions.

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

EXAMPLES
"Let's create a Function!".

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

This is an experimental feature, and using an LLM to create and deploy
code running on your cluster requires careful supervision. Functions is
an inherently "mutative" tool, so enabling write mode for your LLM is
essentially giving (sometimes unpredictable) AI the ability to create,
modify, deploy, and delete Function instances on your currently connected
cluster.

The command "func mcp start" is meant to be invoked by your MCP
client (such as Claude Code, Cursor, VS Code, Windsurf, etc.); not run
directly. Configure your client of choice with a new MCP server which runs
this command. For example, in Claude Code this can be accomplished with:
claude mcp add func func mcp start
Instructions for other clients can be found at:
https://github.com/knative/func/blob/main/docs/mcp-integration/integration.md

AVAILABLE COMMANDS
start Start the MCP server (for use by your agent)

EXAMPLES

o View this help:
func mcp --help

```
func mcp
```

### Options

Expand All @@ -36,4 +57,5 @@ func mcp
### SEE ALSO

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

37 changes: 37 additions & 0 deletions docs/reference/func_mcp_start.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## func mcp start

Start the MCP server

### Synopsis


NAME
func mcp start - start the Model Context Protocol (MCP) server

SYNOPSIS
func mcp start [flags]

DESCRIPTION
Starts the Model Context Protocol (MCP) server.

This command is designed to be invoked by MCP clients directly
(such as Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, etc.);
not run directly.

Please see 'func mcp --help' for more information.


```
func mcp start
```

### Options

```
-h, --help help for start
```

### SEE ALSO

* [func mcp](func_mcp.md) - Model Context Protocol (MCP) server

3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ require (
github.com/hinshun/vt10x v0.0.0-20220228203356-1ab2cad5fd82
github.com/manifestival/client-go-client v0.6.0
github.com/manifestival/manifestival v0.7.2
github.com/mark3labs/mcp-go v0.30.0
github.com/modelcontextprotocol/go-sdk v1.1.0
github.com/opencontainers/image-spec v1.1.1
github.com/openshift-pipelines/pipelines-as-code v0.31.0
github.com/openshift/source-to-image v1.6.0
Expand Down Expand Up @@ -171,6 +171,7 @@ require (
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-intervals v0.0.2 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/jsonschema-go v0.3.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
Expand Down
Loading
Loading