| 80 | type MCPServerOption func(*mcp.ServerOptions) |
| 81 | |
| 82 | func NewMCPServer(ctx context.Context, cfg *MCPServerConfig, deps ToolDependencies, inv *inventory.Inventory, middleware ...mcp.Middleware) (*mcp.Server, error) { |
| 83 | // Create the MCP server |
| 84 | serverOpts := &mcp.ServerOptions{ |
| 85 | Instructions: inv.Instructions(), |
| 86 | Logger: cfg.Logger, |
| 87 | CompletionHandler: CompletionsHandler(deps.GetClient), |
| 88 | } |
| 89 | |
| 90 | // Apply any additional server options |
| 91 | for _, o := range cfg.ServerOptions { |
| 92 | o(serverOpts) |
| 93 | } |
| 94 | |
| 95 | ghServer := NewServer(cfg.Version, cfg.Translator("SERVER_NAME", "github-mcp-server"), cfg.Translator("SERVER_TITLE", "GitHub MCP Server"), serverOpts) |
| 96 | |
| 97 | // 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, |
| 98 | // and any middleware that needs to read or modify the context should be before it. |
| 99 | ghServer.AddReceivingMiddleware(middleware...) |
| 100 | ghServer.AddReceivingMiddleware(InjectDepsMiddleware(deps)) |
| 101 | ghServer.AddReceivingMiddleware(addGitHubAPIErrorToContext) |
| 102 | |
| 103 | if unrecognized := inv.UnrecognizedToolsets(); len(unrecognized) > 0 { |
| 104 | cfg.Logger.Warn("Warning: unrecognized toolsets ignored", "toolsets", strings.Join(unrecognized, ", ")) |
| 105 | } |
| 106 | |
| 107 | // Register GitHub tools/resources/prompts from the inventory. |
| 108 | inv.RegisterAll(ctx, ghServer, deps) |
| 109 | |
| 110 | // Register MCP App UI resources whenever the embedded UI assets are |
| 111 | // available. The resources are static HTML and are only referenced by |
| 112 | // tools when the remote_mcp_ui_apps feature flag is enabled for the |
| 113 | // request (the inventory strips the _meta.ui block otherwise via |
| 114 | // stripMCPAppsMetadata), so registering them unconditionally is safe. |
| 115 | // Registering here — rather than in the stdio bootstrap — ensures the |
| 116 | // remote/HTTP server also serves them, fixing the "-32002 Resource not |
| 117 | // found" error clients hit after the tool returns a ui:// URI. |
| 118 | if UIAssetsAvailable() { |
| 119 | RegisterUIResources(ghServer, cfg.ReadOnly) |
| 120 | } |
| 121 | |
| 122 | return ghServer, nil |
| 123 | } |
| 124 | |
| 125 | // ResolvedEnabledToolsets determines which toolsets should be enabled based on config. |
| 126 | // Returns nil for "use defaults", empty slice for "none", or explicit list. |