84 lines
1.9 KiB
Go
84 lines
1.9 KiB
Go
package mcp
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/http/httputil"
|
|
|
|
"github.com/evcc-io/evcc/util"
|
|
openapi2mcp "github.com/evcc-io/openapi-mcp"
|
|
"github.com/getkin/kin-openapi/openapi3"
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
)
|
|
|
|
//go:embed openapi.json
|
|
var spec []byte
|
|
|
|
func NewHandler(host http.Handler) (http.Handler, error) {
|
|
log := util.NewLogger("mcp")
|
|
|
|
var doc *openapi3.T
|
|
if err := json.Unmarshal(spec, &doc); err != nil {
|
|
return nil, fmt.Errorf("failed to load OpenAPI spec: %v", err)
|
|
}
|
|
|
|
if err := openapi3.NewLoader().ResolveRefsIn(doc, nil); err != nil {
|
|
return nil, fmt.Errorf("failed resolving OpenAPI spec references: %v", err)
|
|
}
|
|
|
|
// required for the /api path
|
|
doc.Servers = []*openapi3.Server{{
|
|
URL: "http://localhost:7070/api",
|
|
Description: "evcc api",
|
|
}}
|
|
|
|
ops := openapi2mcp.ExtractOpenAPIOperations(doc)
|
|
|
|
srv := mcp.NewServer(&mcp.Implementation{Name: "evcc", Version: util.Version}, nil)
|
|
|
|
openapi2mcp.RegisterOpenAPITools(srv, ops, doc, &openapi2mcp.ToolGenOptions{
|
|
TagFilter: []string{
|
|
"general",
|
|
"tariffs",
|
|
"loadpoints",
|
|
"vehicles",
|
|
"battery",
|
|
"state",
|
|
"sessions",
|
|
"experimental",
|
|
},
|
|
RequestHandler: requestHandler(log, host),
|
|
})
|
|
|
|
mcp.AddTool(srv, &mcp.Tool{
|
|
Name: "docs",
|
|
Description: "Documentation",
|
|
}, docsTool)
|
|
|
|
handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server {
|
|
return srv
|
|
}, nil)
|
|
|
|
return handler, nil
|
|
}
|
|
|
|
func requestHandler(log *util.Logger, handler http.Handler) func(req *http.Request) (*http.Response, error) {
|
|
return func(req *http.Request) (*http.Response, error) {
|
|
if r, err := httputil.DumpRequest(req, true); err == nil {
|
|
log.TRACE.Println(string(r))
|
|
}
|
|
|
|
w := httptest.NewRecorder()
|
|
handler.ServeHTTP(w, req)
|
|
resp := w.Result()
|
|
|
|
if r, err := httputil.DumpResponse(resp, true); err == nil {
|
|
log.TRACE.Println(string(r))
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
}
|