feat(tools): expand to 67 tools — full CRUD for contacts, banners, newsfeeds, tags, fields, menu items, messages, media, redirects, associations, checkin, and content history
Cascade Main → Dev / Merge main → dev (push) Has been cancelled
Changelog Validation / Validate CHANGELOG.md (push) Has been cancelled
Build & Release / Build & Release Pipeline (push) Has been cancelled
Deploy to Demo Server (SFTP) / Verify Deployment Permission (push) Has been cancelled
Standards Compliance / Secret Scanning (push) Has been cancelled
Standards Compliance / License Header Validation (push) Has been cancelled
Standards Compliance / Repository Structure Validation (push) Has been cancelled
Standards Compliance / Coding Standards Check (push) Has been cancelled
Standards Compliance / Workflow Configuration Check (push) Has been cancelled
Standards Compliance / Documentation Quality Check (push) Has been cancelled
Standards Compliance / README Completeness Check (push) Has been cancelled
CodeQL Security Scanning / Analyze (actions) (push) Has been cancelled
CodeQL Security Scanning / Analyze (javascript) (push) Has been cancelled
CodeQL Security Scanning / Security Scan Summary (push) Has been cancelled
Standards Compliance / Version Consistency Check (push) Has been cancelled
Standards Compliance / Git Repository Hygiene (push) Has been cancelled
Standards Compliance / Script Integrity Validation (push) Has been cancelled
Standards Compliance / Line Length Check (push) Has been cancelled
Standards Compliance / File Naming Standards (push) Has been cancelled
Standards Compliance / Insecure Code Pattern Detection (push) Has been cancelled
Standards Compliance / Code Complexity Analysis (push) Has been cancelled
Standards Compliance / Code Duplication Detection (push) Has been cancelled
Standards Compliance / Dead Code Detection (push) Has been cancelled
Standards Compliance / File Size Limits (push) Has been cancelled
Standards Compliance / Binary File Detection (push) Has been cancelled
Standards Compliance / TODO/FIXME Tracking (push) Has been cancelled
Standards Compliance / Dependency Vulnerability Scanning (push) Has been cancelled
Standards Compliance / Unused Dependencies Check (push) Has been cancelled
Standards Compliance / Broken Link Detection (push) Has been cancelled
Standards Compliance / API Documentation Coverage (push) Has been cancelled
Standards Compliance / Accessibility Check (push) Has been cancelled
Standards Compliance / Performance Metrics (push) Has been cancelled
Standards Compliance / Enterprise Readiness Check (push) Has been cancelled
Standards Compliance / Repository Health Check (push) Has been cancelled
Standards Compliance / Terraform Configuration Validation (push) Has been cancelled
Standards Compliance / Compliance Summary (push) Has been cancelled
Sync Version from README / Propagate README version (push) Has been cancelled
Deploy to Demo Server (SFTP) / SFTP Deploy → Demo (push) Has been cancelled
Cascade Main → Dev / Merge main → dev (push) Has been cancelled
Changelog Validation / Validate CHANGELOG.md (push) Has been cancelled
Build & Release / Build & Release Pipeline (push) Has been cancelled
Deploy to Demo Server (SFTP) / Verify Deployment Permission (push) Has been cancelled
Standards Compliance / Secret Scanning (push) Has been cancelled
Standards Compliance / License Header Validation (push) Has been cancelled
Standards Compliance / Repository Structure Validation (push) Has been cancelled
Standards Compliance / Coding Standards Check (push) Has been cancelled
Standards Compliance / Workflow Configuration Check (push) Has been cancelled
Standards Compliance / Documentation Quality Check (push) Has been cancelled
Standards Compliance / README Completeness Check (push) Has been cancelled
CodeQL Security Scanning / Analyze (actions) (push) Has been cancelled
CodeQL Security Scanning / Analyze (javascript) (push) Has been cancelled
CodeQL Security Scanning / Security Scan Summary (push) Has been cancelled
Standards Compliance / Version Consistency Check (push) Has been cancelled
Standards Compliance / Git Repository Hygiene (push) Has been cancelled
Standards Compliance / Script Integrity Validation (push) Has been cancelled
Standards Compliance / Line Length Check (push) Has been cancelled
Standards Compliance / File Naming Standards (push) Has been cancelled
Standards Compliance / Insecure Code Pattern Detection (push) Has been cancelled
Standards Compliance / Code Complexity Analysis (push) Has been cancelled
Standards Compliance / Code Duplication Detection (push) Has been cancelled
Standards Compliance / Dead Code Detection (push) Has been cancelled
Standards Compliance / File Size Limits (push) Has been cancelled
Standards Compliance / Binary File Detection (push) Has been cancelled
Standards Compliance / TODO/FIXME Tracking (push) Has been cancelled
Standards Compliance / Dependency Vulnerability Scanning (push) Has been cancelled
Standards Compliance / Unused Dependencies Check (push) Has been cancelled
Standards Compliance / Broken Link Detection (push) Has been cancelled
Standards Compliance / API Documentation Coverage (push) Has been cancelled
Standards Compliance / Accessibility Check (push) Has been cancelled
Standards Compliance / Performance Metrics (push) Has been cancelled
Standards Compliance / Enterprise Readiness Check (push) Has been cancelled
Standards Compliance / Repository Health Check (push) Has been cancelled
Standards Compliance / Terraform Configuration Validation (push) Has been cancelled
Standards Compliance / Compliance Summary (push) Has been cancelled
Sync Version from README / Propagate README version (push) Has been cancelled
Deploy to Demo Server (SFTP) / SFTP Deploy → Demo (push) Has been cancelled
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+541
@@ -633,6 +633,547 @@ server.tool(
|
||||
},
|
||||
);
|
||||
|
||||
// ── Contacts (CRUD) ─────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_contact_get',
|
||||
'Get a single contact by ID',
|
||||
{
|
||||
id: z.number().describe('Contact ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get(`/contact/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_contact_create',
|
||||
'Create a new contact',
|
||||
{
|
||||
name: z.string().describe('Contact name'),
|
||||
alias: z.string().optional().describe('URL alias'),
|
||||
catid: z.number().optional().describe('Category ID'),
|
||||
email_to: z.string().optional().describe('Email address'),
|
||||
telephone: z.string().optional().describe('Phone number'),
|
||||
address: z.string().optional().describe('Street address'),
|
||||
suburb: z.string().optional().describe('City/suburb'),
|
||||
state: z.string().optional().describe('State/province'),
|
||||
postcode: z.string().optional().describe('Postal code'),
|
||||
country_id: z.number().optional().describe('Country ID'),
|
||||
published: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
language: z.string().optional().describe('Language code (default "*")'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ name, alias, catid, email_to, telephone, address, suburb, state, postcode, country_id, published, language, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = { name, language: language ?? '*' };
|
||||
if (alias) body.alias = alias;
|
||||
if (catid !== undefined) body.catid = catid;
|
||||
if (email_to) body.email_to = email_to;
|
||||
if (telephone) body.telephone = telephone;
|
||||
if (address) body.address = address;
|
||||
if (suburb) body.suburb = suburb;
|
||||
if (state) body.state = state;
|
||||
if (postcode) body.postcode = postcode;
|
||||
if (country_id !== undefined) body.country_id = country_id;
|
||||
if (published !== undefined) body.published = published;
|
||||
return formatResponse(await client.post('/contact', body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_contact_update',
|
||||
'Update an existing contact',
|
||||
{
|
||||
id: z.number().describe('Contact ID'),
|
||||
name: z.string().optional().describe('Contact name'),
|
||||
email_to: z.string().optional().describe('Email address'),
|
||||
telephone: z.string().optional().describe('Phone number'),
|
||||
address: z.string().optional().describe('Street address'),
|
||||
published: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, name, email_to, telephone, address, published, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = {};
|
||||
if (name !== undefined) body.name = name;
|
||||
if (email_to !== undefined) body.email_to = email_to;
|
||||
if (telephone !== undefined) body.telephone = telephone;
|
||||
if (address !== undefined) body.address = address;
|
||||
if (published !== undefined) body.published = published;
|
||||
return formatResponse(await client.patch(`/contact/${id}`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_contact_delete',
|
||||
'Delete a contact',
|
||||
{
|
||||
id: z.number().describe('Contact ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/contact/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Banners (CRUD) ──────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_banner_get',
|
||||
'Get a single banner by ID',
|
||||
{
|
||||
id: z.number().describe('Banner ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get(`/banners/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_banner_create',
|
||||
'Create a new banner',
|
||||
{
|
||||
name: z.string().describe('Banner name'),
|
||||
catid: z.number().optional().describe('Category ID'),
|
||||
clickurl: z.string().optional().describe('Click URL'),
|
||||
custombannercode: z.string().optional().describe('Custom HTML/code for the banner'),
|
||||
state: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ name, catid, clickurl, custombannercode, state, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = { name };
|
||||
if (catid !== undefined) body.catid = catid;
|
||||
if (clickurl) body.clickurl = clickurl;
|
||||
if (custombannercode) body.custombannercode = custombannercode;
|
||||
if (state !== undefined) body.state = state;
|
||||
return formatResponse(await client.post('/banners', body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_banner_delete',
|
||||
'Delete a banner',
|
||||
{
|
||||
id: z.number().describe('Banner ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/banners/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Banner Clients ──────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_banner_clients_list',
|
||||
'List banner clients',
|
||||
{ ...ConnectionParam },
|
||||
async ({ connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get('/banners/clients'));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Newsfeeds (CRUD) ────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_newsfeed_get',
|
||||
'Get a single newsfeed by ID',
|
||||
{
|
||||
id: z.number().describe('Newsfeed ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get(`/newsfeeds/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_newsfeed_create',
|
||||
'Create a new newsfeed',
|
||||
{
|
||||
name: z.string().describe('Feed name'),
|
||||
link: z.string().describe('Feed URL'),
|
||||
catid: z.number().describe('Category ID'),
|
||||
numarticles: z.number().optional().describe('Number of articles to display'),
|
||||
published: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
language: z.string().optional().describe('Language code (default "*")'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ name, link, catid, numarticles, published, language, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = { name, link, catid, language: language ?? '*' };
|
||||
if (numarticles !== undefined) body.numarticles = numarticles;
|
||||
if (published !== undefined) body.published = published;
|
||||
return formatResponse(await client.post('/newsfeeds', body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_newsfeed_delete',
|
||||
'Delete a newsfeed',
|
||||
{
|
||||
id: z.number().describe('Newsfeed ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/newsfeeds/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Tags (CRUD) ─────────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_tag_get',
|
||||
'Get a single tag by ID',
|
||||
{
|
||||
id: z.number().describe('Tag ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get(`/tags/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_tag_update',
|
||||
'Update a tag',
|
||||
{
|
||||
id: z.number().describe('Tag ID'),
|
||||
title: z.string().optional().describe('New tag title'),
|
||||
published: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, title, published, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = {};
|
||||
if (title !== undefined) body.title = title;
|
||||
if (published !== undefined) body.published = published;
|
||||
return formatResponse(await client.patch(`/tags/${id}`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_tag_delete',
|
||||
'Delete a tag',
|
||||
{
|
||||
id: z.number().describe('Tag ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/tags/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Custom Fields (CRUD) ────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_field_get',
|
||||
'Get a single custom field by ID',
|
||||
{
|
||||
id: z.number().describe('Field ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get(`/fields/com_content.article/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_field_create',
|
||||
'Create a custom field',
|
||||
{
|
||||
title: z.string().describe('Field title'),
|
||||
name: z.string().describe('Field name (system identifier)'),
|
||||
type: z.string().describe('Field type (text, textarea, list, radio, checkboxes, etc.)'),
|
||||
context: z.string().optional().describe('Context (default "com_content.article")'),
|
||||
label: z.string().optional().describe('Display label'),
|
||||
description: z.string().optional().describe('Field description'),
|
||||
required: z.number().optional().describe('1=required, 0=optional'),
|
||||
state: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ title, name, type, context, label, description, required: req, state, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const ctx = context ?? 'com_content.article';
|
||||
const body: Record<string, unknown> = { title, name, type };
|
||||
if (label) body.label = label;
|
||||
if (description) body.description = description;
|
||||
if (req !== undefined) body.required = req;
|
||||
if (state !== undefined) body.state = state;
|
||||
return formatResponse(await client.post(`/fields/${ctx}`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_field_delete',
|
||||
'Delete a custom field',
|
||||
{
|
||||
id: z.number().describe('Field ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/fields/com_content.article/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Menu Items (CRUD) ───────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_menu_item_create',
|
||||
'Create a new menu item',
|
||||
{
|
||||
title: z.string().describe('Menu item title'),
|
||||
menutype: z.string().describe('Menu type alias (e.g. "mainmenu")'),
|
||||
type: z.string().describe('Menu item type (e.g. "component", "url", "alias", "separator", "heading")'),
|
||||
link: z.string().optional().describe('URL or component link'),
|
||||
parent_id: z.number().optional().describe('Parent menu item ID (default 1 = root)'),
|
||||
published: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
access: z.number().optional().describe('Access level ID'),
|
||||
language: z.string().optional().describe('Language code (default "*")'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ title, menutype, type, link, parent_id, published, access, language, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = {
|
||||
title,
|
||||
menutype,
|
||||
type,
|
||||
language: language ?? '*',
|
||||
};
|
||||
if (link) body.link = link;
|
||||
if (parent_id !== undefined) body.parent_id = parent_id;
|
||||
if (published !== undefined) body.published = published;
|
||||
if (access !== undefined) body.access = access;
|
||||
return formatResponse(await client.post('/menus/items', body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_menu_item_update',
|
||||
'Update a menu item',
|
||||
{
|
||||
id: z.number().describe('Menu item ID'),
|
||||
title: z.string().optional().describe('New title'),
|
||||
link: z.string().optional().describe('New link URL'),
|
||||
published: z.number().optional().describe('1=published, 0=unpublished'),
|
||||
parent_id: z.number().optional().describe('New parent ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, title, link, published, parent_id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = {};
|
||||
if (title !== undefined) body.title = title;
|
||||
if (link !== undefined) body.link = link;
|
||||
if (published !== undefined) body.published = published;
|
||||
if (parent_id !== undefined) body.parent_id = parent_id;
|
||||
return formatResponse(await client.patch(`/menus/items/${id}`, body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_menu_item_delete',
|
||||
'Delete a menu item',
|
||||
{
|
||||
id: z.number().describe('Menu item ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/menus/items/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Messages (Send) ────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_message_send',
|
||||
'Send a private message to a Joomla user',
|
||||
{
|
||||
user_id_to: z.number().describe('Recipient user ID'),
|
||||
subject: z.string().describe('Message subject'),
|
||||
message: z.string().describe('Message body'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ user_id_to, subject, message, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.post('/messages', { user_id_to, subject, message }));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_message_delete',
|
||||
'Delete a private message',
|
||||
{
|
||||
id: z.number().describe('Message ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/messages/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Media (Upload/Delete) ───────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_media_file_get',
|
||||
'Get metadata for a specific media file',
|
||||
{
|
||||
path: z.string().describe('File path relative to media root (e.g. "images/logo.png")'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ path, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get(`/media/files/${encodeURIComponent(path)}`));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_media_file_delete',
|
||||
'Delete a media file',
|
||||
{
|
||||
path: z.string().describe('File path relative to media root'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ path, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/media/files/${encodeURIComponent(path)}`));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_media_folder_create',
|
||||
'Create a new media folder',
|
||||
{
|
||||
path: z.string().describe('Full folder path to create (e.g. "images/photos/2026")'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ path, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.post('/media/files', { path }));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Content History ─────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_content_history_list',
|
||||
'List version history for a content item',
|
||||
{
|
||||
type_alias: z.string().describe('Content type alias (e.g. "com_content.article")'),
|
||||
item_id: z.number().describe('Item ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ type_alias, item_id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get('/content/history', {
|
||||
'filter[type_alias]': type_alias,
|
||||
'filter[item_id]': String(item_id),
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Checkin ─────────────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_checkin',
|
||||
'Check in (unlock) a content item that is checked out',
|
||||
{
|
||||
context: z.string().describe('Context (e.g. "com_content.article")'),
|
||||
id: z.number().describe('Item ID to check in'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ context, id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.post(`/checkin/${context}/${id}`, {}));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Redirects ───────────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_redirects_list',
|
||||
'List URL redirects',
|
||||
{
|
||||
search: z.string().optional().describe('Search in old URL'),
|
||||
state: z.enum(['0', '1', '2', '-2']).optional().describe('0=disabled, 1=enabled, 2=archived, -2=trashed'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ search, state, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const params: Record<string, string> = {};
|
||||
if (search) params['filter[search]'] = search;
|
||||
if (state !== undefined) params['filter[state]'] = state;
|
||||
return formatResponse(await client.get('/redirects', params));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_redirect_create',
|
||||
'Create a URL redirect',
|
||||
{
|
||||
old_url: z.string().describe('Source URL to redirect from'),
|
||||
new_url: z.string().describe('Destination URL to redirect to'),
|
||||
status_code: z.enum(['301', '302']).optional().describe('301=permanent, 302=temporary (default 301)'),
|
||||
published: z.number().optional().describe('1=enabled, 0=disabled'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ old_url, new_url, status_code, published, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
const body: Record<string, unknown> = {
|
||||
old_url,
|
||||
new_url,
|
||||
header: status_code ? Number(status_code) : 301,
|
||||
published: published ?? 1,
|
||||
};
|
||||
return formatResponse(await client.post('/redirects', body));
|
||||
},
|
||||
);
|
||||
|
||||
server.tool(
|
||||
'joomla_redirect_delete',
|
||||
'Delete a URL redirect',
|
||||
{
|
||||
id: z.number().describe('Redirect ID'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.delete(`/redirects/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Associations (Multilingual) ─────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
'joomla_associations_list',
|
||||
'List multilingual associations for a content type',
|
||||
{
|
||||
context: z.string().describe('Context (e.g. "com_content.article")'),
|
||||
id: z.number().describe('Item ID to get associations for'),
|
||||
...ConnectionParam,
|
||||
},
|
||||
async ({ context, id, connection }) => {
|
||||
const client = clientFor(connection);
|
||||
return formatResponse(await client.get(`/associations/${context}/${id}`));
|
||||
},
|
||||
);
|
||||
|
||||
// ── Generic API Call ────────────────────────────────────────────────────
|
||||
|
||||
server.tool(
|
||||
|
||||
Reference in New Issue
Block a user