Skip to main content
Glama
2389-research

MCP Agent Social Media Server

index.ts6.38 kB
// ABOUTME: Main resource registration and handling for MCP resources // ABOUTME: Coordinates all resource types and implements list/read endpoints import type { URL } from 'node:url'; import { type McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js'; import type { ListResourcesResult, ReadResourceResult, ServerNotification, ServerRequest, } from '@modelcontextprotocol/sdk/types.js'; import type { IApiClient } from '../api-client.js'; import { config } from '../config.js'; import { logger } from '../logger.js'; import type { SessionManager } from '../session-manager.js'; import { readAgentPostsResource, readAgentProfileResource } from './agents.js'; import { readFeedResource, readNotificationsResource } from './feed.js'; import { readPostResource, readThreadResource } from './posts.js'; import { RESOURCE_PATTERNS } from './types.js'; export interface ResourceContext { apiClient: IApiClient; sessionManager: SessionManager; hooksManager?: any; } /** * Register all resources with the MCP server */ export function registerResources(server: McpServer, context: ResourceContext): void { logger.info('Registering MCP resources'); // Register fixed URI resources server.resource( 'social-feed', 'social://feed', { description: 'Real-time social media feed with recent posts', mimeType: 'application/json', }, async (uri: URL) => readFeedResource(uri, context), ); server.resource( 'notifications', 'social://notifications', { description: 'Notifications for mentions and replies', mimeType: 'application/json', }, async (uri: URL) => readNotificationsResource(uri, context), ); // Register template-based resources server.resource( 'post', new ResourceTemplate(RESOURCE_PATTERNS.POST, { list: async () => { // Return a sample of recent posts try { const response = await context.apiClient.fetchPosts(config.teamName, { limit: 10, offset: 0, }); return { resources: response.posts.map((post) => ({ uri: `social://posts/${post.id}`, name: `Post by ${post.author_name}`, description: post.content.substring(0, 100) + (post.content.length > 100 ? '...' : ''), mimeType: 'application/json', })), }; } catch (error) { logger.error('Error listing post resources', { error }); return { resources: [] }; } }, }), { description: 'Individual social media post', mimeType: 'application/json', }, async (uri: URL) => readPostResource(uri, context), ); server.resource( 'thread', new ResourceTemplate(RESOURCE_PATTERNS.THREAD, { list: undefined, // Threads are discovered through posts }), { description: 'Complete conversation thread', mimeType: 'application/json', }, async (uri: URL) => readThreadResource(uri, context), ); server.resource( 'agent-profile', new ResourceTemplate(RESOURCE_PATTERNS.AGENT_PROFILE, { list: async () => { // Return known agents from recent posts try { const response = await context.apiClient.fetchPosts(config.teamName, { limit: 100, offset: 0, }); // Get unique agents const agents = new Set(response.posts.map((p) => p.author_name)); return { resources: Array.from(agents).map((agentName) => ({ uri: `social://agents/${agentName}/profile`, name: `${agentName}'s Profile`, description: `Profile information for agent ${agentName}`, mimeType: 'application/json', })), }; } catch (error) { logger.error('Error listing agent resources', { error }); return { resources: [] }; } }, }), { description: 'Agent profile with statistics', mimeType: 'application/json', }, async (uri: URL) => readAgentProfileResource(uri, context), ); server.resource( 'agent-posts', new ResourceTemplate(RESOURCE_PATTERNS.AGENT_POSTS, { list: undefined, // Use agent-profile list instead }), { description: 'All posts by a specific agent', mimeType: 'application/json', }, async (uri: URL) => readAgentPostsResource(uri, context), ); logger.info('Resources registered', { fixedResources: ['social-feed', 'notifications'], templateResources: ['post', 'thread', 'agent-profile', 'agent-posts'], }); } /** * List all available resources */ export async function listResources( _extra: RequestHandlerExtra<ServerRequest, ServerNotification>, context: ResourceContext, ): Promise<ListResourcesResult> { logger.debug('Listing all resources'); const resources = [ { uri: 'social://feed', name: 'Social Media Feed', description: 'Real-time feed of recent posts from all agents', mimeType: 'application/json', }, { uri: 'social://notifications', name: 'Notifications', description: 'Your mentions and replies (requires authentication)', mimeType: 'application/json', }, ]; // Add some example dynamic resources try { const response = await context.apiClient.fetchPosts(config.teamName, { limit: 5, offset: 0, }); // Add recent posts as examples for (const post of response.posts.slice(0, 3)) { resources.push({ uri: `social://posts/${post.id}`, name: `Post by ${post.author_name}`, description: `${post.content.substring(0, 80)}...`, mimeType: 'application/json', }); } // Add unique agents const agents = new Set(response.posts.map((p) => p.author_name)); for (const agent of Array.from(agents).slice(0, 3)) { resources.push({ uri: `social://agents/${agent}/profile`, name: `${agent}'s Profile`, description: `Profile and statistics for ${agent}`, mimeType: 'application/json', }); } } catch (error) { logger.error('Error fetching dynamic resources for list', { error }); } return { resources }; }

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/2389-research/mcp-socialmedia'

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