// Google Drive Permissions MCP Tools
// 5 tools for sharing and managing file permissions
import { z } from 'zod';
import type { DriveService } from '../services/drive.js';
// ─────────────────────────────────────────────────────────────────────────────
// TOOL DEFINITIONS
// ─────────────────────────────────────────────────────────────────────────────
export const permissionsTools = [
{
name: 'drive_listPermissions',
description: 'List all permissions (sharing settings) for a file or folder.',
inputSchema: {
type: 'object' as const,
properties: {
fileId: {
type: 'string',
description: 'File or folder ID'
}
},
required: ['fileId']
}
},
{
name: 'drive_getPermission',
description: 'Get details of a specific permission.',
inputSchema: {
type: 'object' as const,
properties: {
fileId: {
type: 'string',
description: 'File or folder ID'
},
permissionId: {
type: 'string',
description: 'Permission ID'
}
},
required: ['fileId', 'permissionId']
}
},
{
name: 'drive_shareFile',
description: 'Share a file or folder with a user, group, domain, or anyone with the link.',
inputSchema: {
type: 'object' as const,
properties: {
fileId: {
type: 'string',
description: 'File or folder ID to share'
},
type: {
type: 'string',
enum: ['user', 'group', 'domain', 'anyone'],
description: 'Type of grantee: user (specific email), group (Google Group), domain (entire domain), anyone (public link)'
},
role: {
type: 'string',
enum: ['owner', 'organizer', 'fileOrganizer', 'writer', 'commenter', 'reader'],
description: 'Permission role: owner, writer, commenter, reader. organizer/fileOrganizer for shared drives.'
},
emailAddress: {
type: 'string',
description: 'Email address (required for type=user or type=group)'
},
domain: {
type: 'string',
description: 'Domain name (required for type=domain)'
},
sendNotificationEmail: {
type: 'boolean',
description: 'Send email notification to the user (default: true)'
},
emailMessage: {
type: 'string',
description: 'Custom message to include in notification email'
},
expirationTime: {
type: 'string',
description: 'Expiration time for the permission (RFC 3339 timestamp). Only for user/group permissions.'
}
},
required: ['fileId', 'type', 'role']
}
},
{
name: 'drive_updatePermission',
description: 'Update a permission (change role or expiration).',
inputSchema: {
type: 'object' as const,
properties: {
fileId: {
type: 'string',
description: 'File or folder ID'
},
permissionId: {
type: 'string',
description: 'Permission ID to update'
},
role: {
type: 'string',
enum: ['owner', 'organizer', 'fileOrganizer', 'writer', 'commenter', 'reader'],
description: 'New role for the permission'
},
expirationTime: {
type: 'string',
description: 'New expiration time (RFC 3339)'
}
},
required: ['fileId', 'permissionId', 'role']
}
},
{
name: 'drive_unshare',
description: 'Remove a permission (stop sharing with a user/group/domain).',
inputSchema: {
type: 'object' as const,
properties: {
fileId: {
type: 'string',
description: 'File or folder ID'
},
permissionId: {
type: 'string',
description: 'Permission ID to remove'
}
},
required: ['fileId', 'permissionId']
}
},
];
// ─────────────────────────────────────────────────────────────────────────────
// ZOD SCHEMAS
// ─────────────────────────────────────────────────────────────────────────────
const ListPermissionsSchema = z.object({
fileId: z.string().min(1),
});
const GetPermissionSchema = z.object({
fileId: z.string().min(1),
permissionId: z.string().min(1),
});
const ShareFileSchema = z.object({
fileId: z.string().min(1),
type: z.enum(['user', 'group', 'domain', 'anyone']),
role: z.enum(['owner', 'organizer', 'fileOrganizer', 'writer', 'commenter', 'reader']),
emailAddress: z.string().email().optional(),
domain: z.string().optional(),
sendNotificationEmail: z.boolean().optional(),
emailMessage: z.string().optional(),
expirationTime: z.string().optional(),
});
const UpdatePermissionSchema = z.object({
fileId: z.string().min(1),
permissionId: z.string().min(1),
role: z.enum(['owner', 'organizer', 'fileOrganizer', 'writer', 'commenter', 'reader']),
expirationTime: z.string().optional(),
});
const UnshareSchema = z.object({
fileId: z.string().min(1),
permissionId: z.string().min(1),
});
// ─────────────────────────────────────────────────────────────────────────────
// HANDLERS
// ─────────────────────────────────────────────────────────────────────────────
export function createPermissionsHandlers(driveService: DriveService) {
return {
drive_listPermissions: async (args: unknown) => {
const { fileId } = ListPermissionsSchema.parse(args);
const permissions = await driveService.listPermissions(fileId);
return {
content: [{
type: 'text' as const,
text: JSON.stringify({
success: true,
permissions: permissions.map(p => ({
id: p.id,
type: p.type,
role: p.role,
emailAddress: p.emailAddress,
domain: p.domain,
displayName: p.displayName,
expirationTime: p.expirationTime,
})),
totalCount: permissions.length
}, null, 2)
}]
};
},
drive_getPermission: async (args: unknown) => {
const { fileId, permissionId } = GetPermissionSchema.parse(args);
const permission = await driveService.getPermission(fileId, permissionId);
return {
content: [{
type: 'text' as const,
text: JSON.stringify({
success: true,
permission: {
id: permission.id,
type: permission.type,
role: permission.role,
emailAddress: permission.emailAddress,
domain: permission.domain,
displayName: permission.displayName,
expirationTime: permission.expirationTime,
}
}, null, 2)
}]
};
},
drive_shareFile: async (args: unknown) => {
const params = ShareFileSchema.parse(args);
// Validate required fields based on type
if (params.type === 'user' || params.type === 'group') {
if (!params.emailAddress) {
throw new Error(`emailAddress is required for type="${params.type}"`);
}
}
if (params.type === 'domain') {
if (!params.domain) {
throw new Error('domain is required for type="domain"');
}
}
const permission = await driveService.createPermission(
params.fileId,
params.type,
params.role,
{
emailAddress: params.emailAddress,
domain: params.domain,
sendNotificationEmail: params.sendNotificationEmail,
emailMessage: params.emailMessage,
expirationTime: params.expirationTime,
}
);
return {
content: [{
type: 'text' as const,
text: JSON.stringify({
success: true,
message: `File shared successfully with ${params.type === 'anyone' ? 'anyone with the link' : params.emailAddress || params.domain}`,
permission: {
id: permission.id,
type: permission.type,
role: permission.role,
emailAddress: permission.emailAddress,
domain: permission.domain,
expirationTime: permission.expirationTime,
}
}, null, 2)
}]
};
},
drive_updatePermission: async (args: unknown) => {
const { fileId, permissionId, role, expirationTime } = UpdatePermissionSchema.parse(args);
const permission = await driveService.updatePermission(fileId, permissionId, role, { expirationTime });
return {
content: [{
type: 'text' as const,
text: JSON.stringify({
success: true,
message: 'Permission updated successfully',
permission: {
id: permission.id,
type: permission.type,
role: permission.role,
emailAddress: permission.emailAddress,
expirationTime: permission.expirationTime,
}
}, null, 2)
}]
};
},
drive_unshare: async (args: unknown) => {
const { fileId, permissionId } = UnshareSchema.parse(args);
await driveService.deletePermission(fileId, permissionId);
return {
content: [{
type: 'text' as const,
text: JSON.stringify({
success: true,
message: 'Permission removed successfully'
}, null, 2)
}]
};
},
};
}