110 lines
3.1 KiB
Go
110 lines
3.1 KiB
Go
package mcp
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp"
|
|
"github.com/rs/zerolog/log"
|
|
"github.com/spf13/viper"
|
|
|
|
"git.coopgo.io/coopgo-apps/parcoursmob/core/application"
|
|
"git.coopgo.io/coopgo-apps/parcoursmob/core/utils/geo"
|
|
cache "git.coopgo.io/coopgo-apps/parcoursmob/core/utils/storage"
|
|
"git.coopgo.io/coopgo-apps/parcoursmob/services"
|
|
)
|
|
|
|
// MCPServer represents the MCP HTTP server
|
|
type MCPServer struct {
|
|
cfg *viper.Viper
|
|
services *services.ServicesHandler
|
|
kv cache.KVHandler
|
|
filestorage cache.FileStorage
|
|
applicationHandler *application.ApplicationHandler
|
|
mcpServer *mcpsdk.Server
|
|
geoService *geo.GeoService
|
|
}
|
|
|
|
// NewMCPServer creates a new MCP server instance
|
|
func NewMCPServer(
|
|
cfg *viper.Viper,
|
|
svc *services.ServicesHandler,
|
|
applicationHandler *application.ApplicationHandler,
|
|
kv cache.KVHandler,
|
|
filestorage cache.FileStorage,
|
|
) *MCPServer {
|
|
// Initialize geocoding service
|
|
geoType := cfg.GetString("geo.type")
|
|
baseURL := cfg.GetString("geo." + geoType + ".url")
|
|
autocompleteEndpoint := cfg.GetString("geo." + geoType + ".autocomplete")
|
|
geoService := geo.NewGeoService(geoType, baseURL, autocompleteEndpoint)
|
|
|
|
server := &MCPServer{
|
|
cfg: cfg,
|
|
services: svc,
|
|
kv: kv,
|
|
filestorage: filestorage,
|
|
applicationHandler: applicationHandler,
|
|
geoService: geoService,
|
|
}
|
|
|
|
// Create MCP server with implementation info
|
|
server.mcpServer = mcpsdk.NewServer(&mcpsdk.Implementation{
|
|
Name: "parcoursmob-mcp-server",
|
|
Version: "1.0.0",
|
|
}, nil)
|
|
|
|
// Register journey search tool
|
|
server.registerJourneySearchTool()
|
|
|
|
return server
|
|
}
|
|
|
|
// Run starts the MCP HTTP server with SSE transport
|
|
func Run(
|
|
cfg *viper.Viper,
|
|
svc *services.ServicesHandler,
|
|
applicationHandler *application.ApplicationHandler,
|
|
kv cache.KVHandler,
|
|
filestorage cache.FileStorage,
|
|
) {
|
|
address := cfg.GetString("server.mcp.listen")
|
|
service_name := cfg.GetString("service_name")
|
|
|
|
mcpServer := NewMCPServer(cfg, svc, applicationHandler, kv, filestorage)
|
|
|
|
// Create HTTP server with SSE transport
|
|
mux := http.NewServeMux()
|
|
|
|
// Health check endpoint
|
|
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(`{"status":"healthy"}`))
|
|
})
|
|
|
|
// MCP Streamable HTTP endpoint (preferred over SSE as of 2025-03-26 spec)
|
|
streamHandler := mcpsdk.NewStreamableHTTPHandler(func(r *http.Request) *mcpsdk.Server {
|
|
return mcpServer.mcpServer
|
|
}, nil)
|
|
mux.Handle("/", streamHandler)
|
|
|
|
// Also support legacy SSE endpoint for backwards compatibility
|
|
sseHandler := mcpsdk.NewSSEHandler(func(r *http.Request) *mcpsdk.Server {
|
|
return mcpServer.mcpServer
|
|
}, nil)
|
|
mux.Handle("/sse", sseHandler)
|
|
|
|
srv := &http.Server{
|
|
Handler: mux,
|
|
Addr: address,
|
|
WriteTimeout: 60 * time.Second,
|
|
ReadTimeout: 30 * time.Second,
|
|
}
|
|
|
|
log.Info().Str("service_name", service_name).Str("address", address).Msg("Running MCP HTTP server with SSE transport")
|
|
|
|
err := srv.ListenAndServe()
|
|
log.Error().Err(err).Msg("MCP server error")
|
|
}
|