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.
60 lines
1.8 KiB
Go
60 lines
1.8 KiB
Go
// Package server wires the Emby tools into an MCP server using the official
|
|
// modelcontextprotocol go-sdk.
|
|
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
|
|
"git.i3omb.com/gronod/emby-mcp/internal/state"
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
)
|
|
|
|
const (
|
|
Name = "HA Emby MCP"
|
|
Version = "1.0.16"
|
|
Purpose = `These MCP tools allow you to control an Emby media server. Using them you can retrieve
|
|
a list of libraries, genres, playlists, audio & video items, and player sessions.
|
|
You can browse series, seasons and episodes, find the next episode to watch,
|
|
inspect a player's now-playing audio/subtitle tracks, add items to playlists,
|
|
and play, pause, seek and stop items on a player session.`
|
|
)
|
|
|
|
// New builds the MCP server and registers all tools against the shared state.
|
|
func New(st *state.State) *mcp.Server {
|
|
s := mcp.NewServer(
|
|
&mcp.Implementation{Name: Name, Version: Version},
|
|
&mcp.ServerOptions{Instructions: Purpose},
|
|
)
|
|
registerUserTools(s, st)
|
|
registerLibraryTools(s, st)
|
|
registerItemTools(s, st)
|
|
registerBrowseTools(s, st)
|
|
registerPlaylistTools(s, st)
|
|
registerPlayerTools(s, st)
|
|
return s
|
|
}
|
|
|
|
// errf logs to stderr and returns the message in the Python "ERROR: ..." style.
|
|
func errf(format string, args ...any) string {
|
|
msg := fmt.Sprintf(format, args...)
|
|
log.Printf("%s", msg)
|
|
return msg
|
|
}
|
|
|
|
// textResult wraps a string as MCP text content (the Python tools all return
|
|
// bare strings — JSON documents or error messages).
|
|
func textResult(s string) *mcp.CallToolResult {
|
|
return &mcp.CallToolResult{Content: []mcp.Content{&mcp.TextContent{Text: s}}}
|
|
}
|
|
|
|
// jsonResult marshals v to JSON text; on failure returns an error string.
|
|
func jsonResult(v any) *mcp.CallToolResult {
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
return textResult(errf("ERROR: failed to encode result as JSON: %v", err))
|
|
}
|
|
return textResult(string(b))
|
|
}
|