Skip to content

feature: Generic server handler and/or fasthttp support #611

@mjarkk

Description

@mjarkk

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions