Skip to main content
Glama
get-metadata.ts6.21 kB
/** * MCP Tool: tableau_get_metadata * * Purpose: Get comprehensive metadata for a workbook or view * Parameters: * - contentId (required): Workbook or view identifier * - contentType (required): 'workbook' or 'view' * Returns: Detailed metadata including fields, data sources, permissions, etc. */ import { z } from 'zod'; import { TableauClient } from '../tableau-client.js'; // Zod schema for input validation export const GetMetadataArgsSchema = z.object({ contentId: z.string().min(1).describe('Content identifier (required)'), contentType: z.enum(['workbook', 'view']).describe('Content type: workbook or view (required)'), }); export type GetMetadataArgs = z.infer<typeof GetMetadataArgsSchema>; /** * Handler for tableau_get_metadata tool * * Retrieves comprehensive metadata for a workbook or view including * basic info, timestamps, project, owner, tags, and related resources. * * @param args - Tool arguments (contentId, contentType) * @param tableauClient - Initialized Tableau client instance * @returns Formatted response with metadata or error */ export async function getMetadataHandler( args: GetMetadataArgs, tableauClient: TableauClient ): Promise<{ content: Array<{ type: string; text: string }> }> { try { // Validate required parameters if (!args.contentId || args.contentId.trim() === '') { return { content: [{ type: 'text', text: 'Error: contentId is required and cannot be empty.' }] }; } if (!args.contentType) { return { content: [{ type: 'text', text: 'Error: contentType is required. Must be either "workbook" or "view".' }] }; } // Route to appropriate method based on content type let metadata: any; if (args.contentType === 'workbook') { metadata = await tableauClient.getWorkbookMetadata(args.contentId); } else if (args.contentType === 'view') { metadata = await tableauClient.getViewMetadata(args.contentId); } else { return { content: [{ type: 'text', text: `Error: Invalid contentType '${args.contentType}'. Must be either 'workbook' or 'view'.` }] }; } // Format response for LLM consumption let summary = `Metadata for ${args.contentType}: ${metadata.name}\n\n`; // Basic information summary += `BASIC INFORMATION:\n`; summary += `ID: ${metadata.id}\n`; summary += `Name: ${metadata.name}\n`; summary += `Content URL: ${metadata.contentUrl || 'N/A'}\n`; if (metadata.description) { summary += `Description: ${metadata.description}\n`; } // Timestamps summary += `\nTIMESTAMPS:\n`; if (metadata.createdAt) { summary += `Created: ${new Date(metadata.createdAt).toLocaleString()}\n`; } if (metadata.updatedAt) { summary += `Updated: ${new Date(metadata.updatedAt).toLocaleString()}\n`; } // Project information if (metadata.project) { summary += `\nPROJECT:\n`; summary += `Name: ${metadata.project.name}\n`; summary += `ID: ${metadata.project.id}\n`; } // Owner information if (metadata.owner) { summary += `\nOWNER:\n`; summary += `Name: ${metadata.owner.name || metadata.owner.id}\n`; summary += `ID: ${metadata.owner.id}\n`; } // Tags if (metadata.tags && metadata.tags.length > 0) { summary += `\nTAGS:\n`; summary += metadata.tags.map((tag: any) => `- ${tag.label || tag}`).join('\n') + '\n'; } // Workbook-specific: Views and Data Sources if (args.contentType === 'workbook') { if (metadata.views && metadata.views.length > 0) { summary += `\nVIEWS (${metadata.views.length}):\n`; metadata.views.forEach((view: any, index: number) => { summary += `${index + 1}. ${view.name} (ID: ${view.id})\n`; }); } if (metadata.dataSources && metadata.dataSources.length > 0) { summary += `\nDATA SOURCES (${metadata.dataSources.length}):\n`; metadata.dataSources.forEach((ds: any, index: number) => { summary += `${index + 1}. ${ds.name} (ID: ${ds.id})\n`; }); } } // View-specific: Workbook reference if (args.contentType === 'view' && metadata.workbook) { summary += `\nPARENT WORKBOOK:\n`; summary += `Name: ${metadata.workbook.name}\n`; summary += `ID: ${metadata.workbook.id}\n`; } // Also include raw JSON data for structured access const jsonData = JSON.stringify(metadata, null, 2); return { content: [ { type: 'text', text: summary }, { type: 'text', text: `\n\nRaw JSON data:\n${jsonData}` } ] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; // Provide helpful error messages if (errorMessage.includes('404') || errorMessage.includes('not found')) { return { content: [{ type: 'text', text: `Error: ${args.contentType} with ID '${args.contentId}' not found. Please verify the ID is correct and you have access to it.` }] }; } return { content: [{ type: 'text', text: `Error retrieving metadata: ${errorMessage}` }] }; } } // Tool metadata for MCP server registration export const getMetadataTool = { name: 'tableau_get_metadata', description: 'Get comprehensive metadata for a workbook or view. Returns detailed information including basic info, timestamps, project, owner, tags, and related resources. For workbooks: includes list of views and data sources. For views: includes parent workbook reference.', inputSchema: { type: 'object', properties: { contentId: { type: 'string', description: 'Required: Content identifier (workbook ID or view ID)' }, contentType: { type: 'string', enum: ['workbook', 'view'], description: 'Required: Type of content (workbook or view)' } }, required: ['contentId', 'contentType'] } };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/russelenriquez-agile/tableau-mcp-project'

If you have feedback or need assistance with the MCP directory API, please join our Discord server