Files
gronod 7bcf5322e1 feat: emby-mcp 1.0.16 player owner filter and HA links
Expose session/last-used user and device IP on player rows. Filter
retrieve_player_list by users, merge GET /Devices when include_offline
is set, and resolve spoken names to HA media_player entities via
player_links (device_id or IP). PlayNow still requires a live session.
2026-09-25 19:58:58 +00:00

56 lines
1.7 KiB
Go

package mcphttp
import (
"net/http"
"runtime"
"git.i3omb.com/gronod/emby-mcp/internal/config"
"git.i3omb.com/gronod/emby-mcp/internal/server"
"git.i3omb.com/gronod/emby-mcp/internal/state"
"github.com/modelcontextprotocol/go-sdk/auth"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// Endpoint is the HTTP path the MCP streamable transport is served on.
const Endpoint = "/mcp"
// NewHandler builds the HTTP handler for MCP over streamable HTTP. Every
// request must carry Emby credentials: "Authorization: Basic user:pass" or
// "Authorization: Bearer <emby-token>" (optionally with X-Emby-User-Id or
// X-Emby-Username to disambiguate multi-user tokens).
func NewHandler(cfg *config.Config, hostname string) http.Handler {
a := newAuthenticator(cfg, server.Name+" for AI", server.Version, hostname, runtime.GOOS)
getServer := func(req *http.Request) *mcp.Server {
client, userID := authenticatedClient(req.Context())
if client == nil {
return nil
}
// Per-session state: library selection and search chunking are
// isolated between concurrent HTTP clients.
st := state.New(client, userID, cfg.MaxChunkSize)
st.PlayerUsers = cfg.PlayerUsers
st.PlayerLinks = cfg.PlayerLinks
return server.New(st)
}
mcpHandler := mcp.NewStreamableHTTPHandler(getServer, &mcp.StreamableHTTPOptions{
SessionTimeout: cfg.SessionTimeout,
})
chain := a.translateBasic(
auth.RequireBearerToken(a.verify, &auth.RequireBearerTokenOptions{
AllowMissingExpiration: true,
})(
a.stash(mcpHandler),
),
)
mux := http.NewServeMux()
mux.Handle(Endpoint, bodyLogger("mcp", chain))
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok\n"))
})
return mux
}