mcp-go icon indicating copy to clipboard operation
mcp-go copied to clipboard

feature: Generic server handler and/or fasthttp support

Open mjarkk opened this issue 6 months ago • 2 comments

Problem Statement

I'm trying to use this the streamable http server from this package from within an existing server that uses fiber as it's webserver. Under the hood fiber uses fasthttp and not go their own http server.

I've tried 2 things to implement this (somewhat cleanly) so far but both result in panics from within the go-mcp package:

Attempt 1:

var s *server.MCPServer

func createServer() {
	s = server.NewMCPServer("server", "1.0.0")
}

func handlePost(c *fiber.Ctx) error {
	return c.Send(s.HandleMessage(context.Background(), c.Body()))
}

Attempt 2:

var httpServer *server.StreamableHTTPServer

func createServer() {
	httpServer = server.NewStreamableHTTPServer(
		server.NewMCPServer("server", "1.0.0"),
	)
}

func handlePost(c *fiber.Ctx) error {
	httpRequestBody := bytes.NewBuffer(c.Body())
	httpRequest, err := http.NewRequest("POST", "http://localhost:8000/mcp", httpRequestBody)
	if err != nil {
		return err
	}

	const forServer = false
	err = fasthttpadaptor.ConvertRequest(c.Context(), httpRequest, forServer)
	if err != nil {
		return err
	}

  // Note that i have not included the code for HttpCompliantResponseWriter but it's basically a simple collector for the http.ResponseWriter interface
	responseWriter := &HttpCompliantResponseWriter{}
	httpServer.ServeHTTP(responseWriter, httpRequest)
	
	// Note that this is most likely not spec compliant but only for debugging perposes to see if this works
	return c.Status(responseWriter.StatusCode).Send(responseWriter.Bytes)
}

Proposed Solution

A fasthttp specific implementation would be amazing. But that's an extra dependency and it might only be for a very little amound of users.

Personally i would like to have some sort of generic method i can call for a streamable http server so i can use this everywhere with every http server.

For example:

var httpServer *server.GenericStreamableHTTPServer

func createServer() {
	httpServer = server.NewGenericStreamableHTTPServer(
		server.NewMCPServer("server", "1.0.0"),
	)
}

func handlePost(c *fiber.Ctx) error {
	session, err := getMcpSession(c) // some user logic to get the current session
	if err != nil {
		return err
	}
	
	response, status, err := httpServer.Handle(
		session, // the session type might be a interface or struct defined by mcp-go
		c.Body(),
	)
	if err != nil {
		return err
	}
	
	return c.Status(status).Send(response)
}

Alternatives/Workarounds Considered

Spawning a internal server just for go-mcp and proxying all mcp route traffic to it.

But that's a lot of resources wasted on nothing.

mjarkk avatar Oct 05 '25 11:10 mjarkk

can you try this?

package main

import (
	"log"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/adaptor"
	"github.com/mark3labs/mcp-go/server"
)

func main() {
	s := server.NewMCPServer("Custom StreamableHTTP Server", "1.0.0")

	fiberApp := fiber.New()

	fiberApp.Group("/mcp", adaptor.HTTPHandler(server.NewStreamableHTTPServer(s)))

	fiberApp.Get("/api/status", func(c *fiber.Ctx) error {
		return c.SendString("OK")
	})

	if err := fiberApp.Listen(":8099"); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}

vendinim avatar Oct 24 '25 03:10 vendinim

@vendin007 That runs, but how exactly do you test this without running a ton of things? Going to /mcp on the browser or using curl timeout.

gaby avatar Nov 11 '25 14:11 gaby

can you try this?

package main

import ( "log"

"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/adaptor" "github.com/mark3labs/mcp-go/server" )

func main() { s := server.NewMCPServer("Custom StreamableHTTP Server", "1.0.0")

fiberApp := fiber.New()

fiberApp.Group("/mcp", adaptor.HTTPHandler(server.NewStreamableHTTPServer(s)))

fiberApp.Get("/api/status", func(c *fiber.Ctx) error { return c.SendString("OK") })

if err := fiberApp.Listen(":8099"); err != nil { log.Fatalf("Failed to start server: %v", err) } }

this method resolved my problem! thanks

xiaoz194 avatar Dec 03 '25 02:12 xiaoz194