Skip to main content
Glama
createClaudeMcpBundleManifest.ts12.7 kB
#!/usr/bin/env node /* eslint-disable no-console */ import { McpbManifestSchema, McpbUserConfigurationOptionSchema } from '@anthropic-ai/mcpb'; import { writeFileSync } from 'fs'; import { dirname, join } from 'path'; import { fileURLToPath } from 'url'; import { z } from 'zod'; import packageJson from '../../package.json' with { type: 'json' }; import { ProcessEnvEx } from '../../types/process-env.js'; import { toolNames } from '../tools/toolName.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); type McpbUserConfigurationOption = z.infer<typeof McpbUserConfigurationOptionSchema>; type McpbManifest = z.infer<typeof McpbManifestSchema>; type EnvVars = { [TKey in keyof ProcessEnvEx]: McpbUserConfigurationOption & { includeInUserConfig: boolean; }; }; const envVars = { AUTH: { includeInUserConfig: false, type: 'string', title: 'Authentication Method', description: 'The authentication method to use by the server. Possible values are `pat` or `direct-trust`.', required: false, sensitive: false, }, SERVER: { includeInUserConfig: true, type: 'string', title: 'Server', description: 'The URL of the Tableau server e.g. https://tableau.example.com', required: true, sensitive: false, }, SITE_NAME: { includeInUserConfig: true, type: 'string', title: 'Site Name', description: 'The name of the Tableau site to use. For Tableau Server, leave this empty to specify the default site.', required: false, sensitive: false, }, PAT_NAME: { includeInUserConfig: true, type: 'string', title: 'PAT Name', description: 'The name of the Tableau Personal Access Token to use for authentication.', required: true, sensitive: false, }, PAT_VALUE: { includeInUserConfig: true, type: 'string', title: 'PAT Value', description: 'The value of the Tableau Personal Access Token to use for authentication.', required: true, sensitive: true, }, JWT_SUB_CLAIM: { includeInUserConfig: false, type: 'string', title: 'JWT Sub Claim', description: 'The username for the `sub` claim of the JWT.', required: false, sensitive: false, }, CONNECTED_APP_CLIENT_ID: { includeInUserConfig: false, type: 'string', title: 'Connected App Client ID', description: 'The client ID of the Tableau Connected App.', required: false, sensitive: false, }, CONNECTED_APP_SECRET_ID: { includeInUserConfig: false, type: 'string', title: 'Connected App Secret ID', description: 'The secret ID of the Tableau Connected App.', required: false, sensitive: false, }, CONNECTED_APP_SECRET_VALUE: { includeInUserConfig: false, type: 'string', title: 'Connected App Secret Value', description: 'The secret value of the Tableau Connected App.', required: false, sensitive: true, }, JWT_ADDITIONAL_PAYLOAD: { includeInUserConfig: false, type: 'string', title: 'JWT Additional Payload', description: 'A JSON string that includes any additional user attributes to include on the JWT.', required: false, sensitive: false, }, TRANSPORT: { includeInUserConfig: false, type: 'string', title: 'MCP Transport', description: 'The MCP transport type to use for the server.', required: false, sensitive: false, }, ENABLE_SERVER_LOGGING: { includeInUserConfig: false, type: 'string', title: 'Enable Server Logging', description: 'Enable logging of server activity to local files.', required: false, sensitive: false, }, SERVER_LOG_DIRECTORY: { includeInUserConfig: false, type: 'string', title: 'Server Log Directory', description: 'The directory to write the server logs to when ENABLE_SERVER_LOGGING is true.', required: false, sensitive: false, }, DEFAULT_LOG_LEVEL: { includeInUserConfig: false, type: 'string', title: 'Default Log Level', description: 'The default logging level of the server.', required: false, sensitive: false, }, DATASOURCE_CREDENTIALS: { includeInUserConfig: true, type: 'string', title: 'Datasource Credentials', description: 'A JSON string that includes usernames and passwords for any datasources that require them. See the README for details on how to format this string.', required: false, sensitive: true, }, INCLUDE_TOOLS: { includeInUserConfig: false, type: 'string', title: 'Included Tools', description: 'A comma-separated list of tool names to include in the server. Only these tools will be available.', required: false, sensitive: false, }, EXCLUDE_TOOLS: { includeInUserConfig: false, type: 'string', title: 'Excluded Tools', description: 'A comma-separated list of tool names to exclude from the server. All other tools will be available.', required: false, sensitive: false, }, INCLUDE_PROJECT_IDS: { includeInUserConfig: false, type: 'string', title: 'IDs of projects to constrain tool results by', description: 'A comma-separated list of project IDs to constrain tool results by.', required: false, sensitive: false, }, INCLUDE_DATASOURCE_IDS: { includeInUserConfig: false, type: 'string', title: 'IDs of datasources to constrain tool results by', description: 'A comma-separated list of datasource IDs to constrain tool results by.', required: false, sensitive: false, }, INCLUDE_WORKBOOK_IDS: { includeInUserConfig: false, type: 'string', title: 'IDs of workbooks to constrain tool results by', description: 'A comma-separated list of workbook IDs to constrain tool results by.', required: false, sensitive: false, }, MAX_RESULT_LIMIT: { includeInUserConfig: false, type: 'number', title: 'Max Result Limit', description: 'If a tool has a "limit" parameter and returns an array of items, the maximum length of that array.', required: false, sensitive: false, }, DISABLE_QUERY_DATASOURCE_FILTER_VALIDATION: { includeInUserConfig: false, type: 'boolean', title: 'Disable Query Datasource Filter Validation', description: 'Disable validation of SET and MATCH filter values in query-datasource tool.', required: false, sensitive: false, }, DISABLE_METADATA_API_REQUESTS: { includeInUserConfig: false, type: 'boolean', title: 'Disable Metadata API Requests', description: 'Disable requests to the Tableau Metadata API in the get-datasource-metadata tool.', required: false, sensitive: false, }, DISABLE_SESSION_MANAGEMENT: { includeInUserConfig: false, type: 'boolean', title: 'Disable Session Management', description: 'Disable session management.', required: false, sensitive: false, }, SSL_KEY: { includeInUserConfig: false, type: 'string', title: 'SSL Key Path', description: 'The path to the SSL key file to use for the HTTP server.', required: false, sensitive: false, }, SSL_CERT: { includeInUserConfig: false, type: 'string', title: 'SSL Certificate Path', description: 'The path to the SSL certificate file to use for the HTTP server.', required: false, sensitive: false, }, HTTP_PORT_ENV_VAR_NAME: { includeInUserConfig: false, type: 'string', title: 'HTTP Port Environment Variable Name', description: 'The environment variable name to use for the HTTP server port.', required: false, sensitive: false, }, CORS_ORIGIN_CONFIG: { includeInUserConfig: false, type: 'string', title: 'CORS Origin Config', description: 'The origin or origins to allow CORS requests from.', required: false, sensitive: false, }, TRUST_PROXY_CONFIG: { includeInUserConfig: false, type: 'string', title: 'Trust Proxy Config', description: 'The trust proxy config.', required: false, sensitive: false, }, DISABLE_LOG_MASKING: { includeInUserConfig: false, type: 'boolean', title: 'Disable Log Masking', description: 'Disable masking of credentials in logs. For debug purposes only.', required: false, sensitive: false, }, TABLEAU_SERVER_VERSION_CHECK_INTERVAL_IN_HOURS: { includeInUserConfig: false, type: 'number', title: 'Tableau Server Version Check Interval in Hours', description: 'The interval in hours to check the Tableau server version.', required: false, sensitive: false, }, DANGEROUSLY_DISABLE_OAUTH: { includeInUserConfig: false, type: 'boolean', title: 'Dangerously Disable OAuth', description: 'Dangerously disable OAuth when transport is http.', required: false, sensitive: false, }, OAUTH_ISSUER: { includeInUserConfig: false, type: 'string', title: 'OAuth Issuer', description: 'The OAuth issuer.', required: false, sensitive: false, }, OAUTH_JWE_PRIVATE_KEY: { includeInUserConfig: false, type: 'string', title: 'OAuth JWE Private Key', description: 'The OAuth JWE private key.', required: false, sensitive: true, }, OAUTH_JWE_PRIVATE_KEY_PATH: { includeInUserConfig: false, type: 'string', title: 'OAuth JWE Private Key Path', description: 'The path to the OAuth JWE private key.', required: false, sensitive: true, }, OAUTH_JWE_PRIVATE_KEY_PASSPHRASE: { includeInUserConfig: false, type: 'string', title: 'OAuth JWE Private Key Passphrase', description: 'The passphrase for the OAuth JWE private key.', required: false, sensitive: true, }, OAUTH_REDIRECT_URI: { includeInUserConfig: false, type: 'string', title: 'OAuth Redirect URI', description: 'The OAuth redirect URI.', required: false, sensitive: false, }, OAUTH_CLIENT_ID_SECRET_PAIRS: { includeInUserConfig: false, type: 'string', title: 'OAuth Client ID Secret Pairs', description: 'A comma-separated list of client ID and secret pairs for the OAuth client. The format is `clientId:secret`.', required: false, sensitive: true, }, OAUTH_AUTHORIZATION_CODE_TIMEOUT_MS: { includeInUserConfig: false, type: 'number', title: 'OAuth Authorization Code Timeout', description: 'The OAuth authorization code timeout.', required: false, sensitive: false, }, OAUTH_ACCESS_TOKEN_TIMEOUT_MS: { includeInUserConfig: false, type: 'number', title: 'OAuth Access Token Timeout', description: 'The OAuth access token timeout.', required: false, sensitive: false, }, OAUTH_REFRESH_TOKEN_TIMEOUT_MS: { includeInUserConfig: false, type: 'number', title: 'OAuth Refresh Token Timeout', description: 'The OAuth refresh token timeout.', required: false, sensitive: false, }, } satisfies EnvVars; const userConfig = Object.entries(envVars).reduce<Record<string, McpbUserConfigurationOption>>( (acc, [key, value]) => { if (value.includeInUserConfig) { acc[key.toLowerCase()] = { type: value.type, title: value.required ? value.title : `${value.title} (Optional)`, description: value.description, required: value.required, sensitive: value.sensitive, }; } return acc; }, {}, ); const manifestEnvObject = Object.entries(envVars).reduce<Record<string, string>>( (acc, [key, value]) => { if (value.includeInUserConfig) { acc[key] = `\${user_config.${key.toLowerCase()}}`; } return acc; }, {}, ); const manifest = { manifest_version: '0.2', name: 'Tableau', version: packageJson.version, description: packageJson.description, author: { name: 'Tableau', }, repository: { type: 'git', url: 'https://github.com/tableau/tableau-mcp', }, homepage: packageJson.homepage, documentation: 'https://tableau.github.io/tableau-mcp/', license: packageJson.license, support: 'https://github.com/tableau/tableau-mcp/issues', icon: 'https://avatars.githubusercontent.com/u/828667', server: { type: 'node', entry_point: 'build/index.js', mcp_config: { command: 'node', args: ['${__dirname}/build/index.js'], env: manifestEnvObject, }, }, tools: toolNames.map((name) => ({ name })), user_config: userConfig, } satisfies McpbManifest; const manifestPath = join(__dirname, '../../manifest.json'); writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); console.log(`✅ Manifest file generated successfully at ${manifestPath}`);

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/datalabs89/tableau-mcp'

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