Switch MCP implementation to modelcontextprotocol/go-sdk (#22859)

This commit is contained in:
andig 2025-08-10 11:14:36 +02:00 • committed by GitHub
parent 11e7c13f01
commit 7990146bb3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 58 additions and 84 deletions

11
go.mod
View file

@ -33,7 +33,7 @@ require (
github.com/enbility/eebus-go v0.7.0
github.com/enbility/ship-go v0.6.0
github.com/enbility/spine-go v0.7.0
github.com/evcc-io/openapi-mcp v0.3.1-0.20250702152714-5af774c51f55
github.com/evcc-io/openapi-mcp v0.3.2-0.20250810085124-11eaedf32359
github.com/evcc-io/rct v0.1.2-0.20250315164247-d2f41b161785
github.com/evcc-io/tesla-proxy-client v0.0.0-20240221194046-4168b3759701
github.com/fatih/structs v1.1.0
@ -72,8 +72,8 @@ require (
github.com/lorenzodonini/ocpp-go v0.19.0
github.com/lunixbochs/struc v0.0.0-20241101090106-8d528fa2c543
github.com/mabunixda/wattpilot v1.8.5
github.com/mark3labs/mcp-go v0.37.0
github.com/mitchellh/go-homedir v1.1.0
github.com/modelcontextprotocol/go-sdk v0.2.0
github.com/muka/go-bluetooth v0.0.0-20240701044517-04c4f09c514e
github.com/mxschmitt/golang-combinations v1.2.0
github.com/nicksnyder/go-i18n/v2 v2.6.0
@ -133,11 +133,9 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.36.0 // indirect
github.com/aws/smithy-go v1.22.5 // indirect
github.com/azihsoyn/rijndael256 v0.0.0-20200316065338-d14eefa2b66b // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bitly/go-simplejson v0.5.0 // indirect
github.com/breml/rootcerts v0.2.21 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
@ -178,7 +176,6 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect
github.com/insomniacslk/xjson v0.0.0-20240821125711-1236daaf6808 // indirect
github.com/invopop/jsonschema v0.13.0 // indirect
github.com/itchyny/timefmt-go v0.1.6 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
@ -230,10 +227,6 @@ require (
github.com/teivah/onecontext v1.3.0 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a // indirect
go.uber.org/multierr v1.11.0 // indirect

22
go.sum
View file

@ -86,8 +86,6 @@ github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw=
github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/azihsoyn/rijndael256 v0.0.0-20200316065338-d14eefa2b66b h1:/2dABok/UswXOj5rjbR5bZ411ApGBq1pAEZdy5rvFrY=
github.com/azihsoyn/rijndael256 v0.0.0-20200316065338-d14eefa2b66b/go.mod h1:ef+2vMUkiKcy2Tz7HykB01KbgUnkK4gQKq4ZeR4RYVs=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUKVw=
github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw=
github.com/basvdlei/gotsmart v0.0.3 h1:7hrI6btBc8dmFzzHRDkr9Xl87PvrrOT43DzbsTFqMk8=
@ -106,8 +104,6 @@ github.com/bogosj/tesla v1.3.1 h1:2iTieXh8jqG8FGWs63aQfRWbD7toLUm6fQ7677eevIE=
github.com/bogosj/tesla v1.3.1/go.mod h1:JvkjZAswd288BeRYd37fKqyYKLcDj3E5oY/OuLzndaI=
github.com/breml/rootcerts v0.2.21 h1:A1LU8pJgdkAfBwPKF0GkPNSyW7stGh80K90LbEiQqY8=
github.com/breml/rootcerts v0.2.21/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
@ -189,8 +185,8 @@ github.com/evcc-io/modbus v0.0.0-20250501165638-8b6f1fbdb7ea h1:F6eyC8V8wvc3ranl
github.com/evcc-io/modbus v0.0.0-20250501165638-8b6f1fbdb7ea/go.mod h1:swrNGAVgI1r/3d/sEKE7qgujdRR9aHVPYKyc3gvpVTc=
github.com/evcc-io/ocpp-go v0.0.0-20250322092544-c0c6094051c0 h1:Qz34Pm1Wr05jjJia5g2On3zRqdZh+BLTwqHgJGsiIh4=
github.com/evcc-io/ocpp-go v0.0.0-20250322092544-c0c6094051c0/go.mod h1:2kcukDdhui4u730VfnYVWuwzDLgw+mBRGDir/QAyBhg=
github.com/evcc-io/openapi-mcp v0.3.1-0.20250702152714-5af774c51f55 h1:baokU1QbbfUSJ5esFqShKj2M2j/COBRXK0eHkS7kxyU=
github.com/evcc-io/openapi-mcp v0.3.1-0.20250702152714-5af774c51f55/go.mod h1:4KTo8DTLU2BswZLX0hknHRZBavDrLOikKNzIKaq0Z40=
github.com/evcc-io/openapi-mcp v0.3.2-0.20250810085124-11eaedf32359 h1:VrNkGZmSfBDKuAeFbg/Vz3oDN9z1Q3XQ4vS415Jr6Jw=
github.com/evcc-io/openapi-mcp v0.3.2-0.20250810085124-11eaedf32359/go.mod h1:87GSlXX1DP8ne5ELpm18vst5yiMmDFeSRG8xYL1BfzQ=
github.com/evcc-io/rct v0.1.2-0.20250315164247-d2f41b161785 h1:OWCBVMcPsVTffdiZN3VYaq9p4fsWlzd490J6pekaKLA=
github.com/evcc-io/rct v0.1.2-0.20250315164247-d2f41b161785/go.mod h1:n6MTBU36QOadGlxxiADu86VaT5l0eYdbmFBHF14AD/s=
github.com/evcc-io/tesla-proxy-client v0.0.0-20240221194046-4168b3759701 h1:3JplY3KS6KMDVDNAU+3+KWmSWmoHIU34qwuIpW6SiHk=
@ -399,8 +395,6 @@ github.com/insomniacslk/tapo v1.0.1 h1:W7K/1SXR8fvCNqY1Qg+GB3ELUjsHAqXtBjBjes7aR
github.com/insomniacslk/tapo v1.0.1/go.mod h1:1wuMYu0+alZ4oE4BIzxAwQNveZgbb2tRqiIUwIe7SZE=
github.com/insomniacslk/xjson v0.0.0-20240821125711-1236daaf6808 h1:BVD0pRpDWgbzkPYACLLPomriAnUGVfFdFoxs7aCLJkY=
github.com/insomniacslk/xjson v0.0.0-20240821125711-1236daaf6808/go.mod h1:Z4EVr4bVv9LZbbje9xyZEyOLpdCOmCvr5S9BJtrdTfw=
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/itchyny/gojq v0.12.17 h1:8av8eGduDb5+rvEdaOO+zQUjA04MS0m3Ps8HiD+fceg=
github.com/itchyny/gojq v0.12.17/go.mod h1:WBrEMkgAfAGO1LUcGOckBl5O726KPp+OlkKug0I/FEY=
github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q=
@ -473,8 +467,6 @@ github.com/mabunixda/wattpilot v1.8.5 h1:pjm//7dnEiR0OHfMZ+SLlLV557Y0LMrxgjwudOs
github.com/mabunixda/wattpilot v1.8.5/go.mod h1:RmwAAYZooC8Qg/KjfrfYYtaMiE0HKp16/0dUnJYmICg=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mark3labs/mcp-go v0.37.0 h1:BywvZLPRT6Zx6mMG/MJfxLSZQkTGIcJSEGKsvr4DsoQ=
github.com/mark3labs/mcp-go v0.37.0/go.mod h1:T7tUa2jO6MavG+3P25Oy/jR7iCeJPHImCZHRymCn39g=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
@ -512,6 +504,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modelcontextprotocol/go-sdk v0.2.0 h1:PESNYOmyM1c369tRkzXLY5hHrazj8x9CY1Xu0fLCryM=
github.com/modelcontextprotocol/go-sdk v0.2.0/go.mod h1:0sL9zUKKs2FTTkeCCVnKqbLJTw5TScefPAzojjU459E=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -757,16 +751,8 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/volkszaehler/mbmd v0.0.0-20250808161051-499ae856f44e h1:I70valHO57SjmIBUDH94MzbJfevj2rZ2fN2YrZ8IwB4=
github.com/volkszaehler/mbmd v0.0.0-20250808161051-499ae856f44e/go.mod h1:egeAZti78O7U6QcdDPze5NHiiLdPSviw6YA7rsNYSMQ=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/writeas/go-strip-markdown/v2 v2.1.1 h1:hAxUM21Uhznf/FnbVGiJciqzska6iLei22Ijc3q2e28=
github.com/writeas/go-strip-markdown/v2 v2.1.1/go.mod h1:UvvgPJgn1vvN8nWuE5e7v/+qmDu3BSVnKAB6Gl7hFzA=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=

View file

@ -1,15 +0,0 @@
package mcp
import "github.com/evcc-io/evcc/util"
type logger struct {
log *util.Logger
}
func (l *logger) Infof(format string, v ...any) {
l.log.TRACE.Printf(format, v...)
}
func (l *logger) Errorf(format string, v ...any) {
l.log.WARN.Printf(format, v...)
}

View file

@ -10,10 +10,10 @@ import (
"strings"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/openapi-mcp/pkg/openapi2mcp"
openapi2mcp "github.com/evcc-io/openapi-mcp"
"github.com/getkin/kin-openapi/openapi3"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/modelcontextprotocol/go-sdk/jsonschema"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
//go:embed openapi.json
@ -39,9 +39,7 @@ func NewHandler(host http.Handler, baseUrl, basePath string) (http.Handler, erro
ops := openapi2mcp.ExtractOpenAPIOperations(doc)
srv := server.NewMCPServer("evcc", util.Version,
server.WithLogging(),
)
srv := mcp.NewServer(&mcp.Implementation{Name: "evcc", Version: util.Version}, nil)
openapi2mcp.RegisterOpenAPITools(srv, ops, doc, &openapi2mcp.ToolGenOptions{
NameFormat: nameFormat(log),
@ -55,24 +53,24 @@ func NewHandler(host http.Handler, baseUrl, basePath string) (http.Handler, erro
RequestHandler: requestHandler(host),
})
srv.AddTool(mcp.NewTool("docs",
mcp.WithDescription("Documentation"),
), docsTool)
mcp.AddTool(srv, &mcp.Tool{
Name: "docs",
Description: "Documentation",
InputSchema: emptySchema(),
}, docsTool)
srv.AddPrompt(mcp.NewPrompt("create-charge-plan",
mcp.WithPromptDescription("Create an optimized charge plan for a loadpoint or vehicle"),
mcp.WithArgument("loadpoint",
mcp.ArgumentDescription("The loadpoint to create the charge plan for"),
),
mcp.WithArgument("vehicle",
mcp.ArgumentDescription("The vehicle to create the charge plan for"),
),
), promptHandler())
srv.AddPrompt(&mcp.Prompt{
Name: "create-charge-plan",
Description: "Create an optimized charge plan for a loadpoint or vehicle",
Arguments: []*mcp.PromptArgument{
{Name: "loadpoint", Description: "The loadpoint to create the charge plan for"},
{Name: "vehicle", Description: "The vehicle to create the charge plan for"},
},
}, promptHandler())
handler := server.NewStreamableHTTPServer(srv,
server.WithEndpointPath(basePath),
server.WithLogger(&logger{log}),
)
handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server {
return srv
}, nil)
return handler, nil
}
@ -111,3 +109,10 @@ func requestHandler(handler http.Handler) func(req *http.Request) (*http.Respons
return resp, nil
}
}
func emptySchema() *jsonschema.Schema {
return &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{},
}
}

View file

@ -8,35 +8,35 @@ import (
"html/template"
"github.com/Masterminds/sprig/v3"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
//go:embed prompt.tpl
var prompt string
func promptHandler() server.PromptHandlerFunc {
func promptHandler() mcp.PromptHandler {
tmpl := template.Must(template.New("out").Funcs(sprig.FuncMap()).Parse(prompt))
return func(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
// tmpl, err := template.New("out").Funcs(sprig.FuncMap()).Parse(prompt)
// if err != nil {
// return nil, fmt.Errorf("error parsing template: %v", err)
// }
return func(ctx context.Context, ss *mcp.ServerSession, params *mcp.GetPromptParams) (*mcp.GetPromptResult, error) {
out := new(bytes.Buffer)
if err := tmpl.Execute(out, req.Params.Arguments); err != nil {
return nil, fmt.Errorf("failed executing template: %v", err)
if err := tmpl.Execute(out, params.Arguments); err != nil {
return &mcp.GetPromptResult{
Messages: []*mcp.PromptMessage{
{
Role: "assistant",
Content: &mcp.TextContent{
Text: fmt.Sprintf("The was an error parsing the request: %v", err),
},
},
},
}, nil
}
return &mcp.GetPromptResult{
Messages: []mcp.PromptMessage{
Messages: []*mcp.PromptMessage{
{
Role: mcp.RoleAssistant,
Content: mcp.TextContent{
Type: "text",
Text: out.String(),
},
Role: "assistant",
Content: &mcp.TextContent{Text: out.String()},
},
},
}, nil

View file

@ -3,13 +3,18 @@ package mcp
import (
"context"
"github.com/mark3labs/mcp-go/mcp"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
func docsTool(_ context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResult, error) {
func docsTool(_ context.Context, _ *mcp.ServerSession, _ *mcp.CallToolParams) (*mcp.CallToolResult, error) {
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.NewResourceLink("https://docs.evcc.io", "evcc-docs", "evcc documentation", "text/html"),
&mcp.ResourceLink{
URI: "https://docs.evcc.io",
Name: "evcc-docs",
Title: "evcc documentation",
MIMEType: "text/html",
},
},
}, nil
}