plex-mcp 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +11 -0
- package/README.md +81 -9
- package/index.js +249 -90
- package/package.json +6 -5
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "daily"
|
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ A Model Context Protocol (MCP) server for searching Plex media libraries using C
|
|
|
8
8
|
- Filter by content type
|
|
9
9
|
- Configurable result limits
|
|
10
10
|
- Rich formatted results with metadata
|
|
11
|
+
- **Direct Plex authentication with OAuth flow**
|
|
12
|
+
- Support for both static tokens and interactive authentication
|
|
11
13
|
|
|
12
14
|
## Setup
|
|
13
15
|
|
|
@@ -16,19 +18,22 @@ A Model Context Protocol (MCP) server for searching Plex media libraries using C
|
|
|
16
18
|
npm install
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
2. Configure your Plex connection:
|
|
20
|
-
|
|
21
|
+
2. Configure your Plex connection (two options):
|
|
22
|
+
|
|
23
|
+
**Option A: Interactive Authentication (Recommended)**
|
|
24
|
+
- Set your Plex server URL:
|
|
25
|
+
```
|
|
26
|
+
PLEX_URL=http://your-plex-server:32400
|
|
27
|
+
```
|
|
28
|
+
- Use the `authenticate_plex` tool for OAuth login (see Authentication section below)
|
|
29
|
+
|
|
30
|
+
**Option B: Static Token**
|
|
21
31
|
- Set your Plex server URL and token:
|
|
22
32
|
```
|
|
23
33
|
PLEX_URL=http://your-plex-server:32400
|
|
24
34
|
PLEX_TOKEN=your_plex_token
|
|
25
35
|
```
|
|
26
|
-
|
|
27
|
-
3. Get your Plex token:
|
|
28
|
-
- Log into your Plex account
|
|
29
|
-
- Go to Settings > Account > Privacy
|
|
30
|
-
- Click "Show" next to "Plex Pass Subscription"
|
|
31
|
-
- Your token will be displayed
|
|
36
|
+
- Get your Plex token by visiting [Plex Token](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/)
|
|
32
37
|
|
|
33
38
|
## Claude Desktop Configuration
|
|
34
39
|
|
|
@@ -113,9 +118,76 @@ Run the MCP server standalone:
|
|
|
113
118
|
node index.js
|
|
114
119
|
```
|
|
115
120
|
|
|
121
|
+
## Authentication
|
|
122
|
+
|
|
123
|
+
The Plex MCP server supports two authentication methods:
|
|
124
|
+
|
|
125
|
+
### 1. Interactive OAuth Authentication (Recommended)
|
|
126
|
+
|
|
127
|
+
Use the built-in OAuth flow for secure, interactive authentication:
|
|
128
|
+
|
|
129
|
+
1. **Start Authentication:**
|
|
130
|
+
```
|
|
131
|
+
Use the authenticate_plex tool
|
|
132
|
+
```
|
|
133
|
+
This will provide you with a Plex login URL and pin ID.
|
|
134
|
+
|
|
135
|
+
2. **Complete Login:**
|
|
136
|
+
- Open the provided URL in your browser
|
|
137
|
+
- Sign into your Plex account
|
|
138
|
+
- Grant access to the MCP application
|
|
139
|
+
|
|
140
|
+
3. **Check Authentication Status:**
|
|
141
|
+
```
|
|
142
|
+
Use the check_auth_status tool
|
|
143
|
+
```
|
|
144
|
+
This confirms authentication completion and stores your token.
|
|
145
|
+
|
|
146
|
+
4. **Clear Authentication (Optional):**
|
|
147
|
+
```
|
|
148
|
+
Use the clear_auth tool
|
|
149
|
+
```
|
|
150
|
+
This removes stored credentials if needed.
|
|
151
|
+
|
|
152
|
+
### 2. Static Token Authentication
|
|
153
|
+
|
|
154
|
+
For automated setups or if you prefer manual token management:
|
|
155
|
+
|
|
156
|
+
1. Obtain your Plex token from [Plex Support](https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/)
|
|
157
|
+
2. Set the `PLEX_TOKEN` environment variable
|
|
158
|
+
3. All tools will automatically use this token
|
|
159
|
+
|
|
160
|
+
**Note:** The OAuth method takes precedence - if both are available, static tokens are used as fallback.
|
|
161
|
+
|
|
116
162
|
## MCP Tools
|
|
117
163
|
|
|
118
|
-
###
|
|
164
|
+
### Authentication Tools
|
|
165
|
+
|
|
166
|
+
#### authenticate_plex
|
|
167
|
+
Start the Plex OAuth authentication flow.
|
|
168
|
+
|
|
169
|
+
**Parameters:** None
|
|
170
|
+
|
|
171
|
+
**Returns:** Login URL and pin ID for browser authentication.
|
|
172
|
+
|
|
173
|
+
#### check_auth_status
|
|
174
|
+
Check if OAuth authentication is complete and retrieve the token.
|
|
175
|
+
|
|
176
|
+
**Parameters:**
|
|
177
|
+
- `pin_id` (string, optional): Specific pin ID to check
|
|
178
|
+
|
|
179
|
+
**Returns:** Authentication status and success confirmation.
|
|
180
|
+
|
|
181
|
+
#### clear_auth
|
|
182
|
+
Clear stored authentication credentials.
|
|
183
|
+
|
|
184
|
+
**Parameters:** None
|
|
185
|
+
|
|
186
|
+
**Returns:** Confirmation of credential removal.
|
|
187
|
+
|
|
188
|
+
### Content Tools
|
|
189
|
+
|
|
190
|
+
#### search_plex
|
|
119
191
|
|
|
120
192
|
Search for content in your Plex libraries.
|
|
121
193
|
|
package/index.js
CHANGED
|
@@ -7,6 +7,84 @@ const {
|
|
|
7
7
|
ListToolsRequestSchema,
|
|
8
8
|
} = require("@modelcontextprotocol/sdk/types.js");
|
|
9
9
|
const axios = require('axios');
|
|
10
|
+
const { PlexOauth } = require('plex-oauth');
|
|
11
|
+
|
|
12
|
+
class PlexAuthManager {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.authToken = null;
|
|
15
|
+
this.plexOauth = null;
|
|
16
|
+
this.currentPinId = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async getAuthToken() {
|
|
20
|
+
// Try static token first
|
|
21
|
+
const staticToken = process.env.PLEX_TOKEN;
|
|
22
|
+
if (staticToken) {
|
|
23
|
+
return staticToken;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Return stored OAuth token if available
|
|
27
|
+
if (this.authToken) {
|
|
28
|
+
return this.authToken;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
throw new Error('No authentication token available. Please authenticate first using the authenticate_plex tool or set PLEX_TOKEN environment variable.');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
initializeOAuth() {
|
|
35
|
+
if (this.plexOauth) {
|
|
36
|
+
return this.plexOauth;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const clientInfo = {
|
|
40
|
+
clientIdentifier: process.env.PLEX_CLIENT_ID || 'plex-mcp-client',
|
|
41
|
+
product: process.env.PLEX_PRODUCT || 'Plex MCP Server',
|
|
42
|
+
device: process.env.PLEX_DEVICE || 'MCP Server',
|
|
43
|
+
version: process.env.PLEX_VERSION || '1.0.0',
|
|
44
|
+
forwardUrl: process.env.PLEX_REDIRECT_URL || 'https://app.plex.tv/auth#!',
|
|
45
|
+
platform: process.env.PLEX_PLATFORM || 'Web'
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
this.plexOauth = new PlexOauth(clientInfo);
|
|
49
|
+
return this.plexOauth;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async requestAuthUrl() {
|
|
53
|
+
const oauth = this.initializeOAuth();
|
|
54
|
+
try {
|
|
55
|
+
const [hostedUILink, pinId] = await oauth.requestHostedLoginURL();
|
|
56
|
+
this.currentPinId = pinId;
|
|
57
|
+
return { loginUrl: hostedUILink, pinId };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw new Error(`Failed to request authentication URL: ${error.message}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async checkAuthToken(pinId = null) {
|
|
64
|
+
const oauth = this.initializeOAuth();
|
|
65
|
+
const pin = pinId || this.currentPinId;
|
|
66
|
+
|
|
67
|
+
if (!pin) {
|
|
68
|
+
throw new Error('No pin ID available. Please request authentication first.');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const authToken = await oauth.checkForAuthToken(pin);
|
|
73
|
+
if (authToken) {
|
|
74
|
+
this.authToken = authToken;
|
|
75
|
+
return authToken;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
throw new Error(`Failed to check authentication token: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
clearAuth() {
|
|
84
|
+
this.authToken = null;
|
|
85
|
+
this.currentPinId = null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
10
88
|
|
|
11
89
|
class PlexMCPServer {
|
|
12
90
|
constructor() {
|
|
@@ -22,6 +100,7 @@ class PlexMCPServer {
|
|
|
22
100
|
}
|
|
23
101
|
);
|
|
24
102
|
|
|
103
|
+
this.authManager = new PlexAuthManager();
|
|
25
104
|
this.setupToolHandlers();
|
|
26
105
|
}
|
|
27
106
|
|
|
@@ -623,6 +702,38 @@ class PlexMCPServer {
|
|
|
623
702
|
required: [],
|
|
624
703
|
},
|
|
625
704
|
},
|
|
705
|
+
{
|
|
706
|
+
name: "authenticate_plex",
|
|
707
|
+
description: "Initiate Plex OAuth authentication flow to get user login URL",
|
|
708
|
+
inputSchema: {
|
|
709
|
+
type: "object",
|
|
710
|
+
properties: {},
|
|
711
|
+
required: [],
|
|
712
|
+
},
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
name: "check_auth_status",
|
|
716
|
+
description: "Check if Plex authentication is complete and retrieve the auth token",
|
|
717
|
+
inputSchema: {
|
|
718
|
+
type: "object",
|
|
719
|
+
properties: {
|
|
720
|
+
pin_id: {
|
|
721
|
+
type: "string",
|
|
722
|
+
description: "Optional pin ID to check. If not provided, uses the last requested pin.",
|
|
723
|
+
},
|
|
724
|
+
},
|
|
725
|
+
required: [],
|
|
726
|
+
},
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
name: "clear_auth",
|
|
730
|
+
description: "Clear stored authentication credentials",
|
|
731
|
+
inputSchema: {
|
|
732
|
+
type: "object",
|
|
733
|
+
properties: {},
|
|
734
|
+
required: [],
|
|
735
|
+
},
|
|
736
|
+
},
|
|
626
737
|
],
|
|
627
738
|
};
|
|
628
739
|
});
|
|
@@ -666,12 +777,132 @@ class PlexMCPServer {
|
|
|
666
777
|
return await this.handleGetLibraryStats(request.params.arguments);
|
|
667
778
|
case "get_listening_stats":
|
|
668
779
|
return await this.handleGetListeningStats(request.params.arguments);
|
|
780
|
+
case "authenticate_plex":
|
|
781
|
+
return await this.handleAuthenticatePlex(request.params.arguments);
|
|
782
|
+
case "check_auth_status":
|
|
783
|
+
return await this.handleCheckAuthStatus(request.params.arguments);
|
|
784
|
+
case "clear_auth":
|
|
785
|
+
return await this.handleClearAuth(request.params.arguments);
|
|
669
786
|
default:
|
|
670
787
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
671
788
|
}
|
|
672
789
|
});
|
|
673
790
|
}
|
|
674
791
|
|
|
792
|
+
async handleAuthenticatePlex(args) {
|
|
793
|
+
try {
|
|
794
|
+
const { loginUrl, pinId } = await this.authManager.requestAuthUrl();
|
|
795
|
+
|
|
796
|
+
return {
|
|
797
|
+
content: [
|
|
798
|
+
{
|
|
799
|
+
type: "text",
|
|
800
|
+
text: `Plex Authentication Started
|
|
801
|
+
|
|
802
|
+
**Next Steps:**
|
|
803
|
+
1. Open this URL in your browser: ${loginUrl}
|
|
804
|
+
2. Sign into your Plex account
|
|
805
|
+
3. After signing in, run the check_auth_status tool to complete authentication
|
|
806
|
+
|
|
807
|
+
**Pin ID:** ${pinId}
|
|
808
|
+
|
|
809
|
+
Note: Keep this pin ID if you want to check auth status manually later.`
|
|
810
|
+
}
|
|
811
|
+
]
|
|
812
|
+
};
|
|
813
|
+
} catch (error) {
|
|
814
|
+
return {
|
|
815
|
+
content: [
|
|
816
|
+
{
|
|
817
|
+
type: "text",
|
|
818
|
+
text: `❌ Authentication Error: ${error.message}`
|
|
819
|
+
}
|
|
820
|
+
],
|
|
821
|
+
isError: true
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
async handleCheckAuthStatus(args) {
|
|
827
|
+
const { pin_id } = args;
|
|
828
|
+
|
|
829
|
+
try {
|
|
830
|
+
const authToken = await this.authManager.checkAuthToken(pin_id);
|
|
831
|
+
|
|
832
|
+
if (authToken) {
|
|
833
|
+
return {
|
|
834
|
+
content: [
|
|
835
|
+
{
|
|
836
|
+
type: "text",
|
|
837
|
+
text: `✅ Plex Authentication Successful!
|
|
838
|
+
|
|
839
|
+
Your authentication token has been stored and will be used for all Plex API requests. You can now use all Plex tools without needing the PLEX_TOKEN environment variable.
|
|
840
|
+
|
|
841
|
+
**Note:** This token is stored only for this session. For persistent authentication, consider setting the PLEX_TOKEN environment variable.`
|
|
842
|
+
}
|
|
843
|
+
]
|
|
844
|
+
};
|
|
845
|
+
} else {
|
|
846
|
+
return {
|
|
847
|
+
content: [
|
|
848
|
+
{
|
|
849
|
+
type: "text",
|
|
850
|
+
text: `⏳ Authentication Pending
|
|
851
|
+
|
|
852
|
+
The user has not yet completed the authentication process. Please:
|
|
853
|
+
|
|
854
|
+
1. Make sure you've visited the login URL from the authenticate_plex tool
|
|
855
|
+
2. Sign into your Plex account in the browser
|
|
856
|
+
3. Try checking the auth status again in a few moments
|
|
857
|
+
|
|
858
|
+
You can run check_auth_status again to check if authentication is complete.`
|
|
859
|
+
}
|
|
860
|
+
]
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
} catch (error) {
|
|
864
|
+
return {
|
|
865
|
+
content: [
|
|
866
|
+
{
|
|
867
|
+
type: "text",
|
|
868
|
+
text: `❌ Auth Status Check Error: ${error.message}`
|
|
869
|
+
}
|
|
870
|
+
],
|
|
871
|
+
isError: true
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
async handleClearAuth(args) {
|
|
877
|
+
try {
|
|
878
|
+
this.authManager.clearAuth();
|
|
879
|
+
|
|
880
|
+
return {
|
|
881
|
+
content: [
|
|
882
|
+
{
|
|
883
|
+
type: "text",
|
|
884
|
+
text: `🔄 Authentication Cleared
|
|
885
|
+
|
|
886
|
+
All stored authentication credentials have been cleared. To use Plex tools again, you'll need to either:
|
|
887
|
+
|
|
888
|
+
1. Set the PLEX_TOKEN environment variable, or
|
|
889
|
+
2. Run the authenticate_plex tool to sign in again`
|
|
890
|
+
}
|
|
891
|
+
]
|
|
892
|
+
};
|
|
893
|
+
} catch (error) {
|
|
894
|
+
return {
|
|
895
|
+
content: [
|
|
896
|
+
{
|
|
897
|
+
type: "text",
|
|
898
|
+
text: `❌ Clear Auth Error: ${error.message}`
|
|
899
|
+
}
|
|
900
|
+
],
|
|
901
|
+
isError: true
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
675
906
|
async handlePlexSearch(args) {
|
|
676
907
|
const {
|
|
677
908
|
query,
|
|
@@ -706,11 +937,7 @@ class PlexMCPServer {
|
|
|
706
937
|
|
|
707
938
|
try {
|
|
708
939
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
709
|
-
const plexToken =
|
|
710
|
-
|
|
711
|
-
if (!plexToken) {
|
|
712
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
713
|
-
}
|
|
940
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
714
941
|
|
|
715
942
|
const searchUrl = `${plexUrl}/search`;
|
|
716
943
|
const params = {
|
|
@@ -891,11 +1118,7 @@ class PlexMCPServer {
|
|
|
891
1118
|
async handleBrowseLibraries(args) {
|
|
892
1119
|
try {
|
|
893
1120
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
894
|
-
const plexToken =
|
|
895
|
-
|
|
896
|
-
if (!plexToken) {
|
|
897
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
898
|
-
}
|
|
1121
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
899
1122
|
|
|
900
1123
|
const librariesUrl = `${plexUrl}/library/sections`;
|
|
901
1124
|
const params = {
|
|
@@ -1007,11 +1230,7 @@ class PlexMCPServer {
|
|
|
1007
1230
|
|
|
1008
1231
|
try {
|
|
1009
1232
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1010
|
-
const plexToken =
|
|
1011
|
-
|
|
1012
|
-
if (!plexToken) {
|
|
1013
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1014
|
-
}
|
|
1233
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1015
1234
|
|
|
1016
1235
|
const libraryUrl = `${plexUrl}/library/sections/${library_id}/all`;
|
|
1017
1236
|
const params = {
|
|
@@ -1133,11 +1352,7 @@ class PlexMCPServer {
|
|
|
1133
1352
|
|
|
1134
1353
|
try {
|
|
1135
1354
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1136
|
-
const plexToken =
|
|
1137
|
-
|
|
1138
|
-
if (!plexToken) {
|
|
1139
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1140
|
-
}
|
|
1355
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1141
1356
|
|
|
1142
1357
|
let recentUrl;
|
|
1143
1358
|
if (library_id) {
|
|
@@ -1233,11 +1448,7 @@ class PlexMCPServer {
|
|
|
1233
1448
|
|
|
1234
1449
|
try {
|
|
1235
1450
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1236
|
-
const plexToken =
|
|
1237
|
-
|
|
1238
|
-
if (!plexToken) {
|
|
1239
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1240
|
-
}
|
|
1451
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1241
1452
|
|
|
1242
1453
|
const historyUrl = `${plexUrl}/status/sessions/history/all`;
|
|
1243
1454
|
const params = {
|
|
@@ -1357,11 +1568,7 @@ class PlexMCPServer {
|
|
|
1357
1568
|
|
|
1358
1569
|
try {
|
|
1359
1570
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1360
|
-
const plexToken =
|
|
1361
|
-
|
|
1362
|
-
if (!plexToken) {
|
|
1363
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1364
|
-
}
|
|
1571
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1365
1572
|
|
|
1366
1573
|
const onDeckUrl = `${plexUrl}/library/onDeck`;
|
|
1367
1574
|
const params = {
|
|
@@ -1460,11 +1667,7 @@ class PlexMCPServer {
|
|
|
1460
1667
|
|
|
1461
1668
|
try {
|
|
1462
1669
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1463
|
-
const plexToken =
|
|
1464
|
-
|
|
1465
|
-
if (!plexToken) {
|
|
1466
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1467
|
-
}
|
|
1670
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1468
1671
|
|
|
1469
1672
|
const playlistsUrl = `${plexUrl}/playlists`;
|
|
1470
1673
|
const params = {
|
|
@@ -1512,11 +1715,7 @@ class PlexMCPServer {
|
|
|
1512
1715
|
|
|
1513
1716
|
try {
|
|
1514
1717
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1515
|
-
const plexToken =
|
|
1516
|
-
|
|
1517
|
-
if (!plexToken) {
|
|
1518
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1519
|
-
}
|
|
1718
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1520
1719
|
|
|
1521
1720
|
// First get playlist info
|
|
1522
1721
|
const playlistUrl = `${plexUrl}/playlists/${playlist_id}`;
|
|
@@ -1730,11 +1929,7 @@ class PlexMCPServer {
|
|
|
1730
1929
|
|
|
1731
1930
|
try {
|
|
1732
1931
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1733
|
-
const plexToken =
|
|
1734
|
-
|
|
1735
|
-
if (!plexToken) {
|
|
1736
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1737
|
-
}
|
|
1932
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1738
1933
|
|
|
1739
1934
|
// First get server info to get machine identifier
|
|
1740
1935
|
const serverResponse = await axios.get(`${plexUrl}/`, {
|
|
@@ -1839,11 +2034,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
1839
2034
|
|
|
1840
2035
|
try {
|
|
1841
2036
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
1842
|
-
const plexToken =
|
|
1843
|
-
|
|
1844
|
-
if (!plexToken) {
|
|
1845
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
1846
|
-
}
|
|
2037
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
1847
2038
|
|
|
1848
2039
|
// Get playlist info before adding items
|
|
1849
2040
|
const playlistInfoUrl = `${plexUrl}/playlists/${playlist_id}`;
|
|
@@ -2000,11 +2191,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
2000
2191
|
|
|
2001
2192
|
try {
|
|
2002
2193
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
2003
|
-
const plexToken =
|
|
2004
|
-
|
|
2005
|
-
if (!plexToken) {
|
|
2006
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
2007
|
-
}
|
|
2194
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
2008
2195
|
|
|
2009
2196
|
// Get playlist info before removing items
|
|
2010
2197
|
const playlistInfoUrl = `${plexUrl}/playlists/${playlist_id}`;
|
|
@@ -2184,11 +2371,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
2184
2371
|
|
|
2185
2372
|
try {
|
|
2186
2373
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
2187
|
-
const plexToken =
|
|
2188
|
-
|
|
2189
|
-
if (!plexToken) {
|
|
2190
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
2191
|
-
}
|
|
2374
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
2192
2375
|
|
|
2193
2376
|
const deleteUrl = `${plexUrl}/playlists/${playlist_id}`;
|
|
2194
2377
|
const params = {
|
|
@@ -2228,11 +2411,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
2228
2411
|
|
|
2229
2412
|
try {
|
|
2230
2413
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
2231
|
-
const plexToken =
|
|
2232
|
-
|
|
2233
|
-
if (!plexToken) {
|
|
2234
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
2235
|
-
}
|
|
2414
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
2236
2415
|
|
|
2237
2416
|
const statusResults = [];
|
|
2238
2417
|
|
|
@@ -2675,11 +2854,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
2675
2854
|
|
|
2676
2855
|
try {
|
|
2677
2856
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
2678
|
-
const plexToken =
|
|
2679
|
-
|
|
2680
|
-
if (!plexToken) {
|
|
2681
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
2682
|
-
}
|
|
2857
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
2683
2858
|
|
|
2684
2859
|
let collectionsUrl;
|
|
2685
2860
|
if (library_id) {
|
|
@@ -2729,11 +2904,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
2729
2904
|
|
|
2730
2905
|
try {
|
|
2731
2906
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
2732
|
-
const plexToken =
|
|
2733
|
-
|
|
2734
|
-
if (!plexToken) {
|
|
2735
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
2736
|
-
}
|
|
2907
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
2737
2908
|
|
|
2738
2909
|
const collectionUrl = `${plexUrl}/library/collections/${collection_id}/children`;
|
|
2739
2910
|
const params = {
|
|
@@ -2832,11 +3003,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
2832
3003
|
|
|
2833
3004
|
try {
|
|
2834
3005
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
2835
|
-
const plexToken =
|
|
2836
|
-
|
|
2837
|
-
if (!plexToken) {
|
|
2838
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
2839
|
-
}
|
|
3006
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
2840
3007
|
|
|
2841
3008
|
const mediaUrl = `${plexUrl}/library/metadata/${item_key}`;
|
|
2842
3009
|
const params = {
|
|
@@ -3125,11 +3292,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
3125
3292
|
|
|
3126
3293
|
try {
|
|
3127
3294
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
3128
|
-
const plexToken =
|
|
3129
|
-
|
|
3130
|
-
if (!plexToken) {
|
|
3131
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
3132
|
-
}
|
|
3295
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
3133
3296
|
|
|
3134
3297
|
// Get library information first
|
|
3135
3298
|
const librariesResponse = await axios.get(`${plexUrl}/library/sections`, {
|
|
@@ -3480,11 +3643,7 @@ You can try creating the playlist manually in Plex and then use other MCP tools
|
|
|
3480
3643
|
|
|
3481
3644
|
try {
|
|
3482
3645
|
const plexUrl = process.env.PLEX_URL || 'http://localhost:32400';
|
|
3483
|
-
const plexToken =
|
|
3484
|
-
|
|
3485
|
-
if (!plexToken) {
|
|
3486
|
-
throw new Error('PLEX_TOKEN environment variable is required');
|
|
3487
|
-
}
|
|
3646
|
+
const plexToken = await this.authManager.getAuthToken();
|
|
3488
3647
|
|
|
3489
3648
|
// Auto-detect music libraries if not specified
|
|
3490
3649
|
let musicLibraries = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plex-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A Model Context Protocol (MCP) server that enables Claude to query and manage Plex media libraries.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -41,11 +41,12 @@
|
|
|
41
41
|
"type": "commonjs",
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
44
|
-
"axios": "^1.9.0"
|
|
44
|
+
"axios": "^1.9.0",
|
|
45
|
+
"plex-oauth": "^1.2.2"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
|
-
"jest": "^29.
|
|
48
|
-
"
|
|
49
|
-
"
|
|
48
|
+
"@types/jest": "^29.5.14",
|
|
49
|
+
"axios-mock-adapter": "^2.1.0",
|
|
50
|
+
"jest": "^29.7.0"
|
|
50
51
|
}
|
|
51
52
|
}
|