Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions pkg/github/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func NewMCPServer(ctx context.Context, cfg *MCPServerConfig, deps ToolDependenci
}
}

ghServer := NewServer(cfg.Version, serverOpts)
ghServer := NewServer(cfg.Version, cfg.Translator("SERVER_NAME", "github-mcp-server"), cfg.Translator("SERVER_TITLE", "GitHub MCP Server"), serverOpts)

// Add middlewares. Order matters - for example, the error context middleware should be applied last so that it runs FIRST (closest to the handler) to ensure all errors are captured,
// and any middleware that needs to read or modify the context should be before it.
Expand Down Expand Up @@ -177,15 +177,22 @@ func addGitHubAPIErrorToContext(next mcp.MethodHandler) mcp.MethodHandler {
}

// NewServer creates a new GitHub MCP server with the specified GH client and logger.
func NewServer(version string, opts *mcp.ServerOptions) *mcp.Server {
func NewServer(version, name, title string, opts *mcp.ServerOptions) *mcp.Server {
if opts == nil {
opts = &mcp.ServerOptions{}
}

if name == "" {
name = "github-mcp-server"
}
if title == "" {
title = "GitHub MCP Server"
}

// Create a new MCP server
s := mcp.NewServer(&mcp.Implementation{
Name: "github-mcp-server",
Title: "GitHub MCP Server",
Name: name,
Title: title,
Version: version,
Icons: octicons.Icons("mark-github"),
}, opts)
Expand Down
86 changes: 86 additions & 0 deletions pkg/github/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/github/github-mcp-server/pkg/raw"
"github.com/github/github-mcp-server/pkg/translations"
gogithub "github.com/google/go-github/v82/github"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/shurcooL/githubv4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -150,6 +151,91 @@ func TestNewMCPServer_CreatesSuccessfully(t *testing.T) {
// is already tested in pkg/github/*_test.go.
}

// TestNewServer_NameAndTitleViaTranslation verifies that server name and title
// can be overridden via the translation helper (GITHUB_MCP_SERVER_NAME /
// GITHUB_MCP_SERVER_TITLE env vars or github-mcp-server-config.json) and
// fall back to sensible defaults when not overridden.
func TestNewServer_NameAndTitleViaTranslation(t *testing.T) {
t.Parallel()

tests := []struct {
name string
translator translations.TranslationHelperFunc
expectedName string
expectedTitle string
}{
{
name: "defaults when using NullTranslationHelper",
translator: translations.NullTranslationHelper,
expectedName: "github-mcp-server",
expectedTitle: "GitHub MCP Server",
},
{
name: "custom name and title via translator",
translator: func(key, defaultValue string) string {
switch key {
case "SERVER_NAME":
return "my-github-server"
case "SERVER_TITLE":
return "My GitHub MCP Server"
default:
return defaultValue
}
},
expectedName: "my-github-server",
expectedTitle: "My GitHub MCP Server",
},
{
name: "custom name only via translator",
translator: func(key, defaultValue string) string {
if key == "SERVER_NAME" {
return "ghes-server"
}
return defaultValue
},
expectedName: "ghes-server",
expectedTitle: "GitHub MCP Server",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

srv := NewServer("v1.0.0", tt.translator("SERVER_NAME", "github-mcp-server"), tt.translator("SERVER_TITLE", "GitHub MCP Server"), nil)
require.NotNil(t, srv)

// Connect a client to retrieve the initialize result and verify ServerInfo.
st, ct := mcp.NewInMemoryTransports()
client := mcp.NewClient(&mcp.Implementation{Name: "test-client"}, nil)

type clientResult struct {
result *mcp.InitializeResult
err error
}
clientResultCh := make(chan clientResult, 1)
go func() {
cs, err := client.Connect(context.Background(), ct, nil)
if err != nil {
clientResultCh <- clientResult{err: err}
return
}
clientResultCh <- clientResult{result: cs.InitializeResult()}
}()

_, err := srv.Connect(context.Background(), st, nil)
require.NoError(t, err)

got := <-clientResultCh
require.NoError(t, got.err)
require.NotNil(t, got.result)
require.NotNil(t, got.result.ServerInfo)
assert.Equal(t, tt.expectedName, got.result.ServerInfo.Name)
assert.Equal(t, tt.expectedTitle, got.result.ServerInfo.Title)
})
}
}

// TestResolveEnabledToolsets verifies the toolset resolution logic.
func TestResolveEnabledToolsets(t *testing.T) {
t.Parallel()
Expand Down