directify-mcp 1.3.1 → 1.4.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/README.md +34 -2
- package/package.json +1 -1
- package/src/tools.js +127 -2
package/README.md
CHANGED
|
@@ -163,6 +163,10 @@ Ask Claude: *"List my Directify directories"* - or find it in the URL when viewi
|
|
|
163
163
|
| Tool | Description |
|
|
164
164
|
|------|-------------|
|
|
165
165
|
| `list_custom_fields` | List all custom fields (useful to know field names for listings) |
|
|
166
|
+
| `get_custom_field` | Get a custom field definition |
|
|
167
|
+
| `create_custom_field` | Create a custom field definition (text, number, select, etc.) |
|
|
168
|
+
| `update_custom_field` | Update a custom field definition |
|
|
169
|
+
| `delete_custom_field` | Delete a custom field (also removes its values from listings) |
|
|
166
170
|
|
|
167
171
|
### Listings
|
|
168
172
|
|
|
@@ -170,12 +174,14 @@ Ask Claude: *"List my Directify directories"* - or find it in the URL when viewi
|
|
|
170
174
|
|------|-------------|
|
|
171
175
|
| `list_listings` | List all listings (paginated) |
|
|
172
176
|
| `get_listing` | Get full listing details with custom fields |
|
|
173
|
-
| `create_listing` | Create a new listing with custom field values |
|
|
174
|
-
| `update_listing` | Update a listing |
|
|
177
|
+
| `create_listing` | Create a new listing with custom field values (and link organizers) |
|
|
178
|
+
| `update_listing` | Update a listing (including its linked organizers) |
|
|
175
179
|
| `delete_listing` | Delete a listing |
|
|
176
180
|
| `check_listing_exists` | Check if a URL already exists |
|
|
177
181
|
| `bulk_create_listings` | Create up to 100 listings at once |
|
|
178
182
|
|
|
183
|
+
Listings can be linked to one or more organizers by passing an `organizers` array of organizer IDs to `create_listing` / `update_listing` (use `list_organizers` to find the IDs). On update, the array replaces the current set.
|
|
184
|
+
|
|
179
185
|
### Articles
|
|
180
186
|
|
|
181
187
|
| Tool | Description |
|
|
@@ -198,6 +204,20 @@ Ask Claude: *"List my Directify directories"* - or find it in the URL when viewi
|
|
|
198
204
|
| `delete_page` | Delete a page |
|
|
199
205
|
| `toggle_page` | Toggle published/unpublished status |
|
|
200
206
|
|
|
207
|
+
### Organizers
|
|
208
|
+
|
|
209
|
+
Organizers represent entities like agencies, studios, or event hosts that can be linked to multiple listings.
|
|
210
|
+
|
|
211
|
+
| Tool | Description |
|
|
212
|
+
|------|-------------|
|
|
213
|
+
| `list_organizers` | List all organizers (with their linked listings) |
|
|
214
|
+
| `get_organizer` | Get organizer details (with linked listings) |
|
|
215
|
+
| `create_organizer` | Create a new organizer |
|
|
216
|
+
| `update_organizer` | Update an organizer |
|
|
217
|
+
| `delete_organizer` | Delete an organizer |
|
|
218
|
+
|
|
219
|
+
To link an organizer to a listing, pass the organizer's ID in the `organizers` array of `create_listing` / `update_listing` (see Listings above).
|
|
220
|
+
|
|
201
221
|
## Example Conversations
|
|
202
222
|
|
|
203
223
|
### Create a listing
|
|
@@ -224,6 +244,18 @@ Claude will use `create_article` with markdown content.
|
|
|
224
244
|
|
|
225
245
|
Claude will use `list_listings`, then `update_listing` for each one.
|
|
226
246
|
|
|
247
|
+
### Link listings to an organizer
|
|
248
|
+
|
|
249
|
+
> **You:** Create an organizer "Acme Events", then add these 3 festival listings and link them all to it.
|
|
250
|
+
|
|
251
|
+
Claude will use `create_organizer`, then `create_listing` for each festival with the new organizer's ID in the `organizers` array.
|
|
252
|
+
|
|
253
|
+
### Define a custom field
|
|
254
|
+
|
|
255
|
+
> **You:** Add a "Price Range" dropdown field with options $, $$, and $$$, and make it filterable.
|
|
256
|
+
|
|
257
|
+
Claude will use `create_custom_field` with `type: "select"`, the options, and `filterable: true` — then you can set the value per listing via `create_listing` / `update_listing`.
|
|
258
|
+
|
|
227
259
|
### Create programmatic SEO pages
|
|
228
260
|
|
|
229
261
|
> **You:** Create comparison pages for "NYC vs Chicago pizza", "NYC vs LA tacos", and "NYC vs Boston seafood" with SEO titles and descriptions.
|
package/package.json
CHANGED
package/src/tools.js
CHANGED
|
@@ -242,6 +242,116 @@ export const listCustomFields = {
|
|
|
242
242
|
},
|
|
243
243
|
};
|
|
244
244
|
|
|
245
|
+
const CUSTOM_FIELD_TYPES = [
|
|
246
|
+
'text', 'number', 'date', 'file_upload', 'url', 'email', 'rich_editor',
|
|
247
|
+
'markdown', 'textarea', 'checkbox', 'rating', 'select', 'list',
|
|
248
|
+
'multi_select', 'button', 'javascript', 'html',
|
|
249
|
+
];
|
|
250
|
+
|
|
251
|
+
export const getCustomField = {
|
|
252
|
+
name: 'get_custom_field',
|
|
253
|
+
description: 'Get the definition of a specific custom field.',
|
|
254
|
+
inputSchema: {
|
|
255
|
+
type: 'object',
|
|
256
|
+
properties: {
|
|
257
|
+
directory_id: { type: 'string', description: 'Directory ID' },
|
|
258
|
+
custom_field_id: { type: 'string', description: 'Custom field ID' },
|
|
259
|
+
},
|
|
260
|
+
required: ['custom_field_id'],
|
|
261
|
+
},
|
|
262
|
+
handler: async ({ directory_id, custom_field_id }) => {
|
|
263
|
+
const dir = resolveDirectory(directory_id);
|
|
264
|
+
const data = await api.get(`/directories/${dir}/custom-fields/${custom_field_id}`);
|
|
265
|
+
return data.data || data;
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export const createCustomField = {
|
|
270
|
+
name: 'create_custom_field',
|
|
271
|
+
description:
|
|
272
|
+
'Create a new custom field definition for a directory. Field values are then set on listings by passing the field name as a key (see create_listing / update_listing).',
|
|
273
|
+
inputSchema: {
|
|
274
|
+
type: 'object',
|
|
275
|
+
properties: {
|
|
276
|
+
directory_id: { type: 'string', description: 'Directory ID' },
|
|
277
|
+
label: { type: 'string', description: 'Human-readable field label (shown to users)' },
|
|
278
|
+
type: { type: 'string', enum: CUSTOM_FIELD_TYPES, description: 'Field type' },
|
|
279
|
+
name: { type: 'string', description: 'Machine name/key used when setting values (auto-derived from label, snake_cased, if omitted)' },
|
|
280
|
+
fieldable_type: { type: 'string', enum: ['listing', 'organizer', 'article'], description: 'What the field attaches to (default: listing)' },
|
|
281
|
+
placeholder: { type: 'string', description: 'Input placeholder text' },
|
|
282
|
+
description: { type: 'string', description: 'Help text shown under the field' },
|
|
283
|
+
default_value: { type: 'string', description: 'Default value' },
|
|
284
|
+
value_prefix: { type: 'string', description: 'Prefix shown before the value (e.g. "$")' },
|
|
285
|
+
value_suffix: { type: 'string', description: 'Suffix shown after the value (e.g. "/mo")' },
|
|
286
|
+
options: { type: 'array', items: { type: 'string' }, description: 'Options for select / multi_select / list field types' },
|
|
287
|
+
is_required: { type: 'boolean', description: 'Whether the field is required' },
|
|
288
|
+
is_visible: { type: 'boolean', description: 'Whether the field is shown on the listing page (default: true)' },
|
|
289
|
+
show_on_card: { type: 'boolean', description: 'Show the value on listing cards' },
|
|
290
|
+
show_on_public_submission: { type: 'boolean', description: 'Show the field on the public submission form' },
|
|
291
|
+
filterable: { type: 'boolean', description: 'Allow filtering listings by this field' },
|
|
292
|
+
order: { type: 'number', description: 'Sort order among fields' },
|
|
293
|
+
},
|
|
294
|
+
required: ['label', 'type'],
|
|
295
|
+
},
|
|
296
|
+
handler: async ({ directory_id, ...body }) => {
|
|
297
|
+
const dir = resolveDirectory(directory_id);
|
|
298
|
+
const data = await api.post(`/directories/${dir}/custom-fields`, body);
|
|
299
|
+
return data.data || data;
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
export const updateCustomField = {
|
|
304
|
+
name: 'update_custom_field',
|
|
305
|
+
description: 'Update an existing custom field definition. Only pass fields you want to change.',
|
|
306
|
+
inputSchema: {
|
|
307
|
+
type: 'object',
|
|
308
|
+
properties: {
|
|
309
|
+
directory_id: { type: 'string', description: 'Directory ID' },
|
|
310
|
+
custom_field_id: { type: 'string', description: 'Custom field ID to update' },
|
|
311
|
+
label: { type: 'string', description: 'Human-readable field label' },
|
|
312
|
+
type: { type: 'string', enum: CUSTOM_FIELD_TYPES, description: 'Field type' },
|
|
313
|
+
name: { type: 'string', description: 'Machine name/key used when setting values' },
|
|
314
|
+
fieldable_type: { type: 'string', enum: ['listing', 'organizer', 'article'], description: 'What the field attaches to' },
|
|
315
|
+
placeholder: { type: 'string', description: 'Input placeholder text' },
|
|
316
|
+
description: { type: 'string', description: 'Help text shown under the field' },
|
|
317
|
+
default_value: { type: 'string', description: 'Default value' },
|
|
318
|
+
value_prefix: { type: 'string', description: 'Prefix shown before the value' },
|
|
319
|
+
value_suffix: { type: 'string', description: 'Suffix shown after the value' },
|
|
320
|
+
options: { type: 'array', items: { type: 'string' }, description: 'Options for select / multi_select / list field types' },
|
|
321
|
+
is_required: { type: 'boolean', description: 'Whether the field is required' },
|
|
322
|
+
is_visible: { type: 'boolean', description: 'Whether the field is shown on the listing page' },
|
|
323
|
+
show_on_card: { type: 'boolean', description: 'Show the value on listing cards' },
|
|
324
|
+
show_on_public_submission: { type: 'boolean', description: 'Show the field on the public submission form' },
|
|
325
|
+
filterable: { type: 'boolean', description: 'Allow filtering listings by this field' },
|
|
326
|
+
order: { type: 'number', description: 'Sort order among fields' },
|
|
327
|
+
},
|
|
328
|
+
required: ['custom_field_id'],
|
|
329
|
+
},
|
|
330
|
+
handler: async ({ directory_id, custom_field_id, ...body }) => {
|
|
331
|
+
const dir = resolveDirectory(directory_id);
|
|
332
|
+
const data = await api.put(`/directories/${dir}/custom-fields/${custom_field_id}`, body);
|
|
333
|
+
return data.data || data;
|
|
334
|
+
},
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
export const deleteCustomField = {
|
|
338
|
+
name: 'delete_custom_field',
|
|
339
|
+
description: 'Delete a custom field definition from a directory. This also removes the field\'s values from all listings.',
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: 'object',
|
|
342
|
+
properties: {
|
|
343
|
+
directory_id: { type: 'string', description: 'Directory ID' },
|
|
344
|
+
custom_field_id: { type: 'string', description: 'Custom field ID to delete' },
|
|
345
|
+
},
|
|
346
|
+
required: ['custom_field_id'],
|
|
347
|
+
},
|
|
348
|
+
handler: async ({ directory_id, custom_field_id }) => {
|
|
349
|
+
const dir = resolveDirectory(directory_id);
|
|
350
|
+
await api.delete(`/directories/${dir}/custom-fields/${custom_field_id}`);
|
|
351
|
+
return { success: true, message: `Custom field ${custom_field_id} deleted.` };
|
|
352
|
+
},
|
|
353
|
+
};
|
|
354
|
+
|
|
245
355
|
// ─── Listings ───
|
|
246
356
|
|
|
247
357
|
export const listListings = {
|
|
@@ -282,7 +392,7 @@ export const getListing = {
|
|
|
282
392
|
export const createListing = {
|
|
283
393
|
name: 'create_listing',
|
|
284
394
|
description:
|
|
285
|
-
'Create a new listing in a directory. You can include custom field values by using the field name as a key (use list_custom_fields to see available fields).',
|
|
395
|
+
'Create a new listing in a directory. You can include custom field values by using the field name as a key (use list_custom_fields to see available fields). Link the listing to organizers by passing their IDs (use list_organizers to find them).',
|
|
286
396
|
inputSchema: {
|
|
287
397
|
type: 'object',
|
|
288
398
|
properties: {
|
|
@@ -309,6 +419,11 @@ export const createListing = {
|
|
|
309
419
|
items: { type: 'number' },
|
|
310
420
|
description: 'Array of tag IDs',
|
|
311
421
|
},
|
|
422
|
+
organizers: {
|
|
423
|
+
type: 'array',
|
|
424
|
+
items: { type: 'number' },
|
|
425
|
+
description: 'Array of organizer IDs to link this listing to (must belong to the same directory; use list_organizers to find them)',
|
|
426
|
+
},
|
|
312
427
|
is_active: { type: 'boolean', description: 'Active status (default: true)' },
|
|
313
428
|
is_featured: { type: 'boolean', description: 'Featured status' },
|
|
314
429
|
custom_fields: {
|
|
@@ -329,7 +444,7 @@ export const createListing = {
|
|
|
329
444
|
|
|
330
445
|
export const updateListing = {
|
|
331
446
|
name: 'update_listing',
|
|
332
|
-
description:
|
|
447
|
+
description: "Update an existing listing. Only pass fields you want to change. Pass organizers to replace the listing's linked organizers (omit it to leave them untouched).",
|
|
333
448
|
inputSchema: {
|
|
334
449
|
type: 'object',
|
|
335
450
|
properties: {
|
|
@@ -357,6 +472,11 @@ export const updateListing = {
|
|
|
357
472
|
items: { type: 'number' },
|
|
358
473
|
description: 'Array of tag IDs',
|
|
359
474
|
},
|
|
475
|
+
organizers: {
|
|
476
|
+
type: 'array',
|
|
477
|
+
items: { type: 'number' },
|
|
478
|
+
description: 'Array of organizer IDs to link this listing to. Replaces the current set; pass [] to unlink all. Out-of-directory IDs are ignored.',
|
|
479
|
+
},
|
|
360
480
|
is_active: { type: 'boolean', description: 'Active status' },
|
|
361
481
|
is_featured: { type: 'boolean', description: 'Featured status' },
|
|
362
482
|
custom_fields: {
|
|
@@ -436,6 +556,7 @@ export const bulkCreateListings = {
|
|
|
436
556
|
description: { type: 'string' },
|
|
437
557
|
categories: { type: 'array', items: { type: 'number' } },
|
|
438
558
|
tags: { type: 'array', items: { type: 'number' } },
|
|
559
|
+
organizers: { type: 'array', items: { type: 'number' } },
|
|
439
560
|
},
|
|
440
561
|
required: ['name'],
|
|
441
562
|
additionalProperties: true,
|
|
@@ -856,6 +977,10 @@ export const allTools = [
|
|
|
856
977
|
updateTag,
|
|
857
978
|
deleteTag,
|
|
858
979
|
listCustomFields,
|
|
980
|
+
getCustomField,
|
|
981
|
+
createCustomField,
|
|
982
|
+
updateCustomField,
|
|
983
|
+
deleteCustomField,
|
|
859
984
|
listListings,
|
|
860
985
|
getListing,
|
|
861
986
|
createListing,
|