change_keyword
Modify the keyword of an existing short URL to update it with a new keyword or title, ensuring the short URL remains accurate and relevant.
Instructions
Change the keyword of an existing short URL
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| newshorturl | Yes | The new keyword to use | |
| oldshorturl | Yes | The existing short URL or keyword | |
| title | No | Optional new title |
Implementation Reference
- src/tools/changeKeyword.js:39-74 (handler)The execute function implementing the change_keyword tool logic: validates input implicitly via schema, calls yourlsClient.changeKeyword with fallback, processes response, handles errors.execute: async ({ oldshorturl, newshorturl, url, title }) => { try { // Use the changeKeyword method with fallback enabled const result = await yourlsClient.changeKeyword(oldshorturl, newshorturl, url, title, true); if (result.status === 'success' || result.message === 'success: updated' || result.statusCode === 200) { const responseData = { message: result.message || result.simple || `Keyword changed from '${oldshorturl}' to '${newshorturl}'`, oldshorturl: oldshorturl, newshorturl: newshorturl, shorturl: result.shorturl }; // Add fallback information if applicable if (result.fallback_used) { responseData.fallback_used = true; if (result.fallback_limited) { responseData.fallback_limited = true; } if (result.fallback_limitations) { responseData.fallback_limitations = result.fallback_limitations; } } return createMcpResponse(true, responseData); } else { throw new Error(result.message || 'Unknown error'); } } catch (error) { return createMcpResponse(false, { message: error.message, oldshorturl: oldshorturl, newshorturl: newshorturl }); } }
- src/tools/changeKeyword.js:17-38 (schema)Input schema defining parameters for the change_keyword tool.inputSchema: { type: 'object', properties: { oldshorturl: { type: 'string', description: 'The existing short URL or keyword' }, newshorturl: { type: 'string', description: 'The new keyword to use' }, url: { type: 'string', description: 'Optional URL (if not provided, will use the URL from oldshorturl)' }, title: { type: 'string', description: 'Optional new title ("keep" to keep existing, "auto" to fetch from URL)' } }, required: ['oldshorturl', 'newshorturl'] },
- src/index.js:199-208 (registration)MCP server registration of the change_keyword tool, providing Zod schema and execute handler.server.tool( changeKeywordTool.name, changeKeywordTool.description, { oldshorturl: z.string().describe('The existing short URL or keyword'), newshorturl: z.string().describe('The new keyword to use'), title: z.string().optional().describe('Optional new title') }, changeKeywordTool.execute );
- src/api.js:624-666 (helper)YourlsClient.changeKeyword helper method: checks for API Edit URL plugin availability, makes 'change_keyword' API request, or falls back to _changeKeywordFallback.async changeKeyword(oldshorturl, newshorturl, url = null, title = null, useNativeFallback = true) { const params = { oldshorturl, newshorturl }; if (url) { params.url = url; } if (title) { params.title = title; } try { // First check if the plugin is available const isAvailable = await isPluginAvailable(this, 'edit_url', 'change_keyword', { oldshorturl: 'test', newshorturl: 'test2' }); if (isAvailable) { return this.request('change_keyword', params); } else if (useNativeFallback) { // Use our fallback implementation return this._changeKeywordFallback(oldshorturl, newshorturl, url, title); } else { throw new Error('The change_keyword action is not available. Please install the API Edit URL plugin.'); } } catch (error) { // If the error is not about a missing plugin, re-throw it if (!isPluginMissingError(error)) { throw error; } // If we're here, the plugin is missing and we need to use the fallback if (useNativeFallback) { return this._changeKeywordFallback(oldshorturl, newshorturl, url, title); } else { throw new Error('The change_keyword action is not available. Please install the API Edit URL plugin.'); } } }
- src/api.js:678-734 (helper)Fallback implementation when API Edit URL plugin unavailable: expands oldshorturl, creates new shorturl with new keyword (keeping URL/title), notes limitation (old keyword remains).async _changeKeywordFallback(oldshorturl, newshorturl, url = null, title = null) { try { // First, get the current details for the oldshorturl const currentDetails = await this.expand(oldshorturl); if (!currentDetails || !currentDetails.longurl) { throw new Error(`Short URL '${oldshorturl}' not found.`); } // Use the provided URL or the one from the current short URL const targetUrl = url || currentDetails.longurl; // Safety check for URL format validateUrl(targetUrl); // Determine the title let targetTitle = ''; if (title === 'keep') { targetTitle = currentDetails.title || ''; } else if (title === 'auto') { targetTitle = ''; // Let YOURLS fetch it from the URL } else if (title) { targetTitle = title; } else { targetTitle = currentDetails.title || ''; } // Create the new shorturl const shortenResult = await this.request('shorturl', { url: targetUrl, keyword: newshorturl, title: targetTitle }); if (shortenResult.status === 'fail') { throw new Error(`Failed to create new keyword: ${shortenResult.message || 'Unknown error'}`); } // Limitation: We can't delete the old shorturl without the Delete plugin const limitations = 'Creates new keyword but cannot delete old one (requires API Delete plugin)'; return { status: 'success', statusCode: 200, message: `Keyword changed (Note: The old keyword '${oldshorturl}' still exists)`, oldshorturl: oldshorturl, newshorturl: newshorturl, shorturl: shortenResult.shorturl, url: targetUrl, title: targetTitle, ...createFallbackInfo(limitations, true, 'API Edit URL and API Delete') }; } catch (error) { console.error('Change keyword fallback error:', error.message); throw error; } }