mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 22:31:46 +00:00
feat(mcp): introduce OAuth 2.1 auth and enforce addon gating
OAuth 2.1 authentication for MCP:
- Add OAuth 2.1 authorization server with PKCE support (routes/oauth.ts)
- Add OAuth service for client CRUD, auth-code flow, and token management (services/oauthService.ts)
- Add typed scope definitions and enforcement helpers (mcp/scopes.ts)
- Add OAuth consent UI page (OAuthAuthorizePage.tsx)
- Add client-side scope labels and descriptions (api/oauthScopes.ts)
- Integrate OAuth token auth into MCP handler alongside existing static tokens
- All OAuth endpoints gated on `mcp` addon
Addon gating across MCP tools, resources, and prompts:
- Add typed ADDON_IDS constant (server/src/addons.ts) replacing all string literals
- Gate budget tools and resources (trip-budget, per-person, settlement) on `budget` addon
- Gate packing tools and resources (trip-packing, trip-packing-bags, trip-todos) on `packing` addon
- Gate todos tools on `packing` addon (mirrors web UI Lists tab behavior)
- Expand atlas gate to cover full tool body (bucket-list + country tools no longer leak)
- Expand collab gate to cover full tool body (collab notes no longer leak)
- Gate packing-list and budget-overview MCP prompts on their respective addons
- Gate get_trip_summary sections per addon; blank packing/budget/collab_notes/todos when disabled
- Remove trip-files resource and files field from get_trip_summary
- Replace all isAddonEnabled('literal') calls with ADDON_IDS constants
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,11 +15,15 @@ import {
|
||||
TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
|
||||
export function registerAssignmentTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'places');
|
||||
const W = canWrite(scopes, 'places');
|
||||
|
||||
export function registerAssignmentTools(server: McpServer, userId: number): void {
|
||||
// --- ASSIGNMENTS ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'assign_place_to_day',
|
||||
{
|
||||
description: 'Assign a place to a specific day in a trip.',
|
||||
@@ -42,7 +46,7 @@ export function registerAssignmentTools(server: McpServer, userId: number): void
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'unassign_place',
|
||||
{
|
||||
description: 'Remove a place assignment from a day.',
|
||||
@@ -64,7 +68,7 @@ export function registerAssignmentTools(server: McpServer, userId: number): void
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_assignment_time',
|
||||
{
|
||||
description: 'Set the start and/or end time for a place assignment on a day (e.g. "09:00", "11:30"). Pass null to clear a time.',
|
||||
@@ -91,7 +95,7 @@ export function registerAssignmentTools(server: McpServer, userId: number): void
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'move_assignment',
|
||||
{
|
||||
description: 'Move a place assignment to a different day.',
|
||||
@@ -113,7 +117,7 @@ export function registerAssignmentTools(server: McpServer, userId: number): void
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_assignment_participants',
|
||||
{
|
||||
description: 'Get the list of users participating in a specific place assignment.',
|
||||
@@ -130,7 +134,7 @@ export function registerAssignmentTools(server: McpServer, userId: number): void
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'set_assignment_participants',
|
||||
{
|
||||
description: 'Set the participants for a place assignment (replaces current list).',
|
||||
@@ -152,7 +156,7 @@ export function registerAssignmentTools(server: McpServer, userId: number): void
|
||||
|
||||
// --- REORDER ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'reorder_day_assignments',
|
||||
{
|
||||
description: 'Reorder places within a day by providing the assignment IDs in the desired order.',
|
||||
|
||||
@@ -7,16 +7,23 @@ import {
|
||||
markRegionVisited, unmarkRegionVisited, getCountryPlaces, updateBucketItem,
|
||||
} from '../../services/atlasService';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
import {
|
||||
TOOL_ANNOTATIONS_WRITE, TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
TOOL_ANNOTATIONS_READONLY,
|
||||
demoDenied, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
|
||||
export function registerAtlasTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'places');
|
||||
const W = canWrite(scopes, 'places');
|
||||
|
||||
if (!isAddonEnabled(ADDON_IDS.ATLAS)) return;
|
||||
|
||||
export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
// --- BUCKET LIST ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_bucket_list_item',
|
||||
{
|
||||
description: 'Add a destination to your personal travel bucket list.',
|
||||
@@ -36,7 +43,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_bucket_list_item',
|
||||
{
|
||||
description: 'Remove an item from your travel bucket list.',
|
||||
@@ -55,7 +62,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- ATLAS ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'mark_country_visited',
|
||||
{
|
||||
description: 'Mark a country as visited in your Atlas.',
|
||||
@@ -71,7 +78,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'unmark_country_visited',
|
||||
{
|
||||
description: 'Remove a country from your visited countries in Atlas.',
|
||||
@@ -89,8 +96,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- ATLAS EXPANDED ---
|
||||
|
||||
if (isAddonEnabled('atlas')) {
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_atlas_stats',
|
||||
{
|
||||
description: 'Get atlas statistics — total visited countries, region counts, continent breakdown.',
|
||||
@@ -103,7 +109,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_visited_regions',
|
||||
{
|
||||
description: 'List all manually visited sub-country regions for the current user.',
|
||||
@@ -116,7 +122,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'mark_region_visited',
|
||||
{
|
||||
description: 'Mark a sub-country region as visited.',
|
||||
@@ -135,7 +141,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'unmark_region_visited',
|
||||
{
|
||||
description: 'Remove a region from the visited list.',
|
||||
@@ -151,7 +157,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_country_atlas_places',
|
||||
{
|
||||
description: 'Get places saved in the user\'s atlas for a specific country.',
|
||||
@@ -166,7 +172,7 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_bucket_list_item',
|
||||
{
|
||||
description: 'Update a bucket list item (notes, name, target date, location).',
|
||||
@@ -188,5 +194,4 @@ export function registerAtlasTools(server: McpServer, userId: number): void {
|
||||
return ok({ item });
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,17 @@ import {
|
||||
TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canWrite } from '../scopes';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
|
||||
export function registerBudgetTools(server: McpServer, userId: number): void {
|
||||
export function registerBudgetTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const W = canWrite(scopes, 'budget');
|
||||
|
||||
if (isAddonEnabled(ADDON_IDS.BUDGET)) {
|
||||
// --- BUDGET ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_budget_item',
|
||||
{
|
||||
description: 'Add a budget/expense item to a trip.',
|
||||
@@ -38,7 +44,7 @@ export function registerBudgetTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_budget_item',
|
||||
{
|
||||
description: 'Delete a budget item from a trip.',
|
||||
@@ -60,7 +66,7 @@ export function registerBudgetTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- BUDGET (update) ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_budget_item',
|
||||
{
|
||||
description: 'Update an existing budget/expense item in a trip.',
|
||||
@@ -88,7 +94,7 @@ export function registerBudgetTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- BUDGET ADVANCED ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'set_budget_item_members',
|
||||
{
|
||||
description: 'Set which trip members are splitting a budget item (replaces current member list).',
|
||||
@@ -108,7 +114,7 @@ export function registerBudgetTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'toggle_budget_member_paid',
|
||||
{
|
||||
description: 'Mark or unmark a member as having paid their share of a budget item.',
|
||||
@@ -128,4 +134,5 @@ export function registerBudgetTools(server: McpServer, userId: number): void {
|
||||
return ok({ member });
|
||||
}
|
||||
);
|
||||
} // isAddonEnabled(BUDGET)
|
||||
}
|
||||
|
||||
@@ -8,16 +8,23 @@ import {
|
||||
listMessages, createMessage, deleteMessage, addOrRemoveReaction,
|
||||
} from '../../services/collabService';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
import {
|
||||
safeBroadcast, TOOL_ANNOTATIONS_WRITE, TOOL_ANNOTATIONS_DELETE,
|
||||
TOOL_ANNOTATIONS_NON_IDEMPOTENT, TOOL_ANNOTATIONS_READONLY,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
|
||||
export function registerCollabTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'collab');
|
||||
const W = canWrite(scopes, 'collab');
|
||||
|
||||
if (!isAddonEnabled(ADDON_IDS.COLLAB)) return;
|
||||
|
||||
export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
// --- COLLAB NOTES ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_collab_note',
|
||||
{
|
||||
description: 'Create a shared collaborative note on a trip (visible to all trip members in the Collab tab).',
|
||||
@@ -40,7 +47,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_collab_note',
|
||||
{
|
||||
description: 'Edit an existing collaborative note on a trip.',
|
||||
@@ -65,7 +72,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_collab_note',
|
||||
{
|
||||
description: 'Delete a collaborative note from a trip.',
|
||||
@@ -87,9 +94,8 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- COLLAB POLLS & CHAT ---
|
||||
|
||||
if (isAddonEnabled('collab')) {
|
||||
server.registerTool(
|
||||
'list_collab_polls',
|
||||
if (R) server.registerTool(
|
||||
'list_collab_polls',
|
||||
{
|
||||
description: 'List all polls for a trip.',
|
||||
inputSchema: {
|
||||
@@ -104,7 +110,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_collab_poll',
|
||||
{
|
||||
description: 'Create a new poll in the collab panel.',
|
||||
@@ -126,7 +132,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'vote_collab_poll',
|
||||
{
|
||||
description: 'Vote on a poll option (or remove vote if already voted for that option).',
|
||||
@@ -146,7 +152,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'close_collab_poll',
|
||||
{
|
||||
description: 'Close a poll so no more votes can be cast.',
|
||||
@@ -166,7 +172,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_collab_poll',
|
||||
{
|
||||
description: 'Delete a poll and all its votes.',
|
||||
@@ -186,7 +192,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_collab_messages',
|
||||
{
|
||||
description: 'List chat messages for a trip (most recent 100, oldest-first).',
|
||||
@@ -203,7 +209,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'send_collab_message',
|
||||
{
|
||||
description: "Send a chat message to a trip's collab channel.",
|
||||
@@ -224,7 +230,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_collab_message',
|
||||
{
|
||||
description: 'Delete a chat message (only the message owner can delete their own messages).',
|
||||
@@ -244,7 +250,7 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'react_collab_message',
|
||||
{
|
||||
description: 'Toggle a reaction emoji on a chat message (adds if not present, removes if already reacted).',
|
||||
@@ -264,5 +270,4 @@ export function registerCollabTools(server: McpServer, userId: number): void {
|
||||
return ok({ reactions: result.reactions });
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,11 @@ import {
|
||||
TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canWrite } from '../scopes';
|
||||
|
||||
export function registerDayTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
if (!canWrite(scopes, 'trips')) return;
|
||||
|
||||
export function registerDayTools(server: McpServer, userId: number): void {
|
||||
// --- DAYS ---
|
||||
|
||||
server.registerTool(
|
||||
|
||||
@@ -6,8 +6,11 @@ import {
|
||||
TOOL_ANNOTATIONS_READONLY,
|
||||
ok,
|
||||
} from './_shared';
|
||||
import { canRead } from '../scopes';
|
||||
|
||||
export function registerMapsWeatherTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
if (!canRead(scopes, 'media')) return;
|
||||
|
||||
export function registerMapsWeatherTools(server: McpServer, userId: number): void {
|
||||
// --- MAPS EXTRAS ---
|
||||
|
||||
server.registerTool(
|
||||
|
||||
@@ -11,11 +11,15 @@ import {
|
||||
TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
|
||||
export function registerNotificationTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'notifications');
|
||||
const W = canWrite(scopes, 'notifications');
|
||||
|
||||
export function registerNotificationTools(server: McpServer, userId: number): void {
|
||||
// --- NOTIFICATIONS ---
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_notifications',
|
||||
{
|
||||
description: 'List in-app notifications for the current user.',
|
||||
@@ -32,7 +36,7 @@ export function registerNotificationTools(server: McpServer, userId: number): vo
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_unread_notification_count',
|
||||
{
|
||||
description: 'Get the number of unread in-app notifications.',
|
||||
@@ -45,7 +49,7 @@ export function registerNotificationTools(server: McpServer, userId: number): vo
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'mark_notification_read',
|
||||
{
|
||||
description: 'Mark a single notification as read.',
|
||||
@@ -62,7 +66,7 @@ export function registerNotificationTools(server: McpServer, userId: number): vo
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'mark_notification_unread',
|
||||
{
|
||||
description: 'Mark a single notification as unread.',
|
||||
@@ -79,7 +83,7 @@ export function registerNotificationTools(server: McpServer, userId: number): vo
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'mark_all_notifications_read',
|
||||
{
|
||||
description: "Mark all of the current user's notifications as read.",
|
||||
|
||||
@@ -16,11 +16,19 @@ import {
|
||||
TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
|
||||
export function registerPackingTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'packing');
|
||||
const W = canWrite(scopes, 'packing');
|
||||
|
||||
if (!isAddonEnabled(ADDON_IDS.PACKING)) return;
|
||||
|
||||
export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
// --- PACKING ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_packing_item',
|
||||
{
|
||||
description: 'Add an item to the packing checklist for a trip.',
|
||||
@@ -40,7 +48,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'toggle_packing_item',
|
||||
{
|
||||
description: 'Check or uncheck a packing item.',
|
||||
@@ -61,7 +69,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_packing_item',
|
||||
{
|
||||
description: 'Remove an item from the packing checklist.',
|
||||
@@ -83,7 +91,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- PACKING (update) ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_packing_item',
|
||||
{
|
||||
description: 'Rename a packing item or change its category.',
|
||||
@@ -108,7 +116,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- PACKING ADVANCED ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'reorder_packing_items',
|
||||
{
|
||||
description: 'Set the display order of packing items within a trip.',
|
||||
@@ -127,7 +135,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_packing_bags',
|
||||
{
|
||||
description: 'List all packing bags for a trip.',
|
||||
@@ -143,7 +151,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_packing_bag',
|
||||
{
|
||||
description: 'Create a new packing bag (e.g. "Carry-on", "Checked bag").',
|
||||
@@ -163,7 +171,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_packing_bag',
|
||||
{
|
||||
description: 'Rename or recolor a packing bag.',
|
||||
@@ -188,7 +196,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_packing_bag',
|
||||
{
|
||||
description: 'Delete a packing bag (items in the bag are unassigned, not deleted).',
|
||||
@@ -207,7 +215,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'set_bag_members',
|
||||
{
|
||||
description: 'Assign trip members to a packing bag (determines who packs what bag).',
|
||||
@@ -227,7 +235,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_packing_category_assignees',
|
||||
{
|
||||
description: 'Get which trip members are assigned to each packing category.',
|
||||
@@ -243,7 +251,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'set_packing_category_assignees',
|
||||
{
|
||||
description: 'Assign trip members to a packing category.',
|
||||
@@ -263,7 +271,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'apply_packing_template',
|
||||
{
|
||||
description: 'Apply a packing template to a trip (adds items from the template).',
|
||||
@@ -283,7 +291,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'save_packing_template',
|
||||
{
|
||||
description: 'Save the current packing list as a reusable template.',
|
||||
@@ -301,7 +309,7 @@ export function registerPackingTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'bulk_import_packing',
|
||||
{
|
||||
description: 'Import multiple packing items at once from a list.',
|
||||
|
||||
@@ -10,11 +10,15 @@ import {
|
||||
TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
|
||||
export function registerPlaceTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'places');
|
||||
const W = canWrite(scopes, 'places');
|
||||
|
||||
export function registerPlaceTools(server: McpServer, userId: number): void {
|
||||
// --- PLACES ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_place',
|
||||
{
|
||||
description: 'Add a new place/POI to a trip. Set google_place_id or osm_id (from search_place) so the app can show opening hours and ratings.',
|
||||
@@ -43,7 +47,7 @@ export function registerPlaceTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_place',
|
||||
{
|
||||
description: 'Update an existing place in a trip.',
|
||||
@@ -80,7 +84,7 @@ export function registerPlaceTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_place',
|
||||
{
|
||||
description: 'Delete a place from a trip.',
|
||||
@@ -100,7 +104,7 @@ export function registerPlaceTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_places',
|
||||
{
|
||||
description: 'List all places/POIs in a trip, optionally filtered by assignment status. Use assignment=unassigned to find orphan activities not yet scheduled on any day.',
|
||||
@@ -122,7 +126,7 @@ export function registerPlaceTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- CATEGORIES ---
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_categories',
|
||||
{
|
||||
description: 'List all available place categories with their id, name, icon and color. Use category_id when creating or updating places.',
|
||||
@@ -137,7 +141,7 @@ export function registerPlaceTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- SEARCH ---
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'search_place',
|
||||
{
|
||||
description: 'Search for a real-world place by name or address. Returns results with osm_id (and google_place_id if configured). Use these IDs when calling create_place so the app can display opening hours and ratings.',
|
||||
|
||||
@@ -3,8 +3,30 @@ import { z } from 'zod';
|
||||
import { canAccessTrip } from '../../db/database';
|
||||
import { getTripSummary } from '../../services/tripService';
|
||||
import { listItems as listPackingItems } from '../../services/packingService';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
|
||||
export function registerMcpPrompts(server: McpServer, _userId: number): void {
|
||||
export function registerMcpPrompts(server: McpServer, _userId: number, isStaticToken = false): void {
|
||||
if (isStaticToken) {
|
||||
server.registerPrompt(
|
||||
'token_auth_notice',
|
||||
{
|
||||
title: 'Static Token Auth Notice',
|
||||
description: 'Notification that this session uses a static API token which will be deprecated',
|
||||
argsSchema: {},
|
||||
},
|
||||
async () => ({
|
||||
description: 'Static token deprecation notice',
|
||||
messages: [{
|
||||
role: 'user' as const,
|
||||
content: {
|
||||
type: 'text' as const,
|
||||
text: '⚠️ This MCP connection is authenticated with a static API token (trek_…). Static token authentication will be deprecated in a future version of TREK. Please inform the user that they should migrate to OAuth 2.1 by going to Settings → Integrations → MCP → OAuth Clients in TREK and registering an OAuth 2.1 application for their MCP client.',
|
||||
},
|
||||
}],
|
||||
})
|
||||
);
|
||||
}
|
||||
const userId = _userId;
|
||||
|
||||
server.registerPrompt(
|
||||
@@ -43,7 +65,7 @@ ${days?.map((d: any, i: number) => `Day ${i + 1} (${d.date}): ${d.assignments?.l
|
||||
}
|
||||
);
|
||||
|
||||
server.registerPrompt(
|
||||
if (isAddonEnabled(ADDON_IDS.PACKING)) server.registerPrompt(
|
||||
'packing-list',
|
||||
{
|
||||
title: 'Packing List',
|
||||
@@ -77,7 +99,7 @@ ${days?.map((d: any, i: number) => `Day ${i + 1} (${d.date}): ${d.assignments?.l
|
||||
}
|
||||
);
|
||||
|
||||
server.registerPrompt(
|
||||
if (isAddonEnabled(ADDON_IDS.BUDGET)) server.registerPrompt(
|
||||
'budget-overview',
|
||||
{
|
||||
title: 'Budget Overview',
|
||||
|
||||
@@ -13,8 +13,11 @@ import {
|
||||
TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canWrite } from '../scopes';
|
||||
|
||||
export function registerReservationTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
if (!canWrite(scopes, 'reservations')) return;
|
||||
|
||||
export function registerReservationTools(server: McpServer, userId: number): void {
|
||||
|
||||
server.registerTool(
|
||||
'create_reservation',
|
||||
|
||||
@@ -7,11 +7,15 @@ import {
|
||||
TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
|
||||
export function registerTagTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'places');
|
||||
const W = canWrite(scopes, 'places');
|
||||
|
||||
export function registerTagTools(server: McpServer, userId: number): void {
|
||||
// --- TAGS ---
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_tags',
|
||||
{
|
||||
description: 'List all tags belonging to the current user.',
|
||||
@@ -24,7 +28,7 @@ export function registerTagTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_tag',
|
||||
{
|
||||
description: 'Create a new tag (user-scoped label for places).',
|
||||
@@ -41,7 +45,7 @@ export function registerTagTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_tag',
|
||||
{
|
||||
description: 'Update the name or color of an existing tag.',
|
||||
@@ -60,7 +64,7 @@ export function registerTagTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_tag',
|
||||
{
|
||||
description: 'Delete a tag (removes it from all places it was attached to).',
|
||||
|
||||
@@ -12,11 +12,19 @@ import {
|
||||
TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
|
||||
export function registerTodoTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'collab');
|
||||
const W = canWrite(scopes, 'collab');
|
||||
|
||||
if (!isAddonEnabled(ADDON_IDS.PACKING)) return;
|
||||
|
||||
export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
// --- TODOS ---
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_todos',
|
||||
{
|
||||
description: 'List all to-do items for a trip, ordered by position.',
|
||||
@@ -32,7 +40,7 @@ export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_todo',
|
||||
{
|
||||
description: 'Create a new to-do item for a trip.',
|
||||
@@ -56,7 +64,7 @@ export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_todo',
|
||||
{
|
||||
description: 'Update an existing to-do item. Only provided fields are changed; omitted fields stay as-is. Pass null to clear a nullable field.',
|
||||
@@ -88,7 +96,7 @@ export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'toggle_todo',
|
||||
{
|
||||
description: 'Mark a to-do item as checked (done) or unchecked.',
|
||||
@@ -109,7 +117,7 @@ export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_todo',
|
||||
{
|
||||
description: 'Delete a to-do item.',
|
||||
@@ -129,7 +137,7 @@ export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'reorder_todos',
|
||||
{
|
||||
description: 'Reorder to-do items within a trip by providing a new ordered list of item IDs.',
|
||||
@@ -147,7 +155,7 @@ export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_todo_category_assignees',
|
||||
{
|
||||
description: 'Get the default assignees configured per to-do category for a trip.',
|
||||
@@ -163,7 +171,7 @@ export function registerTodoTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'set_todo_category_assignees',
|
||||
{
|
||||
description: 'Set the default assignees for a to-do category on a trip. Pass an empty array to clear.',
|
||||
|
||||
@@ -13,22 +13,27 @@ import {
|
||||
createOrUpdateShareLink, getShareLink, deleteShareLink,
|
||||
} from '../../services/shareService';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
import { countMessages, listPolls } from '../../services/collabService';
|
||||
import {
|
||||
listItems as listTodoItems,
|
||||
} from '../../services/todoService';
|
||||
import { listFiles } from '../../services/fileService';
|
||||
import {
|
||||
safeBroadcast, MAX_MCP_TRIP_DAYS,
|
||||
TOOL_ANNOTATIONS_READONLY, TOOL_ANNOTATIONS_WRITE,
|
||||
TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, noAccess, ok,
|
||||
} from './_shared';
|
||||
import { canReadTrips, canWrite, canDeleteTrips } from '../scopes';
|
||||
|
||||
export function registerTripTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canReadTrips(scopes);
|
||||
const W = canWrite(scopes, 'trips');
|
||||
const D = canDeleteTrips(scopes);
|
||||
|
||||
export function registerTripTools(server: McpServer, userId: number): void {
|
||||
// --- TRIPS ---
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_trip',
|
||||
{
|
||||
description: 'Create a new trip. Returns the created trip with its generated days.',
|
||||
@@ -61,7 +66,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_trip',
|
||||
{
|
||||
description: 'Update an existing trip\'s details.',
|
||||
@@ -94,7 +99,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (D) server.registerTool(
|
||||
'delete_trip',
|
||||
{
|
||||
description: 'Delete a trip. Only the trip owner can delete it.',
|
||||
@@ -111,7 +116,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_trips',
|
||||
{
|
||||
description: 'List all trips the current user owns or is a member of. Use this for trip discovery before calling get_trip_summary.',
|
||||
@@ -128,10 +133,10 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
|
||||
// --- TRIP SUMMARY ---
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_trip_summary',
|
||||
{
|
||||
description: 'Get a full denormalized summary of a trip in a single call: metadata, members, days with assignments and notes, accommodations, full budget line items with totals, full packing list with checked status, reservations, collab notes, to-do items, files, and collab poll/message counts. Use this as a context loader before planning or modifying a trip.',
|
||||
description: 'Get a full denormalized summary of a trip in a single call: metadata, members, days with assignments and notes, accommodations, budget line items (when enabled), packing list (when enabled), reservations, collab notes and poll/message counts (when enabled), and to-do items (when enabled). Use this as a context loader before planning or modifying a trip.',
|
||||
inputSchema: {
|
||||
tripId: z.number().int().positive(),
|
||||
},
|
||||
@@ -141,31 +146,31 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
if (!canAccessTrip(tripId, userId)) return noAccess();
|
||||
const summary = getTripSummary(tripId);
|
||||
if (!summary) return noAccess();
|
||||
const todos = listTodoItems(tripId);
|
||||
const files = listFiles(tripId, false).map((f: any) => ({
|
||||
id: f.id,
|
||||
original_name: f.original_name,
|
||||
mime_type: f.mime_type,
|
||||
file_size: f.file_size,
|
||||
starred: !!f.starred,
|
||||
deleted: !!f.deleted_at,
|
||||
created_at: f.created_at,
|
||||
}));
|
||||
const packingEnabled = isAddonEnabled(ADDON_IDS.PACKING);
|
||||
const budgetEnabled = isAddonEnabled(ADDON_IDS.BUDGET);
|
||||
const collabEnabled = isAddonEnabled(ADDON_IDS.COLLAB);
|
||||
const todos = packingEnabled ? listTodoItems(tripId) : [];
|
||||
let pollCount = 0;
|
||||
if (isAddonEnabled('collab')) {
|
||||
pollCount = listPolls(tripId).length;
|
||||
}
|
||||
let messageCount = 0;
|
||||
if (isAddonEnabled('collab')) {
|
||||
if (collabEnabled) {
|
||||
pollCount = listPolls(tripId).length;
|
||||
messageCount = countMessages(tripId);
|
||||
}
|
||||
return ok({ ...summary, todos, files, pollCount, messageCount });
|
||||
return ok({
|
||||
...summary,
|
||||
packing: packingEnabled ? summary.packing : undefined,
|
||||
budget: budgetEnabled ? summary.budget : undefined,
|
||||
collab_notes: collabEnabled ? summary.collab_notes : [],
|
||||
todos,
|
||||
pollCount,
|
||||
messageCount,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// --- TRIP MEMBERS, COPY, ICS, SHARE ---
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_trip_members',
|
||||
{
|
||||
description: 'List all members of a trip (owner + collaborators).',
|
||||
@@ -183,7 +188,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'add_trip_member',
|
||||
{
|
||||
description: 'Add a user to a trip by their username or email address. Only the trip owner can do this.',
|
||||
@@ -210,7 +215,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'remove_trip_member',
|
||||
{
|
||||
description: 'Remove a member from a trip. Only the trip owner can do this.',
|
||||
@@ -232,7 +237,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'copy_trip',
|
||||
{
|
||||
description: 'Duplicate a trip (all days, places, itinerary, packing, budget, reservations, day notes). Packing items are reset to unchecked. Returns the new trip.',
|
||||
@@ -255,7 +260,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'export_trip_ics',
|
||||
{
|
||||
description: 'Export a trip\'s itinerary and reservations as iCalendar (.ics) format text. Useful for importing into calendar apps.',
|
||||
@@ -275,7 +280,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_share_link',
|
||||
{
|
||||
description: 'Get the current public share link for a trip, including its permission flags. Returns null if no share link exists.',
|
||||
@@ -291,7 +296,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'create_share_link',
|
||||
{
|
||||
description: 'Create or update the public share link for a trip. Set permission flags to control what is visible to guests.',
|
||||
@@ -319,7 +324,7 @@ export function registerTripTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_share_link',
|
||||
{
|
||||
description: 'Revoke the public share link for a trip. Guests will no longer be able to access the shared view.',
|
||||
|
||||
@@ -13,15 +13,20 @@ import {
|
||||
getCountries as getHolidayCountries, getHolidays,
|
||||
} from '../../services/vacayService';
|
||||
import { isAddonEnabled } from '../../services/adminService';
|
||||
import { ADDON_IDS } from '../../addons';
|
||||
import {
|
||||
TOOL_ANNOTATIONS_READONLY, TOOL_ANNOTATIONS_WRITE,
|
||||
TOOL_ANNOTATIONS_DELETE, TOOL_ANNOTATIONS_NON_IDEMPOTENT,
|
||||
demoDenied, ok,
|
||||
} from './_shared';
|
||||
import { canRead, canWrite } from '../scopes';
|
||||
|
||||
export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
if (isAddonEnabled('vacay')) {
|
||||
server.registerTool(
|
||||
export function registerVacayTools(server: McpServer, userId: number, scopes: string[] | null): void {
|
||||
const R = canRead(scopes, 'vacay');
|
||||
const W = canWrite(scopes, 'vacay');
|
||||
|
||||
if (isAddonEnabled(ADDON_IDS.VACAY)) {
|
||||
if (R) server.registerTool(
|
||||
'get_vacay_plan',
|
||||
{
|
||||
description: "Get the current user's active vacation plan (own or joined).",
|
||||
@@ -34,7 +39,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_vacay_plan',
|
||||
{
|
||||
description: 'Update vacation plan settings (weekends blocking, holidays, carry-over).',
|
||||
@@ -55,7 +60,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'set_vacay_color',
|
||||
{
|
||||
description: "Set the current user's color in the vacation plan calendar.",
|
||||
@@ -72,7 +77,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_available_vacay_users',
|
||||
{
|
||||
description: 'List users who can be invited to the current vacation plan.',
|
||||
@@ -86,7 +91,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'send_vacay_invite',
|
||||
{
|
||||
description: 'Invite a user to join the vacation plan by their user ID.',
|
||||
@@ -106,7 +111,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'accept_vacay_invite',
|
||||
{
|
||||
description: 'Accept a pending invitation to join another user\'s vacation plan.',
|
||||
@@ -123,7 +128,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'decline_vacay_invite',
|
||||
{
|
||||
description: 'Decline a pending vacation plan invitation.',
|
||||
@@ -138,7 +143,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'cancel_vacay_invite',
|
||||
{
|
||||
description: 'Cancel an outgoing invitation (owner cancels invite they sent).',
|
||||
@@ -155,7 +160,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'dissolve_vacay_plan',
|
||||
{
|
||||
description: 'Dissolve the shared plan — all members are removed and everyone returns to their own individual plan.',
|
||||
@@ -169,7 +174,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_vacay_years',
|
||||
{
|
||||
description: 'List calendar years tracked in the current vacation plan.',
|
||||
@@ -183,7 +188,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'add_vacay_year',
|
||||
{
|
||||
description: 'Add a calendar year to the vacation plan.',
|
||||
@@ -200,7 +205,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_vacay_year',
|
||||
{
|
||||
description: 'Remove a calendar year from the vacation plan.',
|
||||
@@ -217,7 +222,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_vacay_entries',
|
||||
{
|
||||
description: 'Get all vacation day entries for a plan and year.',
|
||||
@@ -233,7 +238,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'toggle_vacay_entry',
|
||||
{
|
||||
description: 'Toggle a day on or off as a vacation day for the current user.',
|
||||
@@ -250,7 +255,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'toggle_company_holiday',
|
||||
{
|
||||
description: 'Toggle a date as a company holiday for the whole plan.',
|
||||
@@ -268,7 +273,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'get_vacay_stats',
|
||||
{
|
||||
description: 'Get vacation statistics for a specific year (days used, remaining, carried over).',
|
||||
@@ -284,7 +289,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_vacay_stats',
|
||||
{
|
||||
description: 'Update the vacation day allowance for a specific user and year.',
|
||||
@@ -302,7 +307,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'add_holiday_calendar',
|
||||
{
|
||||
description: 'Add a public holiday calendar (by region code) to the vacation plan.',
|
||||
@@ -322,7 +327,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'update_holiday_calendar',
|
||||
{
|
||||
description: 'Update label or color for a holiday calendar.',
|
||||
@@ -342,7 +347,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (W) server.registerTool(
|
||||
'delete_holiday_calendar',
|
||||
{
|
||||
description: 'Remove a holiday calendar from the vacation plan.',
|
||||
@@ -359,7 +364,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_holiday_countries',
|
||||
{
|
||||
description: 'List countries available for public holiday calendars.',
|
||||
@@ -373,7 +378,7 @@ export function registerVacayTools(server: McpServer, userId: number): void {
|
||||
}
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
if (R) server.registerTool(
|
||||
'list_holidays',
|
||||
{
|
||||
description: 'List public holidays for a country and year.',
|
||||
|
||||
Reference in New Issue
Block a user