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")
 | 
						|
}
 |