diff --git a/go.mod b/go.mod index b1d97c054..dcff24fd2 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 7e7a71e44..d9ff40632 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/server/mcp/logger.go b/server/mcp/logger.go deleted file mode 100644 index 9e8f2d2d8..000000000 --- a/server/mcp/logger.go +++ /dev/null @@ -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...) -} diff --git a/server/mcp/mcp.go b/server/mcp/mcp.go index 13110db0c..4ade6ae6c 100644 --- a/server/mcp/mcp.go +++ b/server/mcp/mcp.go @@ -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{}, + } +} diff --git a/server/mcp/prompt.go b/server/mcp/prompt.go index beb08f7bf..8756a6c49 100644 --- a/server/mcp/prompt.go +++ b/server/mcp/prompt.go @@ -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 diff --git a/server/mcp/tools.go b/server/mcp/tools.go index e376526a1..2951b5f44 100644 --- a/server/mcp/tools.go +++ b/server/mcp/tools.go @@ -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 }