diff --git a/client/src/api/oauthScopes.ts b/client/src/api/oauthScopes.ts index d11bf853e..3f266e519 100644 --- a/client/src/api/oauthScopes.ts +++ b/client/src/api/oauthScopes.ts @@ -43,6 +43,11 @@ export const SCOPE_GROUPS: Record = { 'journey:read': { labelKey: 'oauth.scope.journey:read.label', descriptionKey: 'oauth.scope.journey:read.description', groupKey: 'oauth.scope.group.journey' }, 'journey:write': { labelKey: 'oauth.scope.journey:write.label', descriptionKey: 'oauth.scope.journey:write.description', groupKey: 'oauth.scope.group.journey' }, 'journey:share': { labelKey: 'oauth.scope.journey:share.label', descriptionKey: 'oauth.scope.journey:share.description', groupKey: 'oauth.scope.group.journey' }, + 'files:read': { labelKey: 'oauth.scope.files:read.label', descriptionKey: 'oauth.scope.files:read.description', groupKey: 'oauth.scope.group.files' }, + 'files:write': { labelKey: 'oauth.scope.files:write.label', descriptionKey: 'oauth.scope.files:write.description', groupKey: 'oauth.scope.group.files' }, + 'files:content': { labelKey: 'oauth.scope.files:content.label', descriptionKey: 'oauth.scope.files:content.description', groupKey: 'oauth.scope.group.files' }, + 'settings:read': { labelKey: 'oauth.scope.settings:read.label', descriptionKey: 'oauth.scope.settings:read.description', groupKey: 'oauth.scope.group.settings' }, + 'settings:write': { labelKey: 'oauth.scope.settings:write.label', descriptionKey: 'oauth.scope.settings:write.description', groupKey: 'oauth.scope.group.settings' }, } export const ALL_SCOPES = Object.keys(SCOPE_GROUPS) diff --git a/server/src/mcp/scopes.ts b/server/src/mcp/scopes.ts index 2ef5062a7..760021e28 100644 --- a/server/src/mcp/scopes.ts +++ b/server/src/mcp/scopes.ts @@ -32,6 +32,16 @@ export const SCOPES = { JOURNEY_READ: 'journey:read', JOURNEY_WRITE: 'journey:write', JOURNEY_SHARE: 'journey:share', + FILES_READ: 'files:read', + FILES_WRITE: 'files:write', + // A third mode rather than a second group: listing what a trip carries and + // reading the bytes of a booking PDF are different privileges, and the plugin + // host already draws that line (db:read:files vs db:read:files:content). Not + // implied by files:write, the way journey:share is not implied by + // journey:write. The policy's fallback branch covers both. + FILES_CONTENT: 'files:content', + SETTINGS_READ: 'settings:read', + SETTINGS_WRITE: 'settings:write', } as const; export type Scope = typeof SCOPES[keyof typeof SCOPES]; @@ -77,6 +87,11 @@ export const SCOPE_INFO: Record = { 'journey:read': { label: 'View journeys', description: 'Read journeys, entries, and contributor list', group: 'Journey' }, 'journey:write': { label: 'Manage journeys', description: 'Create, update, and delete journeys and their entries', group: 'Journey' }, 'journey:share': { label: 'Manage journey links', description: 'Create, update, and revoke public share links for journeys', group: 'Journey' }, + 'files:read': { label: 'View trip files', description: 'List the documents on a trip: names, sizes, who uploaded them, what they link to', group: 'Files' }, + 'files:write': { label: 'Organise trip files', description: 'Rename and describe files, link them to bookings and places, star and trash them', group: 'Files' }, + 'files:content': { label: 'Read file contents', description: 'Read what is inside an uploaded document, such as a booking PDF or a ticket', group: 'Files' }, + 'settings:read': { label: 'View your preferences', description: 'Read units, time format, language, default currency, and start page', group: 'Settings' }, + 'settings:write': { label: 'Change your preferences', description: 'Change units, time format, language, default currency, and start page. Never stored API keys', group: 'Settings' }, }; // --------------------------------------------------------------------------- @@ -114,6 +129,15 @@ export function canShareTrips(scopes: string[] | null): boolean { return scopes.includes('trips:share'); } +/** + * files:content is a separate scope from files:read: a token may list a trip's + * documents without being allowed to read what is inside them. + */ +export function canReadFileContent(scopes: string[] | null): boolean { + if (!scopes) return true; + return scopes.includes('files:content'); +} + /** journey:share is a separate scope for managing public share links for journeys */ export function canShareJourneys(scopes: string[] | null): boolean { if (!scopes) return true; diff --git a/server/tests/unit/mcp/scopes.test.ts b/server/tests/unit/mcp/scopes.test.ts index 15a310eb1..f922f641d 100644 --- a/server/tests/unit/mcp/scopes.test.ts +++ b/server/tests/unit/mcp/scopes.test.ts @@ -46,7 +46,7 @@ describe('ALL_SCOPES', () => { expect(ALL_SCOPES.length).toBeGreaterThan(0); }); - it('derives exactly the 14 known scope groups (ScopeGroup lockstep)', () => { + it('derives exactly the 16 known scope groups (ScopeGroup lockstep)', () => { // The runtime half of the ScopeGroup lockstep — the type half is // MCP_ACCESS_GROUPS_MATCH_SCOPE_GROUPS in src/mcp/nest-mcp-policy.ts, // covered by `npm run typecheck`. If this list changes, the MCP @@ -57,12 +57,14 @@ describe('ALL_SCOPES', () => { 'budget', 'collab', 'collections', + 'files', 'geo', 'journey', 'notifications', 'packing', 'places', 'reservations', + 'settings', 'todos', 'trips', 'vacay', diff --git a/shared/src/i18n/ar/oauth.ts b/shared/src/i18n/ar/oauth.ts index d097cc7f8..54036bfdc 100644 --- a/shared/src/i18n/ar/oauth.ts +++ b/shared/src/i18n/ar/oauth.ts @@ -93,5 +93,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'الملفات', + 'oauth.scope.group.settings': 'الإعدادات', + 'oauth.scope.files:read.label': 'عرض ملفات الرحلة', + 'oauth.scope.files:read.description': 'سرد مستندات الرحلة: الأسماء والأحجام ومن رفعها وبماذا ترتبط', + 'oauth.scope.files:write.label': 'إدارة ملفات الرحلة', + 'oauth.scope.files:write.description': 'إعادة تسمية الملفات ووصفها وربطها بالحجوزات والأماكن وتمييزها ونقلها إلى سلة المهملات', + 'oauth.scope.files:content.label': 'قراءة محتوى الملفات', + 'oauth.scope.files:content.description': 'قراءة محتوى مستند مرفوع، مثل ملف PDF لحجز أو تذكرة', + 'oauth.scope.settings:read.label': 'عرض تفضيلاتك', + 'oauth.scope.settings:read.description': 'قراءة الوحدات وتنسيق الوقت واللغة والعملة الافتراضية وصفحة البداية', + 'oauth.scope.settings:write.label': 'تغيير تفضيلاتك', + 'oauth.scope.settings:write.description': 'تغيير الوحدات وتنسيق الوقت واللغة والعملة الافتراضية وصفحة البداية. لا مفاتيح API المخزنة أبدًا', }; export default oauth; diff --git a/shared/src/i18n/br/oauth.ts b/shared/src/i18n/br/oauth.ts index 7a8456907..f67f140b5 100644 --- a/shared/src/i18n/br/oauth.ts +++ b/shared/src/i18n/br/oauth.ts @@ -95,5 +95,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Arquivos', + 'oauth.scope.group.settings': 'Configurações', + 'oauth.scope.files:read.label': 'Ver arquivos da viagem', + 'oauth.scope.files:read.description': 'Listar os documentos de uma viagem: nomes, tamanhos, quem enviou e a que estão vinculados', + 'oauth.scope.files:write.label': 'Gerenciar arquivos da viagem', + 'oauth.scope.files:write.description': 'Renomear e descrever arquivos, vinculá-los a reservas e lugares, favoritá-los e movê-los para a lixeira', + 'oauth.scope.files:content.label': 'Ler o conteúdo dos arquivos', + 'oauth.scope.files:content.description': 'Ler o conteúdo de um documento enviado, como um PDF de reserva ou um bilhete', + 'oauth.scope.settings:read.label': 'Ver suas preferências', + 'oauth.scope.settings:read.description': 'Ler unidades, formato de hora, idioma, moeda padrão e página inicial', + 'oauth.scope.settings:write.label': 'Alterar suas preferências', + 'oauth.scope.settings:write.description': 'Alterar unidades, formato de hora, idioma, moeda padrão e página inicial. Nunca as chaves de API salvas', }; export default oauth; diff --git a/shared/src/i18n/ca/oauth.ts b/shared/src/i18n/ca/oauth.ts index a434960e4..49228d9a4 100644 --- a/shared/src/i18n/ca/oauth.ts +++ b/shared/src/i18n/ca/oauth.ts @@ -97,5 +97,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysTool.listTrips': 'Llista els teus viatges perquè la IA pugui descobrir els IDs dels viatges', 'oauth.authorize.alwaysTool.getTripSummary': 'Llegeix una visió general del viatge necessària per utilitzar qualsevol altra eina', + 'oauth.scope.group.files': 'Fitxers', + 'oauth.scope.group.settings': 'Configuració', + 'oauth.scope.files:read.label': 'Veure els fitxers del viatge', + 'oauth.scope.files:read.description': 'Llistar els documents d’un viatge: noms, mides, qui els ha pujat i a què estan vinculats', + 'oauth.scope.files:write.label': 'Gestionar els fitxers del viatge', + 'oauth.scope.files:write.description': 'Reanomenar i descriure fitxers, vincular-los a reserves i llocs, destacar-los i enviar-los a la paperera', + 'oauth.scope.files:content.label': 'Llegir el contingut dels fitxers', + 'oauth.scope.files:content.description': 'Llegir el contingut d’un document pujat, com un PDF de reserva o un bitllet', + 'oauth.scope.settings:read.label': 'Veure les teves preferències', + 'oauth.scope.settings:read.description': 'Llegir unitats, format d’hora, idioma, moneda per defecte i pàgina d’inici', + 'oauth.scope.settings:write.label': 'Canviar les teves preferències', + 'oauth.scope.settings:write.description': 'Canviar unitats, format d’hora, idioma, moneda per defecte i pàgina d’inici. Mai les claus API desades', }; export default oauth; diff --git a/shared/src/i18n/cs/oauth.ts b/shared/src/i18n/cs/oauth.ts index 5d456cb45..29914ad9d 100644 --- a/shared/src/i18n/cs/oauth.ts +++ b/shared/src/i18n/cs/oauth.ts @@ -93,5 +93,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Soubory', + 'oauth.scope.group.settings': 'Nastavení', + 'oauth.scope.files:read.label': 'Zobrazit soubory cesty', + 'oauth.scope.files:read.description': 'Vypsat dokumenty cesty: názvy, velikosti, kdo je nahrál a k čemu jsou připojené', + 'oauth.scope.files:write.label': 'Spravovat soubory cesty', + 'oauth.scope.files:write.description': 'Přejmenovat a popsat soubory, připojit je k rezervacím a místům, označit hvězdičkou a přesunout do koše', + 'oauth.scope.files:content.label': 'Číst obsah souborů', + 'oauth.scope.files:content.description': 'Přečíst obsah nahraného dokumentu, například PDF rezervace nebo jízdenku', + 'oauth.scope.settings:read.label': 'Zobrazit vaše předvolby', + 'oauth.scope.settings:read.description': 'Číst jednotky, formát času, jazyk, výchozí měnu a úvodní stránku', + 'oauth.scope.settings:write.label': 'Změnit vaše předvolby', + 'oauth.scope.settings:write.description': 'Změnit jednotky, formát času, jazyk, výchozí měnu a úvodní stránku. Nikdy uložené API klíče', }; export default oauth; diff --git a/shared/src/i18n/de/oauth.ts b/shared/src/i18n/de/oauth.ts index aa875e99d..99beea982 100644 --- a/shared/src/i18n/de/oauth.ts +++ b/shared/src/i18n/de/oauth.ts @@ -97,5 +97,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Dateien', + 'oauth.scope.group.settings': 'Einstellungen', + 'oauth.scope.files:read.label': 'Reisedateien ansehen', + 'oauth.scope.files:read.description': 'Dokumente einer Reise auflisten: Namen, Größen, wer sie hochgeladen hat und woran sie hängen', + 'oauth.scope.files:write.label': 'Reisedateien verwalten', + 'oauth.scope.files:write.description': 'Dateien umbenennen und beschreiben, mit Buchungen und Orten verknüpfen, markieren und in den Papierkorb legen', + 'oauth.scope.files:content.label': 'Dateiinhalte lesen', + 'oauth.scope.files:content.description': 'Den Inhalt eines hochgeladenen Dokuments lesen, etwa ein Buchungs-PDF oder ein Ticket', + 'oauth.scope.settings:read.label': 'Einstellungen ansehen', + 'oauth.scope.settings:read.description': 'Einheiten, Zeitformat, Sprache, Standardwährung und Startseite lesen', + 'oauth.scope.settings:write.label': 'Einstellungen ändern', + 'oauth.scope.settings:write.description': 'Einheiten, Zeitformat, Sprache, Standardwährung und Startseite ändern. Niemals gespeicherte API-Schlüssel', }; export default oauth; diff --git a/shared/src/i18n/en/oauth.ts b/shared/src/i18n/en/oauth.ts index 8271153cb..350598c8f 100644 --- a/shared/src/i18n/en/oauth.ts +++ b/shared/src/i18n/en/oauth.ts @@ -94,5 +94,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', + 'oauth.scope.group.files': 'Files', + 'oauth.scope.group.settings': 'Settings', + 'oauth.scope.files:read.label': 'View trip files', + 'oauth.scope.files:read.description': 'List the documents on a trip: names, sizes, who uploaded them, what they link to', + 'oauth.scope.files:write.label': 'Organise trip files', + 'oauth.scope.files:write.description': 'Rename and describe files, link them to bookings and places, star and trash them', + 'oauth.scope.files:content.label': 'Read file contents', + 'oauth.scope.files:content.description': 'Read what is inside an uploaded document, such as a booking PDF or a ticket', + 'oauth.scope.settings:read.label': 'View your preferences', + 'oauth.scope.settings:read.description': 'Read units, time format, language, default currency, and start page', + 'oauth.scope.settings:write.label': 'Change your preferences', + 'oauth.scope.settings:write.description': 'Change units, time format, language, default currency, and start page. Never stored API keys', }; export default oauth; diff --git a/shared/src/i18n/es/oauth.ts b/shared/src/i18n/es/oauth.ts index 8794a2b2e..8746c3d5b 100644 --- a/shared/src/i18n/es/oauth.ts +++ b/shared/src/i18n/es/oauth.ts @@ -94,5 +94,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Archivos', + 'oauth.scope.group.settings': 'Configuración', + 'oauth.scope.files:read.label': 'Ver archivos del viaje', + 'oauth.scope.files:read.description': 'Listar los documentos de un viaje: nombres, tamaños, quién los subió y a qué están vinculados', + 'oauth.scope.files:write.label': 'Gestionar archivos del viaje', + 'oauth.scope.files:write.description': 'Renombrar y describir archivos, vincularlos a reservas y lugares, destacarlos y enviarlos a la papelera', + 'oauth.scope.files:content.label': 'Leer el contenido de archivos', + 'oauth.scope.files:content.description': 'Leer el contenido de un documento subido, como un PDF de reserva o un billete', + 'oauth.scope.settings:read.label': 'Ver tus preferencias', + 'oauth.scope.settings:read.description': 'Leer unidades, formato de hora, idioma, moneda predeterminada y página de inicio', + 'oauth.scope.settings:write.label': 'Cambiar tus preferencias', + 'oauth.scope.settings:write.description': 'Cambiar unidades, formato de hora, idioma, moneda predeterminada y página de inicio. Nunca las claves API guardadas', }; export default oauth; diff --git a/shared/src/i18n/fr/oauth.ts b/shared/src/i18n/fr/oauth.ts index 645b6f537..5dd222a52 100644 --- a/shared/src/i18n/fr/oauth.ts +++ b/shared/src/i18n/fr/oauth.ts @@ -97,5 +97,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Fichiers', + 'oauth.scope.group.settings': 'Paramètres', + 'oauth.scope.files:read.label': 'Voir les fichiers du voyage', + 'oauth.scope.files:read.description': 'Lister les documents d’un voyage : noms, tailles, qui les a envoyés et ce à quoi ils sont liés', + 'oauth.scope.files:write.label': 'Gérer les fichiers du voyage', + 'oauth.scope.files:write.description': 'Renommer et décrire les fichiers, les lier aux réservations et aux lieux, les épingler et les mettre à la corbeille', + 'oauth.scope.files:content.label': 'Lire le contenu des fichiers', + 'oauth.scope.files:content.description': 'Lire le contenu d’un document envoyé, par exemple un PDF de réservation ou un billet', + 'oauth.scope.settings:read.label': 'Voir vos préférences', + 'oauth.scope.settings:read.description': 'Lire les unités, le format horaire, la langue, la devise par défaut et la page d’accueil', + 'oauth.scope.settings:write.label': 'Modifier vos préférences', + 'oauth.scope.settings:write.description': 'Modifier les unités, le format horaire, la langue, la devise par défaut et la page d’accueil. Jamais les clés API enregistrées', }; export default oauth; diff --git a/shared/src/i18n/gr/oauth.ts b/shared/src/i18n/gr/oauth.ts index 54dbcea48..133ab0b81 100644 --- a/shared/src/i18n/gr/oauth.ts +++ b/shared/src/i18n/gr/oauth.ts @@ -99,5 +99,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Αρχεία', + 'oauth.scope.group.settings': 'Ρυθμίσεις', + 'oauth.scope.files:read.label': 'Προβολή αρχείων ταξιδιού', + 'oauth.scope.files:read.description': 'Λίστα των εγγράφων ενός ταξιδιού: ονόματα, μεγέθη, ποιος τα ανέβασε και με τι συνδέονται', + 'oauth.scope.files:write.label': 'Διαχείριση αρχείων ταξιδιού', + 'oauth.scope.files:write.description': 'Μετονομασία και περιγραφή αρχείων, σύνδεσή τους με κρατήσεις και τοποθεσίες, επισήμανση και διαγραφή', + 'oauth.scope.files:content.label': 'Ανάγνωση περιεχομένου αρχείων', + 'oauth.scope.files:content.description': 'Ανάγνωση του περιεχομένου ενός ανεβασμένου εγγράφου, όπως ένα PDF κράτησης ή ένα εισιτήριο', + 'oauth.scope.settings:read.label': 'Προβολή προτιμήσεων', + 'oauth.scope.settings:read.description': 'Ανάγνωση μονάδων, μορφής ώρας, γλώσσας, προεπιλεγμένου νομίσματος και αρχικής σελίδας', + 'oauth.scope.settings:write.label': 'Αλλαγή προτιμήσεων', + 'oauth.scope.settings:write.description': 'Αλλαγή μονάδων, μορφής ώρας, γλώσσας, προεπιλεγμένου νομίσματος και αρχικής σελίδας. Ποτέ αποθηκευμένων κλειδιών API', }; export default oauth; diff --git a/shared/src/i18n/hu/oauth.ts b/shared/src/i18n/hu/oauth.ts index 1ae2caa30..f16fd6034 100644 --- a/shared/src/i18n/hu/oauth.ts +++ b/shared/src/i18n/hu/oauth.ts @@ -97,5 +97,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Fájlok', + 'oauth.scope.group.settings': 'Beállítások', + 'oauth.scope.files:read.label': 'Az utazás fájljainak megtekintése', + 'oauth.scope.files:read.description': 'Az utazás dokumentumainak listázása: nevek, méretek, ki töltötte fel és mihez kapcsolódnak', + 'oauth.scope.files:write.label': 'Az utazás fájljainak kezelése', + 'oauth.scope.files:write.description': 'Fájlok átnevezése és leírása, foglalásokhoz és helyekhez kapcsolása, megjelölése és kukába helyezése', + 'oauth.scope.files:content.label': 'Fájltartalom olvasása', + 'oauth.scope.files:content.description': 'Feltöltött dokumentum tartalmának olvasása, például egy foglalási PDF vagy jegy', + 'oauth.scope.settings:read.label': 'Beállítások megtekintése', + 'oauth.scope.settings:read.description': 'Mértékegységek, időformátum, nyelv, alapértelmezett pénznem és kezdőoldal olvasása', + 'oauth.scope.settings:write.label': 'Beállítások módosítása', + 'oauth.scope.settings:write.description': 'Mértékegységek, időformátum, nyelv, alapértelmezett pénznem és kezdőoldal módosítása. Soha nem a tárolt API-kulcsok', }; export default oauth; diff --git a/shared/src/i18n/id/oauth.ts b/shared/src/i18n/id/oauth.ts index 0e2918e1b..4b1b2bff4 100644 --- a/shared/src/i18n/id/oauth.ts +++ b/shared/src/i18n/id/oauth.ts @@ -94,5 +94,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Berkas', + 'oauth.scope.group.settings': 'Pengaturan', + 'oauth.scope.files:read.label': 'Lihat berkas perjalanan', + 'oauth.scope.files:read.description': 'Menampilkan dokumen perjalanan: nama, ukuran, siapa yang mengunggah, dan tautannya', + 'oauth.scope.files:write.label': 'Kelola berkas perjalanan', + 'oauth.scope.files:write.description': 'Ganti nama dan deskripsi berkas, tautkan ke pemesanan dan tempat, beri bintang dan buang ke sampah', + 'oauth.scope.files:content.label': 'Baca isi berkas', + 'oauth.scope.files:content.description': 'Membaca isi dokumen yang diunggah, misalnya PDF pemesanan atau tiket', + 'oauth.scope.settings:read.label': 'Lihat preferensi Anda', + 'oauth.scope.settings:read.description': 'Membaca satuan, format waktu, bahasa, mata uang bawaan, dan halaman awal', + 'oauth.scope.settings:write.label': 'Ubah preferensi Anda', + 'oauth.scope.settings:write.description': 'Mengubah satuan, format waktu, bahasa, mata uang bawaan, dan halaman awal. Tidak pernah kunci API tersimpan', }; export default oauth; diff --git a/shared/src/i18n/it/oauth.ts b/shared/src/i18n/it/oauth.ts index 3f730e874..fc743448e 100644 --- a/shared/src/i18n/it/oauth.ts +++ b/shared/src/i18n/it/oauth.ts @@ -95,5 +95,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'File', + 'oauth.scope.group.settings': 'Impostazioni', + 'oauth.scope.files:read.label': 'Vedere i file del viaggio', + 'oauth.scope.files:read.description': 'Elencare i documenti di un viaggio: nomi, dimensioni, chi li ha caricati e a cosa sono collegati', + 'oauth.scope.files:write.label': 'Gestire i file del viaggio', + 'oauth.scope.files:write.description': 'Rinominare e descrivere i file, collegarli a prenotazioni e luoghi, contrassegnarli e cestinarli', + 'oauth.scope.files:content.label': 'Leggere il contenuto dei file', + 'oauth.scope.files:content.description': 'Leggere il contenuto di un documento caricato, come un PDF di prenotazione o un biglietto', + 'oauth.scope.settings:read.label': 'Vedere le tue preferenze', + 'oauth.scope.settings:read.description': 'Leggere unità, formato orario, lingua, valuta predefinita e pagina iniziale', + 'oauth.scope.settings:write.label': 'Modificare le tue preferenze', + 'oauth.scope.settings:write.description': 'Modificare unità, formato orario, lingua, valuta predefinita e pagina iniziale. Mai le chiavi API salvate', }; export default oauth; diff --git a/shared/src/i18n/ja/oauth.ts b/shared/src/i18n/ja/oauth.ts index cf4d8dfca..6fe50bedf 100644 --- a/shared/src/i18n/ja/oauth.ts +++ b/shared/src/i18n/ja/oauth.ts @@ -94,5 +94,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'ファイル', + 'oauth.scope.group.settings': '設定', + 'oauth.scope.files:read.label': '旅行のファイルを表示', + 'oauth.scope.files:read.description': '旅行の書類を一覧表示します。名前、サイズ、アップロードした人、リンク先', + 'oauth.scope.files:write.label': '旅行のファイルを管理', + 'oauth.scope.files:write.description': 'ファイルの名前と説明の変更、予約や場所への紐付け、スターとゴミ箱への移動', + 'oauth.scope.files:content.label': 'ファイルの中身を読む', + 'oauth.scope.files:content.description': 'アップロードされた書類の中身を読みます。予約PDFやチケットなど', + 'oauth.scope.settings:read.label': '環境設定を表示', + 'oauth.scope.settings:read.description': '単位、時刻表示、言語、既定通貨、開始ページの読み取り', + 'oauth.scope.settings:write.label': '環境設定を変更', + 'oauth.scope.settings:write.description': '単位、時刻表示、言語、既定通貨、開始ページの変更。保存されたAPIキーは対象外', }; export default oauth; diff --git a/shared/src/i18n/ko/oauth.ts b/shared/src/i18n/ko/oauth.ts index 356810d38..5fcf3be70 100644 --- a/shared/src/i18n/ko/oauth.ts +++ b/shared/src/i18n/ko/oauth.ts @@ -92,5 +92,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': '파일', + 'oauth.scope.group.settings': '설정', + 'oauth.scope.files:read.label': '여행 파일 보기', + 'oauth.scope.files:read.description': '여행의 문서를 나열합니다. 이름, 크기, 업로드한 사람, 연결된 항목', + 'oauth.scope.files:write.label': '여행 파일 관리', + 'oauth.scope.files:write.description': '파일 이름과 설명 변경, 예약 및 장소에 연결, 즐겨찾기 및 휴지통 이동', + 'oauth.scope.files:content.label': '파일 내용 읽기', + 'oauth.scope.files:content.description': '업로드된 문서의 내용을 읽습니다. 예약 PDF나 티켓 등', + 'oauth.scope.settings:read.label': '환경설정 보기', + 'oauth.scope.settings:read.description': '단위, 시간 형식, 언어, 기본 통화, 시작 페이지 읽기', + 'oauth.scope.settings:write.label': '환경설정 변경', + 'oauth.scope.settings:write.description': '단위, 시간 형식, 언어, 기본 통화, 시작 페이지 변경. 저장된 API 키는 제외', }; export default oauth; diff --git a/shared/src/i18n/nl/oauth.ts b/shared/src/i18n/nl/oauth.ts index 976ef0006..940379624 100644 --- a/shared/src/i18n/nl/oauth.ts +++ b/shared/src/i18n/nl/oauth.ts @@ -96,5 +96,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Bestanden', + 'oauth.scope.group.settings': 'Instellingen', + 'oauth.scope.files:read.label': 'Reisbestanden bekijken', + 'oauth.scope.files:read.description': 'De documenten van een reis tonen: namen, groottes, wie ze heeft geüpload en waaraan ze gekoppeld zijn', + 'oauth.scope.files:write.label': 'Reisbestanden beheren', + 'oauth.scope.files:write.description': 'Bestanden hernoemen en beschrijven, koppelen aan boekingen en plaatsen, markeren en naar de prullenbak verplaatsen', + 'oauth.scope.files:content.label': 'Bestandsinhoud lezen', + 'oauth.scope.files:content.description': 'De inhoud van een geüpload document lezen, zoals een boekings-PDF of een ticket', + 'oauth.scope.settings:read.label': 'Je voorkeuren bekijken', + 'oauth.scope.settings:read.description': 'Eenheden, tijdnotatie, taal, standaardvaluta en startpagina lezen', + 'oauth.scope.settings:write.label': 'Je voorkeuren wijzigen', + 'oauth.scope.settings:write.description': 'Eenheden, tijdnotatie, taal, standaardvaluta en startpagina wijzigen. Nooit opgeslagen API-sleutels', }; export default oauth; diff --git a/shared/src/i18n/pl/oauth.ts b/shared/src/i18n/pl/oauth.ts index 5481512e5..19e20eba3 100644 --- a/shared/src/i18n/pl/oauth.ts +++ b/shared/src/i18n/pl/oauth.ts @@ -95,5 +95,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Pliki', + 'oauth.scope.group.settings': 'Ustawienia', + 'oauth.scope.files:read.label': 'Przeglądanie plików podróży', + 'oauth.scope.files:read.description': 'Wyświetlanie dokumentów podróży: nazw, rozmiarów, kto je przesłał i z czym są powiązane', + 'oauth.scope.files:write.label': 'Zarządzanie plikami podróży', + 'oauth.scope.files:write.description': 'Zmiana nazw i opisów plików, wiązanie ich z rezerwacjami i miejscami, oznaczanie i przenoszenie do kosza', + 'oauth.scope.files:content.label': 'Odczyt zawartości plików', + 'oauth.scope.files:content.description': 'Odczyt zawartości przesłanego dokumentu, na przykład PDF-u rezerwacji lub biletu', + 'oauth.scope.settings:read.label': 'Przeglądanie preferencji', + 'oauth.scope.settings:read.description': 'Odczyt jednostek, formatu czasu, języka, waluty domyślnej i strony startowej', + 'oauth.scope.settings:write.label': 'Zmiana preferencji', + 'oauth.scope.settings:write.description': 'Zmiana jednostek, formatu czasu, języka, waluty domyślnej i strony startowej. Nigdy zapisanych kluczy API', }; export default oauth; diff --git a/shared/src/i18n/ru/oauth.ts b/shared/src/i18n/ru/oauth.ts index 9e71181ce..ece34f24b 100644 --- a/shared/src/i18n/ru/oauth.ts +++ b/shared/src/i18n/ru/oauth.ts @@ -95,5 +95,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Файлы', + 'oauth.scope.group.settings': 'Настройки', + 'oauth.scope.files:read.label': 'Просмотр файлов поездки', + 'oauth.scope.files:read.description': 'Список документов поездки: названия, размеры, кто их загрузил и с чем они связаны', + 'oauth.scope.files:write.label': 'Управление файлами поездки', + 'oauth.scope.files:write.description': 'Переименование и описание файлов, привязка к бронированиям и местам, отметка и удаление в корзину', + 'oauth.scope.files:content.label': 'Чтение содержимого файлов', + 'oauth.scope.files:content.description': 'Чтение содержимого загруженного документа, например PDF бронирования или билета', + 'oauth.scope.settings:read.label': 'Просмотр ваших настроек', + 'oauth.scope.settings:read.description': 'Чтение единиц измерения, формата времени, языка, валюты по умолчанию и стартовой страницы', + 'oauth.scope.settings:write.label': 'Изменение ваших настроек', + 'oauth.scope.settings:write.description': 'Изменение единиц измерения, формата времени, языка, валюты по умолчанию и стартовой страницы. Никогда сохранённых ключей API', }; export default oauth; diff --git a/shared/src/i18n/sv/oauth.ts b/shared/src/i18n/sv/oauth.ts index 614093af6..b9dcf97ed 100644 --- a/shared/src/i18n/sv/oauth.ts +++ b/shared/src/i18n/sv/oauth.ts @@ -100,5 +100,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysTool.listTrips': 'Lista dina resor så att AI:n kan identifiera resenummer', 'oauth.authorize.alwaysTool.getTripSummary': 'Läs en översikt över resan som krävs för att kunna använda något annat verktyg', + 'oauth.scope.group.files': 'Filer', + 'oauth.scope.group.settings': 'Inställningar', + 'oauth.scope.files:read.label': 'Visa resans filer', + 'oauth.scope.files:read.description': 'Lista dokumenten på en resa: namn, storlek, vem som laddade upp dem och vad de är kopplade till', + 'oauth.scope.files:write.label': 'Hantera resans filer', + 'oauth.scope.files:write.description': 'Byt namn på och beskriv filer, koppla dem till bokningar och platser, stjärnmärk och släng dem', + 'oauth.scope.files:content.label': 'Läsa filinnehåll', + 'oauth.scope.files:content.description': 'Läsa innehållet i ett uppladdat dokument, till exempel en boknings-PDF eller en biljett', + 'oauth.scope.settings:read.label': 'Visa dina inställningar', + 'oauth.scope.settings:read.description': 'Läsa enheter, tidsformat, språk, standardvaluta och startsida', + 'oauth.scope.settings:write.label': 'Ändra dina inställningar', + 'oauth.scope.settings:write.description': 'Ändra enheter, tidsformat, språk, standardvaluta och startsida. Aldrig sparade API-nycklar', }; export default oauth; diff --git a/shared/src/i18n/tr/oauth.ts b/shared/src/i18n/tr/oauth.ts index 29216f452..231f7fb1e 100644 --- a/shared/src/i18n/tr/oauth.ts +++ b/shared/src/i18n/tr/oauth.ts @@ -98,5 +98,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Dosyalar', + 'oauth.scope.group.settings': 'Ayarlar', + 'oauth.scope.files:read.label': 'Gezi dosyalarını görüntüle', + 'oauth.scope.files:read.description': 'Bir gezinin belgelerini listele: adlar, boyutlar, kimin yüklediği ve neye bağlı oldukları', + 'oauth.scope.files:write.label': 'Gezi dosyalarını yönet', + 'oauth.scope.files:write.description': 'Dosyaları yeniden adlandır ve açıkla, rezervasyonlara ve yerlere bağla, yıldızla ve çöpe taşı', + 'oauth.scope.files:content.label': 'Dosya içeriğini oku', + 'oauth.scope.files:content.description': 'Yüklenmiş bir belgenin içeriğini oku, örneğin bir rezervasyon PDF’i veya bir bilet', + 'oauth.scope.settings:read.label': 'Tercihlerini görüntüle', + 'oauth.scope.settings:read.description': 'Birimleri, saat biçimini, dili, varsayılan para birimini ve başlangıç sayfasını oku', + 'oauth.scope.settings:write.label': 'Tercihlerini değiştir', + 'oauth.scope.settings:write.description': 'Birimleri, saat biçimini, dili, varsayılan para birimini ve başlangıç sayfasını değiştir. Kayıtlı API anahtarlarını asla', }; export default oauth; diff --git a/shared/src/i18n/uk/oauth.ts b/shared/src/i18n/uk/oauth.ts index ed4109f1b..d9e3f4786 100644 --- a/shared/src/i18n/uk/oauth.ts +++ b/shared/src/i18n/uk/oauth.ts @@ -94,5 +94,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': 'Файли', + 'oauth.scope.group.settings': 'Налаштування', + 'oauth.scope.files:read.label': 'Перегляд файлів подорожі', + 'oauth.scope.files:read.description': 'Список документів подорожі: назви, розміри, хто їх завантажив і з чим вони пов’язані', + 'oauth.scope.files:write.label': 'Керування файлами подорожі', + 'oauth.scope.files:write.description': 'Перейменування та опис файлів, прив’язка до бронювань і місць, позначення та переміщення в кошик', + 'oauth.scope.files:content.label': 'Читання вмісту файлів', + 'oauth.scope.files:content.description': 'Читання вмісту завантаженого документа, наприклад PDF бронювання або квитка', + 'oauth.scope.settings:read.label': 'Перегляд ваших налаштувань', + 'oauth.scope.settings:read.description': 'Читання одиниць вимірювання, формату часу, мови, валюти за умовчанням і стартової сторінки', + 'oauth.scope.settings:write.label': 'Зміна ваших налаштувань', + 'oauth.scope.settings:write.description': 'Зміна одиниць вимірювання, формату часу, мови, валюти за умовчанням і стартової сторінки. Ніколи збережених ключів API', }; export default oauth; diff --git a/shared/src/i18n/vi/oauth.ts b/shared/src/i18n/vi/oauth.ts index 410e5e28e..84723220b 100644 --- a/shared/src/i18n/vi/oauth.ts +++ b/shared/src/i18n/vi/oauth.ts @@ -97,5 +97,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysTool.listTrips': 'Liệt kê các chuyến đi của bạn để AI có thể khám phá ID chuyến đi', 'oauth.authorize.alwaysTool.getTripSummary': 'Đọc tổng quan về chuyến đi cần thiết để sử dụng bất kỳ công cụ nào khác', + 'oauth.scope.group.files': 'Tệp', + 'oauth.scope.group.settings': 'Cài đặt', + 'oauth.scope.files:read.label': 'Xem tệp của chuyến đi', + 'oauth.scope.files:read.description': 'Liệt kê tài liệu của chuyến đi: tên, kích thước, ai đã tải lên và chúng liên kết với gì', + 'oauth.scope.files:write.label': 'Quản lý tệp của chuyến đi', + 'oauth.scope.files:write.description': 'Đổi tên và mô tả tệp, liên kết với đặt chỗ và địa điểm, gắn sao và chuyển vào thùng rác', + 'oauth.scope.files:content.label': 'Đọc nội dung tệp', + 'oauth.scope.files:content.description': 'Đọc nội dung của tài liệu đã tải lên, chẳng hạn PDF đặt chỗ hoặc vé', + 'oauth.scope.settings:read.label': 'Xem tuỳ chọn của bạn', + 'oauth.scope.settings:read.description': 'Đọc đơn vị, định dạng giờ, ngôn ngữ, tiền tệ mặc định và trang khởi đầu', + 'oauth.scope.settings:write.label': 'Thay đổi tuỳ chọn của bạn', + 'oauth.scope.settings:write.description': 'Thay đổi đơn vị, định dạng giờ, ngôn ngữ, tiền tệ mặc định và trang khởi đầu. Không bao giờ khoá API đã lưu', }; export default oauth; diff --git a/shared/src/i18n/zh-TW/oauth.ts b/shared/src/i18n/zh-TW/oauth.ts index 81b2eebd1..9aa758ce2 100644 --- a/shared/src/i18n/zh-TW/oauth.ts +++ b/shared/src/i18n/zh-TW/oauth.ts @@ -92,5 +92,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback 'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback 'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback + 'oauth.scope.group.files': '檔案', + 'oauth.scope.group.settings': '設定', + 'oauth.scope.files:read.label': '檢視行程檔案', + 'oauth.scope.files:read.description': '列出行程的文件:名稱、大小、上傳者以及關聯的對象', + 'oauth.scope.files:write.label': '管理行程檔案', + 'oauth.scope.files:write.description': '重新命名與描述檔案,關聯至訂位和地點,加上星號並移至垃圾桶', + 'oauth.scope.files:content.label': '讀取檔案內容', + 'oauth.scope.files:content.description': '讀取已上傳文件的內容,例如訂位 PDF 或票券', + 'oauth.scope.settings:read.label': '檢視你的偏好設定', + 'oauth.scope.settings:read.description': '讀取單位、時間格式、語言、預設貨幣和起始頁', + 'oauth.scope.settings:write.label': '更改你的偏好設定', + 'oauth.scope.settings:write.description': '更改單位、時間格式、語言、預設貨幣和起始頁。絕不涉及已儲存的 API 金鑰', }; export default oauth; diff --git a/shared/src/i18n/zh/oauth.ts b/shared/src/i18n/zh/oauth.ts index e1338aeec..1410c6933 100644 --- a/shared/src/i18n/zh/oauth.ts +++ b/shared/src/i18n/zh/oauth.ts @@ -92,5 +92,17 @@ const oauth: TranslationStrings = { 'oauth.authorize.alwaysIncluded': '始终包含', 'oauth.authorize.alwaysTool.listTrips': '列出你的行程,以使 AI 找到行程 ID', 'oauth.authorize.alwaysTool.getTripSummary': '读取行程概览,这是使用其他工具所需的信息', + 'oauth.scope.group.files': '文件', + 'oauth.scope.group.settings': '设置', + 'oauth.scope.files:read.label': '查看行程文件', + 'oauth.scope.files:read.description': '列出行程的文档:名称、大小、上传者以及关联的对象', + 'oauth.scope.files:write.label': '管理行程文件', + 'oauth.scope.files:write.description': '重命名和描述文件,关联到预订和地点,标记星标并移入回收站', + 'oauth.scope.files:content.label': '读取文件内容', + 'oauth.scope.files:content.description': '读取已上传文档的内容,例如预订 PDF 或票据', + 'oauth.scope.settings:read.label': '查看你的偏好设置', + 'oauth.scope.settings:read.description': '读取单位、时间格式、语言、默认货币和起始页', + 'oauth.scope.settings:write.label': '更改你的偏好设置', + 'oauth.scope.settings:write.description': '更改单位、时间格式、语言、默认货币和起始页。绝不涉及已保存的 API 密钥', }; export default oauth; diff --git a/wiki/MCP-Scopes.md b/wiki/MCP-Scopes.md index ec4037c2e..d24610bbb 100644 --- a/wiki/MCP-Scopes.md +++ b/wiki/MCP-Scopes.md @@ -6,7 +6,7 @@ OAuth scopes control exactly which data your AI client can read or write in TREK ## All scopes -TREK defines 29 scopes across 14 groups. +TREK defines 34 scopes across 16 groups. | Group | Scope | Permission | |---|---|---| @@ -39,12 +39,19 @@ TREK defines 29 scopes across 14 groups. | **Journey** | `journey:read` | Read journeys, entries, and contributor list | | | `journey:write` | Create, update, and delete journeys and their entries | | | `journey:share` | Create, update, and revoke public share links for journeys | +| **Files** | `files:read` | List the documents on a trip: names, sizes, who uploaded them, what they link to | +| | `files:write` | Rename and describe files, link them to bookings and places, star and trash them | +| | `files:content` | Read what is inside an uploaded document, such as a booking PDF or a ticket | +| **Settings** | `settings:read` | Read units, time format, language, default currency, and start page | +| | `settings:write` | Change units, time format, language, default currency, and start page | ## Scope rules - A `:write` scope implies `:read` access for the same group (e.g. `budget:write` also grants read access to budget data). - Any `trips:*` scope (`trips:read`, `trips:write`, `trips:delete`, or `trips:share`) grants trip read access. -- `journey:read` or `journey:write` grants journey read access. `journey:share` alone does **not** grant read access — it only enables managing public share links. +- `journey:read` or `journey:write` grants journey read access. `journey:share` alone does **not** grant read access, it only enables managing public share links. +- `files:content` is a **separate** scope from `files:read` and is not implied by `files:write`. A token can list a trip's documents without being allowed to read what is inside them. Content reads are capped at 10 MB per file. +- `settings:write` never reaches a stored credential. The API keys, tokens and webhook URLs kept in settings are refused by the same allow-list the REST route uses, so an assistant can switch you to Fahrenheit but cannot read or replace your Mapbox key. - `list_trips` and `get_trip_summary` are always available regardless of scope — they are navigation tools. - Static tokens and web session JWTs have full access equivalent to all scopes. - Addon-gated tools (Packing, To-dos, Budget, Collections, Atlas, Collab, Vacay, Journey) require both the relevant scope **and** the corresponding addon to be enabled by an admin. The to-do tools ride the **Packing** addon, not an addon of their own.