@darrenjaws/spotify-mcp 0.4.0 → 0.6.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.
@@ -1,169 +1,300 @@
1
1
  /**
2
2
  * Playback control tools
3
3
  */
4
+ import { spawnSync } from "child_process";
4
5
  import { getAuthenticatedClient } from "../spotify/client.js";
5
- export async function play(args) {
6
- const client = await getAuthenticatedClient();
7
- const options = {};
8
- if (args.uri) {
9
- // Determine if URI is a context (album, playlist, artist) or a track
10
- if (args.uri.startsWith('spotify:album:') ||
11
- args.uri.startsWith('spotify:playlist:') ||
12
- args.uri.startsWith('spotify:artist:')) {
13
- options.context_uri = args.uri;
14
- }
15
- else {
16
- // Track or other URI - use uris array
17
- options.uris = [args.uri];
18
- }
19
- }
20
- if (args.uris) {
21
- options.uris = args.uris;
22
- }
23
- if (args.device_id) {
24
- options.device_id = args.device_id;
6
+ import { handleToolError } from "../spotify/errors.js";
7
+ async function ensureDevice(client, deviceId) {
8
+ // If caller specified a device_id, trust it
9
+ if (deviceId)
10
+ return null;
11
+ const response = await client.getMyDevices();
12
+ const devices = response.body?.devices ?? [];
13
+ const active = devices.find((d) => d.is_active);
14
+ if (active)
15
+ return null;
16
+ // No active device — return helpful error
17
+ if (devices.length > 0) {
18
+ const list = devices.map((d) => ` - ${d.name} (${d.type})`).join("\n");
19
+ return {
20
+ content: [{
21
+ type: "text",
22
+ text: `No active Spotify device. Available devices:\n${list}\n\nOpen Spotify on one of these devices or use spotify_open to launch it.`,
23
+ }],
24
+ isError: true,
25
+ };
25
26
  }
26
- await client.play(options);
27
- // Generate appropriate response message
28
- let message = "Resumed playback";
29
- if (args.uri) {
30
- if (args.uri.startsWith('spotify:album:')) {
31
- message = `Started playing album: ${args.uri}`;
27
+ return {
28
+ content: [{
29
+ type: "text",
30
+ text: "No Spotify devices found. Please open Spotify on a device and try again, or use spotify_open to launch it.",
31
+ }],
32
+ isError: true,
33
+ };
34
+ }
35
+ export async function play(args) {
36
+ try {
37
+ const client = await getAuthenticatedClient();
38
+ const deviceError = await ensureDevice(client, args.device_id);
39
+ if (deviceError)
40
+ return deviceError;
41
+ const options = {};
42
+ if (args.uri) {
43
+ // Determine if URI is a context (album, playlist, artist) or a track
44
+ if (args.uri.startsWith('spotify:album:') ||
45
+ args.uri.startsWith('spotify:playlist:') ||
46
+ args.uri.startsWith('spotify:artist:')) {
47
+ options.context_uri = args.uri;
48
+ }
49
+ else {
50
+ // Track or other URI - use uris array
51
+ options.uris = [args.uri];
52
+ }
32
53
  }
33
- else if (args.uri.startsWith('spotify:playlist:')) {
34
- message = `Started playing playlist: ${args.uri}`;
54
+ if (args.uris) {
55
+ options.uris = args.uris;
35
56
  }
36
- else if (args.uri.startsWith('spotify:artist:')) {
37
- message = `Started playing artist: ${args.uri}`;
57
+ if (args.device_id) {
58
+ options.device_id = args.device_id;
38
59
  }
39
- else if (args.uri.startsWith('spotify:track:')) {
40
- message = `Started playing track: ${args.uri}`;
60
+ await client.play(options);
61
+ // Generate appropriate response message
62
+ let message = "Resumed playback";
63
+ if (args.uri) {
64
+ if (args.uri.startsWith('spotify:album:')) {
65
+ message = `Started playing album: ${args.uri}`;
66
+ }
67
+ else if (args.uri.startsWith('spotify:playlist:')) {
68
+ message = `Started playing playlist: ${args.uri}`;
69
+ }
70
+ else if (args.uri.startsWith('spotify:artist:')) {
71
+ message = `Started playing artist: ${args.uri}`;
72
+ }
73
+ else if (args.uri.startsWith('spotify:track:')) {
74
+ message = `Started playing track: ${args.uri}`;
75
+ }
76
+ else {
77
+ message = `Started playback: ${args.uri}`;
78
+ }
41
79
  }
42
- else {
43
- message = `Started playback: ${args.uri}`;
80
+ else if (args.uris && args.uris.length > 0) {
81
+ message = `Started playing ${args.uris.length} track${args.uris.length > 1 ? 's' : ''}`;
44
82
  }
83
+ return {
84
+ content: [
85
+ {
86
+ type: "text",
87
+ text: message,
88
+ },
89
+ ],
90
+ };
45
91
  }
46
- else if (args.uris && args.uris.length > 0) {
47
- message = `Started playing ${args.uris.length} track${args.uris.length > 1 ? 's' : ''}`;
92
+ catch (error) {
93
+ return handleToolError(error, "spotify_play");
48
94
  }
49
- return {
50
- content: [
51
- {
52
- type: "text",
53
- text: message,
54
- },
55
- ],
56
- };
57
95
  }
58
96
  export async function pause(args) {
59
- const client = await getAuthenticatedClient();
60
- const options = {};
61
- if (args.device_id) {
62
- options.device_id = args.device_id;
97
+ try {
98
+ const client = await getAuthenticatedClient();
99
+ const deviceError = await ensureDevice(client, args.device_id);
100
+ if (deviceError)
101
+ return deviceError;
102
+ const options = {};
103
+ if (args.device_id) {
104
+ options.device_id = args.device_id;
105
+ }
106
+ await client.pause(options);
107
+ return {
108
+ content: [
109
+ {
110
+ type: "text",
111
+ text: "Playback paused",
112
+ },
113
+ ],
114
+ };
115
+ }
116
+ catch (error) {
117
+ return handleToolError(error, "spotify_pause");
63
118
  }
64
- await client.pause(options);
65
- return {
66
- content: [
67
- {
68
- type: "text",
69
- text: "Playback paused",
70
- },
71
- ],
72
- };
73
119
  }
74
120
  export async function next(args) {
75
- const client = await getAuthenticatedClient();
76
- const options = {};
77
- if (args.device_id) {
78
- options.device_id = args.device_id;
121
+ try {
122
+ const client = await getAuthenticatedClient();
123
+ const deviceError = await ensureDevice(client, args.device_id);
124
+ if (deviceError)
125
+ return deviceError;
126
+ const options = {};
127
+ if (args.device_id) {
128
+ options.device_id = args.device_id;
129
+ }
130
+ await client.skipToNext(options);
131
+ return {
132
+ content: [
133
+ {
134
+ type: "text",
135
+ text: "Skipped to next track",
136
+ },
137
+ ],
138
+ };
139
+ }
140
+ catch (error) {
141
+ return handleToolError(error, "spotify_next");
79
142
  }
80
- await client.skipToNext(options);
81
- return {
82
- content: [
83
- {
84
- type: "text",
85
- text: "Skipped to next track",
86
- },
87
- ],
88
- };
89
143
  }
90
144
  export async function previous(args) {
91
- const client = await getAuthenticatedClient();
92
- const options = {};
93
- if (args.device_id) {
94
- options.device_id = args.device_id;
145
+ try {
146
+ const client = await getAuthenticatedClient();
147
+ const deviceError = await ensureDevice(client, args.device_id);
148
+ if (deviceError)
149
+ return deviceError;
150
+ const options = {};
151
+ if (args.device_id) {
152
+ options.device_id = args.device_id;
153
+ }
154
+ await client.skipToPrevious(options);
155
+ return {
156
+ content: [
157
+ {
158
+ type: "text",
159
+ text: "Skipped to previous track",
160
+ },
161
+ ],
162
+ };
163
+ }
164
+ catch (error) {
165
+ return handleToolError(error, "spotify_previous");
95
166
  }
96
- await client.skipToPrevious(options);
97
- return {
98
- content: [
99
- {
100
- type: "text",
101
- text: "Skipped to previous track",
102
- },
103
- ],
104
- };
105
167
  }
106
168
  export async function setVolume(args) {
107
- const client = await getAuthenticatedClient();
108
- const options = { volume_percent: args.volume_percent };
109
- if (args.device_id) {
110
- options.device_id = args.device_id;
169
+ try {
170
+ const client = await getAuthenticatedClient();
171
+ const deviceError = await ensureDevice(client, args.device_id);
172
+ if (deviceError)
173
+ return deviceError;
174
+ const options = { volume_percent: args.volume_percent };
175
+ if (args.device_id) {
176
+ options.device_id = args.device_id;
177
+ }
178
+ await client.setVolume(options.volume_percent, options);
179
+ return {
180
+ content: [
181
+ {
182
+ type: "text",
183
+ text: `Volume set to ${args.volume_percent}%`,
184
+ },
185
+ ],
186
+ };
187
+ }
188
+ catch (error) {
189
+ return handleToolError(error, "spotify_set_volume");
111
190
  }
112
- await client.setVolume(options.volume_percent, options);
113
- return {
114
- content: [
115
- {
116
- type: "text",
117
- text: `Volume set to ${args.volume_percent}%`,
118
- },
119
- ],
120
- };
121
191
  }
122
192
  export async function getPlaybackState() {
123
- const client = await getAuthenticatedClient();
124
- const state = await client.getMyCurrentPlaybackState();
125
- if (!state.body || !state.body.item) {
193
+ try {
194
+ const client = await getAuthenticatedClient();
195
+ const state = await client.getMyCurrentPlaybackState();
196
+ if (!state.body || !state.body.item) {
197
+ return {
198
+ content: [
199
+ {
200
+ type: "text",
201
+ text: "No active playback",
202
+ },
203
+ ],
204
+ };
205
+ }
206
+ const track = state.body.item;
207
+ const isPlaying = state.body.is_playing;
208
+ const device = state.body.device;
209
+ // Type guard for track
210
+ if (track.type !== "track") {
211
+ return {
212
+ content: [
213
+ {
214
+ type: "text",
215
+ text: `Currently playing: ${track.name} (${track.type})`,
216
+ },
217
+ ],
218
+ };
219
+ }
220
+ const artists = track.artists.map((a) => a.name).join(", ");
221
+ const album = track.album.name;
222
+ const progress = Math.floor((state.body.progress_ms || 0) / 1000);
223
+ const duration = Math.floor(track.duration_ms / 1000);
224
+ const systemVol = getSystemVolume();
225
+ const volumeLine = systemVol !== null
226
+ ? `Volume: ${device.volume_percent}% (Spotify) / ${systemVol}% (System)`
227
+ : `Volume: ${device.volume_percent}%`;
228
+ const text = `${isPlaying ? "▶️ Playing" : "⏸️ Paused"}: ${track.name}
229
+ Artist: ${artists}
230
+ Album: ${album}
231
+ Progress: ${formatTime(progress)} / ${formatTime(duration)}
232
+ Device: ${device.name} (${device.type})
233
+ ${volumeLine}`;
126
234
  return {
127
235
  content: [
128
236
  {
129
237
  type: "text",
130
- text: "No active playback",
238
+ text,
131
239
  },
132
240
  ],
133
241
  };
134
242
  }
135
- const track = state.body.item;
136
- const isPlaying = state.body.is_playing;
137
- const device = state.body.device;
138
- // Type guard for track
139
- if (track.type !== "track") {
243
+ catch (error) {
244
+ return handleToolError(error, "spotify_get_playback_state");
245
+ }
246
+ }
247
+ export async function getDevices() {
248
+ try {
249
+ const client = await getAuthenticatedClient();
250
+ const response = await client.getMyDevices();
251
+ const devices = response.body?.devices ?? [];
252
+ if (devices.length === 0) {
253
+ return {
254
+ content: [
255
+ {
256
+ type: "text",
257
+ text: "No Spotify devices found. Please open Spotify on a device and try again, or use spotify_open to launch it.",
258
+ },
259
+ ],
260
+ };
261
+ }
262
+ const formatted = devices.map((d, index) => {
263
+ const active = d.is_active ? " [Active]" : "";
264
+ const volume = d.volume_percent !== null && d.volume_percent !== undefined
265
+ ? ` - Volume: ${d.volume_percent}%`
266
+ : "";
267
+ return `${index + 1}. ${d.name} (${d.type})${active}${volume}\n ID: ${d.id}`;
268
+ });
140
269
  return {
141
270
  content: [
142
271
  {
143
272
  type: "text",
144
- text: `Currently playing: ${track.name} (${track.type})`,
273
+ text: `Available Spotify devices:\n\n${formatted.join("\n")}`,
145
274
  },
146
275
  ],
147
276
  };
148
277
  }
149
- const artists = track.artists.map((a) => a.name).join(", ");
150
- const album = track.album.name;
151
- const progress = Math.floor((state.body.progress_ms || 0) / 1000);
152
- const duration = Math.floor(track.duration_ms / 1000);
153
- const text = `${isPlaying ? "▶️ Playing" : "⏸️ Paused"}: ${track.name}
154
- Artist: ${artists}
155
- Album: ${album}
156
- Progress: ${formatTime(progress)} / ${formatTime(duration)}
157
- Device: ${device.name} (${device.type})
158
- Volume: ${device.volume_percent}%`;
159
- return {
160
- content: [
161
- {
162
- type: "text",
163
- text,
164
- },
165
- ],
166
- };
278
+ catch (error) {
279
+ return handleToolError(error, "spotify_get_devices");
280
+ }
281
+ }
282
+ function getSystemVolume() {
283
+ try {
284
+ if (process.platform !== "darwin")
285
+ return null;
286
+ const result = spawnSync("osascript", ["-e", "output volume of (get volume settings)"], {
287
+ shell: false,
288
+ timeout: 2000,
289
+ });
290
+ if (result.status !== 0)
291
+ return null;
292
+ const vol = parseInt(result.stdout.toString().trim(), 10);
293
+ return isNaN(vol) ? null : vol;
294
+ }
295
+ catch {
296
+ return null;
297
+ }
167
298
  }
168
299
  function formatTime(seconds) {
169
300
  const mins = Math.floor(seconds / 60);
@@ -1 +1 @@
1
- {"version":3,"file":"playback.js","sourceRoot":"","sources":["../../src/tools/playback.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"playback.js","sourceRoot":"","sources":["../../src/tools/playback.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"playlists.d.ts","sourceRoot":"","sources":["../../src/tools/playlists.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB,wBAAsB,YAAY,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CA+BlF;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CA6B9E;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuBpF;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAkBlF"}
1
+ {"version":3,"file":"playlists.d.ts","sourceRoot":"","sources":["../../src/tools/playlists.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB,wBAAsB,YAAY,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAmClF;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAiC9E;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CA2BpF;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAsBlF"}
@@ -2,42 +2,49 @@
2
2
  * Playlist management tools
3
3
  */
4
4
  import { getAuthenticatedClient } from "../spotify/client.js";
5
+ import { handleToolError } from "../spotify/errors.js";
5
6
  export async function getPlaylists(args) {
6
- const client = await getAuthenticatedClient();
7
- const limit = args.limit || 20;
8
- const result = await client.getUserPlaylists({ limit });
9
- const playlists = result.body.items;
10
- if (playlists.length === 0) {
7
+ try {
8
+ const client = await getAuthenticatedClient();
9
+ const limit = args.limit || 20;
10
+ const result = await client.getUserPlaylists({ limit });
11
+ const playlists = result.body.items;
12
+ if (playlists.length === 0) {
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: "No playlists found",
18
+ },
19
+ ],
20
+ };
21
+ }
22
+ const formatted = playlists.map((playlist, index) => `${index + 1}. ${playlist.name} (${playlist.tracks.total} tracks) - ${playlist.id}`);
11
23
  return {
12
24
  content: [
13
25
  {
14
26
  type: "text",
15
- text: "No playlists found",
27
+ text: `Your playlists:\n\n${formatted.join("\n")}`,
16
28
  },
17
29
  ],
18
30
  };
19
31
  }
20
- const formatted = playlists.map((playlist, index) => `${index + 1}. ${playlist.name} (${playlist.tracks.total} tracks) - ${playlist.id}`);
21
- return {
22
- content: [
23
- {
24
- type: "text",
25
- text: `Your playlists:\n\n${formatted.join("\n")}`,
26
- },
27
- ],
28
- };
32
+ catch (error) {
33
+ return handleToolError(error, "spotify_get_playlists");
34
+ }
29
35
  }
30
36
  export async function getPlaylist(args) {
31
- const client = await getAuthenticatedClient();
32
- const result = await client.getPlaylist(args.playlist_id);
33
- const playlist = result.body;
34
- const tracks = playlist.tracks.items.slice(0, 10).map((item, index) => {
35
- const track = item.track;
36
- if (!track)
37
- return `${index + 1}. [Unknown track]`;
38
- return `${index + 1}. ${track.name} - ${track.artists.map((a) => a.name).join(", ")}`;
39
- });
40
- const text = `Playlist: ${playlist.name}
37
+ try {
38
+ const client = await getAuthenticatedClient();
39
+ const result = await client.getPlaylist(args.playlist_id);
40
+ const playlist = result.body;
41
+ const tracks = playlist.tracks.items.slice(0, 10).map((item, index) => {
42
+ const track = item.track;
43
+ if (!track)
44
+ return `${index + 1}. [Unknown track]`;
45
+ return `${index + 1}. ${track.name} - ${track.artists.map((a) => a.name).join(", ")}`;
46
+ });
47
+ const text = `Playlist: ${playlist.name}
41
48
  Description: ${playlist.description || "No description"}
42
49
  Owner: ${playlist.owner.display_name}
43
50
  Tracks: ${playlist.tracks.total}
@@ -45,49 +52,63 @@ Public: ${playlist.public ? "Yes" : "No"}
45
52
 
46
53
  First 10 tracks:
47
54
  ${tracks.join("\n")}`;
48
- return {
49
- content: [
50
- {
51
- type: "text",
52
- text,
53
- },
54
- ],
55
- };
55
+ return {
56
+ content: [
57
+ {
58
+ type: "text",
59
+ text,
60
+ },
61
+ ],
62
+ };
63
+ }
64
+ catch (error) {
65
+ return handleToolError(error, "spotify_get_playlist");
66
+ }
56
67
  }
57
68
  export async function createPlaylist(args) {
58
- const client = await getAuthenticatedClient();
59
- const options = {
60
- name: args.name,
61
- public: args.public !== false, // Default to true
62
- };
63
- if (args.description) {
64
- options.description = args.description;
69
+ try {
70
+ const client = await getAuthenticatedClient();
71
+ const options = {
72
+ name: args.name,
73
+ public: args.public !== false, // Default to true
74
+ };
75
+ if (args.description) {
76
+ options.description = args.description;
77
+ }
78
+ const result = await client.createPlaylist(options.name, options);
79
+ const playlist = result.body;
80
+ return {
81
+ content: [
82
+ {
83
+ type: "text",
84
+ text: `Created playlist: ${playlist.name} (ID: ${playlist.id})`,
85
+ },
86
+ ],
87
+ };
88
+ }
89
+ catch (error) {
90
+ return handleToolError(error, "spotify_create_playlist");
65
91
  }
66
- const result = await client.createPlaylist(options.name, options);
67
- const playlist = result.body;
68
- return {
69
- content: [
70
- {
71
- type: "text",
72
- text: `Created playlist: ${playlist.name} (ID: ${playlist.id})`,
73
- },
74
- ],
75
- };
76
92
  }
77
93
  export async function addToPlaylist(args) {
78
- const client = await getAuthenticatedClient();
79
- const options = {};
80
- if (args.position !== undefined) {
81
- options.position = args.position;
94
+ try {
95
+ const client = await getAuthenticatedClient();
96
+ const options = {};
97
+ if (args.position !== undefined) {
98
+ options.position = args.position;
99
+ }
100
+ await client.addTracksToPlaylist(args.playlist_id, args.uris, options);
101
+ return {
102
+ content: [
103
+ {
104
+ type: "text",
105
+ text: `Added ${args.uris.length} track(s) to playlist`,
106
+ },
107
+ ],
108
+ };
109
+ }
110
+ catch (error) {
111
+ return handleToolError(error, "spotify_add_to_playlist");
82
112
  }
83
- await client.addTracksToPlaylist(args.playlist_id, args.uris, options);
84
- return {
85
- content: [
86
- {
87
- type: "text",
88
- text: `Added ${args.uris.length} track(s) to playlist`,
89
- },
90
- ],
91
- };
92
113
  }
93
114
  //# sourceMappingURL=playlists.js.map