Skip to main content
Glama

browse_wwdc_topics

Explore WWDC topic categories with IDs to filter Apple developer videos. Use topic IDs like "swiftui-ui-frameworks" to find relevant sessions and content.

Instructions

List all WWDC topic categories with their IDs. Essential first step before using list_wwdc_videos with topic filtering. Returns topic IDs like "swiftui-ui-frameworks" that can be used in other tools.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
topicIdNoTopic ID to explore. Available IDs: "accessibility-inclusion", "app-services", "app-store-distribution-marketing", "audio-video", "business-education", "design", "developer-tools", "essentials", "graphics-games", "health-fitness", "machine-learning-ai", "maps-location", "photos-camera", "privacy-security", "safari-web", "spatial-computing", "swift", "swiftui-ui-frameworks", "system-services". Leave empty to see all topics with video counts.
includeVideosNoList videos in the topic. Set false for topic structure only. Default: true
yearNoFilter topic videos by year. Only when browsing specific topic.
limitNoMax videos per topic (default: 20).

Implementation Reference

  • The main handler function `handleBrowseWWDCTopics` that implements the tool logic. It lists all WWDC topics or explores a specific topic with its videos. Uses helper functions loadGlobalMetadata() and loadTopicIndex() to fetch data, groups videos by year, and formats the output as markdown.
    export async function handleBrowseWWDCTopics(
      topicId?: string,
      includeVideos: boolean = true,
      year?: string,
      limit: number = 20,
    ): Promise<string> {
      try {
        const metadata = await loadGlobalMetadata();
    
        if (!topicId) {
          // List all available topics
          let content = '# WWDC Topics\n\n';
          content += `Found ${metadata.topics.length} topics:\n\n`;
    
          metadata.topics.forEach(topic => {
            content += `## [${topic.name}](${topic.url})\n`;
            content += `**Topic ID:** ${topic.id}\n`;
    
            // Show video count for this topic
            const topicStats = metadata.statistics.byTopic[topic.id];
            if (topicStats) {
              content += `**Videos:** ${topicStats}\n`;
            }
    
            content += '\n';
          });
    
          return content;
        }
    
        // Browse specific topic
        const topic = metadata.topics.find(t => t.id === topicId);
        if (!topic) {
          return `Topic "${topicId}" not found. Available topics: ${metadata.topics.map(t => t.id).join(', ')}`;
        }
    
        let content = `# ${topic.name}\n\n`;
        content += `**Topic ID:** ${topic.id}\n`;
        content += `**URL:** [${topic.url}](${topic.url})\n\n`;
    
        if (includeVideos) {
          try {
            const topicIndex = await loadTopicIndex(topicId);
    
            // Filter by year if specified
            let videosToShow = topicIndex.videos;
            if (year && year !== 'all') {
              videosToShow = videosToShow.filter(v => v.year === year);
            }
    
            // Apply limit
            videosToShow = videosToShow.slice(0, limit);
    
            content += `## Videos (${videosToShow.length}${videosToShow.length === limit ? '+' : ''})\n\n`;
    
            if (videosToShow.length === 0) {
              content += 'No videos found for this topic.\n';
            } else {
              // Group by year
              const videosByYear = videosToShow.reduce((acc, video) => {
                if (!acc[video.year]) {
                  acc[video.year] = [];
                }
                acc[video.year].push(video);
                return acc;
              }, {} as Record<string, typeof videosToShow>);
    
              Object.keys(videosByYear)
                .sort((a, b) => parseInt(b) - parseInt(a))
                .forEach(y => {
                  content += `### WWDC${y}\n\n`;
    
                  videosByYear[y].forEach(video => {
                    content += `- [${video.title}](${video.url})`;
    
                    const features: string[] = [];
                    if (video.hasTranscript) {
                      features.push('Transcript');
                    }
                    if (video.hasCode) {
                      features.push('Code');
                    }
    
                    if (features.length > 0) {
                      content += ` | ${features.join(' | ')}`;
                    }
    
                    content += '\n';
                  });
    
                  content += '\n';
                });
            }
    
          } catch (error) {
            content += `Error loading videos for topic: ${error instanceof Error ? error.message : String(error)}\n`;
          }
        }
    
        return content;
    
      } catch (error) {
        logger.error('Failed to browse WWDC topics:', error);
        const errorMessage = error instanceof Error ? error.message : String(error);
        return `Error: Failed to browse WWDC topics: ${errorMessage}`;
      }
    }
  • Zod schema definition `browseWWDCTopicsSchema` that validates input parameters: topicId (optional string), includeVideos (boolean, default true), year (optional string), and limit (number 1-100, default 20).
    export const browseWWDCTopicsSchema = z.object({
      topicId: z.string().optional().describe('Specific topic ID to browse'),
      includeVideos: z.boolean().default(true).describe('Include video list'),
      year: z.string().optional().describe('Filter videos by year'),
      limit: z.number().min(1).max(100).default(20).describe('Maximum number of videos per topic'),
    });
  • Tool registration wrapper that validates arguments using browseWWDCTopicsSchema.parse() and calls handleBrowseWWDCTopics with validated parameters. Returns formatted content as MCP tool response.
    browse_wwdc_topics: async (args, _server) => {
      const validatedArgs = browseWWDCTopicsSchema.parse(args);
      const result = await handleBrowseWWDCTopics(
        validatedArgs.topicId,
        validatedArgs.includeVideos,
        validatedArgs.year,
        validatedArgs.limit,
      );
      return { content: [{ type: 'text', text: result }] };
    },
  • MCP tool definition with metadata including tool name 'browse_wwdc_topics', description, and inputSchema specifying parameter types, descriptions, and available topic IDs.
      name: 'browse_wwdc_topics',
      description: 'List all WWDC topic categories with their IDs. Essential first step before using list_wwdc_videos with topic filtering. Returns topic IDs like "swiftui-ui-frameworks" that can be used in other tools.',
      inputSchema: {
        type: 'object',
        properties: {
          topicId: {
            type: 'string',
            description: 'Topic ID to explore. Available IDs: "accessibility-inclusion", "app-services", "app-store-distribution-marketing", "audio-video", "business-education", "design", "developer-tools", "essentials", "graphics-games", "health-fitness", "machine-learning-ai", "maps-location", "photos-camera", "privacy-security", "safari-web", "spatial-computing", "swift", "swiftui-ui-frameworks", "system-services". Leave empty to see all topics with video counts.',
          },
          includeVideos: {
            type: 'boolean',
            description: 'List videos in the topic. Set false for topic structure only. Default: true',
          },
          year: {
            type: 'string',
            description: 'Filter topic videos by year. Only when browsing specific topic.',
          },
          limit: {
            type: 'number',
            description: 'Max videos per topic (default: 20).',
          },
        },
        required: [],
      },
    },
  • Imports helper utilities used by the handler: loadGlobalMetadata and loadTopicIndex from utils/wwdc-data-source.js, plus logger for error handling and WWDCVideo type.
    /**
     * WWDC Video MCP Tool Handlers
     */
    
    import type { WWDCVideo } from '../../types/wwdc.js';
    import { logger } from '../../utils/logger.js';
    import {
      loadGlobalMetadata,
      loadTopicIndex,
      loadYearIndex,
      loadVideoData,
    } from '../../utils/wwdc-data-source.js';

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/kimsungwhee/apple-docs-mcp'

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