Skip to main content
Glama
live-server.test.js9.52 kB
const PlexMCPServer = require('../../index.js'); // Check if we should run E2E tests const plexUrl = process.env.E2E_PLEX_URL || process.env.PLEX_URL; const plexToken = process.env.E2E_PLEX_TOKEN || process.env.PLEX_TOKEN; const isTestEnvironment = plexUrl?.includes('test-plex-server.com') || plexToken?.includes('test-token'); const shouldRunE2E = plexUrl && plexToken && !isTestEnvironment; const describeE2E = shouldRunE2E ? describe : describe.skip; describeE2E('E2E Live Plex Server Tests', () => { let server; let originalEnv; beforeAll(() => { // Save original environment originalEnv = { ...process.env }; console.log('Running E2E tests against live Plex server'); // Set environment for tests process.env.PLEX_URL = plexUrl; process.env.PLEX_TOKEN = plexToken; // Validate environment variables format if (!process.env.PLEX_URL.startsWith('http')) { throw new Error('PLEX_URL must start with http:// or https://'); } if (process.env.PLEX_TOKEN.length < 10) { throw new Error('PLEX_TOKEN appears to be too short'); } server = new PlexMCPServer(); }); afterAll(() => { // Restore original environment process.env = originalEnv; }); describe('Server Connectivity', () => { it('should connect to live Plex server and retrieve library data', async() => { const result = await server.handleBrowseLibraries(); expect(result).toBeDefined(); expect(result.content).toBeDefined(); expect(result.content[0].type).toBe('text'); const text = result.content[0].text; // Should either show libraries, an error, or SSL certificate issues (all valid outcomes) expect(text).toMatch(/Available Plex Libraries|libraries found|No libraries found|Library:|Error (browsing libraries|searching Plex): .*(certificate|SSL|hostname)/i); }, 10000); // 10 second timeout for network requests it('should handle SSL verification based on PLEX_VERIFY_SSL setting', async() => { // Test with SSL verification enabled (default) delete process.env.PLEX_VERIFY_SSL; const result1 = await server.handleBrowseLibraries(); expect(result1.content[0].text).toMatch(/Available Plex Libraries|libraries found|No libraries found|Library:|Error (browsing libraries|searching Plex): .*(certificate|SSL|hostname)/i); // Test with SSL verification disabled process.env.PLEX_VERIFY_SSL = 'false'; const server2 = new PlexMCPServer(); const result2 = await server2.handleBrowseLibraries(); expect(result2.content[0].text).toMatch(/Available Plex Libraries|libraries found|No libraries found|Library:|Error (browsing libraries|searching Plex): .*(certificate|SSL|hostname)/i); // Clean up delete process.env.PLEX_VERIFY_SSL; }, 15000); }); describe('Library Data Retrieval', () => { it('should retrieve library list from live Plex server', async() => { const result = await server.handleBrowseLibraries(); expect(result).toBeDefined(); expect(result.content).toBeDefined(); expect(result.content[0].type).toBe('text'); const libraryText = result.content[0].text; expect(libraryText).toMatch(/Available Plex Libraries|libraries found|Error (browsing libraries|searching Plex): .*(certificate|SSL|hostname)/i); // Should contain at least basic library structure (unless SSL error) if (!libraryText.match(/Error.*certificate|SSL|hostname/i)) { expect(libraryText).toMatch(/Library:|Type:|Key:|Library ID:/); } }, 10000); it('should retrieve content from first available library', async() => { // First get the libraries const librariesResult = await server.handleBrowseLibraries(); const libraryText = librariesResult.content[0].text; // Extract first library key using regex const keyMatch = libraryText.match(/Library ID: (\d+)|Key: (\d+)/); if (keyMatch) { const libraryKey = keyMatch[1] || keyMatch[2]; // Browse the first library const browseResult = await server.handleBrowseLibrary({ library_key: libraryKey, limit: 5 }); expect(browseResult).toBeDefined(); expect(browseResult.content).toBeDefined(); expect(browseResult.content[0].type).toBe('text'); const browseText = browseResult.content[0].text; expect(browseText).toMatch(/Found \d+ items|No items found/); } else { // If no libraries found or SSL error, that's also a valid test result expect(libraryText).toMatch(/No libraries found|Available Plex Libraries|Error.*certificate|SSL|hostname/i); } }, 15000); it('should perform a simple search on live server', async() => { const result = await server.handlePlexSearch({ query: 'the', // Simple search term likely to return results limit: 3 }); expect(result).toBeDefined(); expect(result.content).toBeDefined(); expect(result.content[0].type).toBe('text'); const searchText = result.content[0].text; expect(searchText).toMatch(/Found \d+ results|No results found|Error searching Plex: .*(certificate|SSL|hostname)/i); }, 10000); }); describe('Playlist Operations with Live Server', () => { let createdPlaylistId = null; it('should create playlist with initial item using ratingKey', async() => { // First search for an item to use const searchResult = await server.handlePlexSearch({ query: 'track', limit: 1 }); const searchText = searchResult.content[0].text; console.log('Search result:', searchText); // Extract ratingKey from search results - look for "ID: 244736" pattern const idMatch = searchText.match(/\*\*ID: (\d+)\*\*/); if (idMatch) { const itemKey = idMatch[1]; console.log('Found item with ratingKey:', itemKey); // Create playlist with this item const createResult = await server.handleCreatePlaylist({ title: 'Claude_Code_Test_' + Date.now(), type: 'audio', item_key: itemKey }); expect(createResult).toBeDefined(); const createText = createResult.content[0].text; console.log('Create result:', createText); // Extract playlist ID from response const playlistMatch = createText.match(/Playlist ID: (\w+)/); if (playlistMatch) { createdPlaylistId = playlistMatch[1]; console.log('Created playlist ID:', createdPlaylistId); } expect(createText).toMatch(/Successfully created playlist|Playlist ID:/); } else { console.log('No items found in search, skipping playlist creation test'); } }, 15000); it('should add second item to playlist using ratingKey', async() => { if (!createdPlaylistId) { console.log('No playlist created, skipping add item test'); return; } // Search for another item const searchResult = await server.handlePlexSearch({ query: 'music', limit: 2 }); const searchText = searchResult.content[0].text; console.log('Second search result:', searchText); // Extract different ratingKey from search results const allIds = [...searchText.matchAll(/\*\*ID: (\d+)\*\*/g)]; if (allIds.length > 1) { const secondItemKey = allIds[1][1]; console.log('Adding second item with ratingKey:', secondItemKey); // Add item to playlist const addResult = await server.handleAddToPlaylist({ playlist_id: createdPlaylistId, item_keys: [secondItemKey] }); expect(addResult).toBeDefined(); const addText = addResult.content[0].text; console.log('Add item result:', addText); expect(addText).toMatch(/Successfully added|items to playlist|Error adding items/); } else { console.log('Not enough items found for add test'); } }, 15000); it('should browse playlist contents', async() => { if (!createdPlaylistId) { console.log('No playlist created, skipping browse test'); return; } const browseResult = await server.handleBrowsePlaylist({ playlist_id: createdPlaylistId }); expect(browseResult).toBeDefined(); const browseText = browseResult.content[0].text; console.log('Browse playlist result:', browseText); // Should show playlist contents or explain why empty expect(browseText).toMatch(/Found \d+ items|No items found|Playlist contents|Error browsing playlist/); }, 10000); }); describe('Error Handling with Live Server', () => { it('should handle invalid search gracefully', async() => { const result = await server.handlePlexSearch({ query: 'zzznonexistentmovie12345zzz', limit: 1 }); expect(result).toBeDefined(); expect(result.content[0].text).toMatch(/Found 0 results|Error searching Plex: .*(certificate|SSL|hostname)/i); }, 10000); it('should handle invalid library key gracefully', async() => { const result = await server.handleBrowseLibrary({ library_key: '99999', // Non-existent library key limit: 1 }); expect(result).toBeDefined(); // Should either return error message or empty results expect(result.content[0].text).toMatch(/error|not found|No items found|Found 0 items/i); }, 10000); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vyb1ng/plex-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server