Skip to main content
Glama

Social Media MCP Server

by tayler-id
linkedin-integration.md10.4 kB
# LinkedIn Integration Documentation ## Overview The LinkedIn integration allows the Social Media MCP Server to post content to LinkedIn accounts. This document outlines how the integration works, the authentication process, and how to troubleshoot common issues. ## Authentication The LinkedIn client uses OAuth 2.0 for authentication with the following credentials: 1. Client ID 2. Client Secret 3. Access Token These credentials are stored in the configuration and used to authenticate API requests. ## Key Components ### LinkedInClient Class Located in `src/platforms/linkedin/client.ts`, this class handles all interactions with the LinkedIn API: - **Authentication**: Manages token verification and authentication state - **Posting**: Handles posting content to LinkedIn - **Trending Topics**: Retrieves trending topics from LinkedIn - **Engagement Metrics**: Gets engagement data for posts ## Posting to LinkedIn The `postShare` method handles posting content to LinkedIn: ```typescript async postShare(content: Content): Promise<PostResult> { logger.info('Posting share', { content: content.text.substring(0, 30) + '...' }); try { // Use rate limit manager to handle API rate limits const result = await rateLimitManager.executeRequest({ api: 'linkedin', endpoint: 'postShare', method: 'POST', priority: 'high', retryCount: 0, maxRetries: config.rateLimit.maxRetries, execute: async () => { try { // Get user profile first const meResponse = await this.apiRequest('get', '/me'); const userId = meResponse.data.id; if (this.debug) { logger.info('LinkedIn API Debug: User profile', { userId }); } // Create share const shareResponse = await this.apiRequest('post', '/rest/posts', { author: `urn:li:person:${userId}`, lifecycleState: 'PUBLISHED', specificContent: { 'com.linkedin.ugc.ShareContent': { shareCommentary: { text: content.text }, shareMediaCategory: 'NONE' } }, visibility: { 'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC' } }); return shareResponse.data; } catch (apiError) { // Fall back to mock implementation for testing logger.info('Falling back to mock implementation for posting share'); // Generate a mock share response const mockShare = { id: `urn:li:share:mock-${Date.now()}`, created: { time: Date.now() }, lastModified: { time: Date.now() }, text: { text: content.text } }; if (this.debug) { logger.info('LinkedIn API Debug: Mock share response', { response: mockShare }); } return mockShare; } } }); // Get share ID const shareId = result.id; if (!shareId) { throw new Error('No share ID returned from LinkedIn API'); } // Check if this is a mock response const isMock = typeof shareId === 'string' && shareId.includes('mock-'); // Generate share URL const shareUrl = isMock ? `https://www.linkedin.com/feed/update/mock/${shareId}` : `https://www.linkedin.com/feed/update/${shareId}`; logger.info('Share posted successfully', { id: shareId }); // Return post result return { platform: SocialPlatform.LINKEDIN, success: true, postId: shareId, url: shareUrl, timestamp: new Date(), isMock }; } catch (error) { logger.error('Error posting share', { error: error instanceof Error ? error.message : String(error) }); return { platform: SocialPlatform.LINKEDIN, success: false, error: error instanceof Error ? error.message : String(error), timestamp: new Date(), }; } } ``` ## API Request Helper The LinkedIn client uses a helper method for making API requests: ```typescript private async apiRequest(method: string, url: string, data?: any): Promise<any> { try { // Create request config const config: AxiosRequestConfig = { method, url, headers: { 'Accept': 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.accessToken}`, 'X-Restli-Protocol-Version': '2.0.0' } }; // Add data if provided if (data) { config.data = data; } if (this.debug) { logger.info('LinkedIn API Request', { method, url, headers: config.headers, data: data ? 'data provided' : 'no data' }); } // Make request const response = await this.client.request(config); if (this.debug) { logger.info('LinkedIn API Response', { status: response.status, data: response.data ? 'data received' : 'no data' }); } return response; } catch (error) { if (axios.isAxiosError(error)) { logger.error('LinkedIn API Error', { response: { status: error.response?.status, statusText: error.response?.statusText, data: error.response?.data } }); } else { logger.error('LinkedIn API Error', { error: error instanceof Error ? error.message : String(error) }); } throw error; } } ``` ## Content Limitations LinkedIn has a character limit of 3,000 characters for posts. If your content exceeds this limit, the API will return an error. Make sure your content fits within this limit. ## Configuration The LinkedIn client is configured in `src/config/index.ts`: ```typescript linkedin: { credentials: { clientId: process.env.LINKEDIN_CLIENT_ID || '', clientSecret: process.env.LINKEDIN_CLIENT_SECRET || '', accessToken: process.env.LINKEDIN_ACCESS_TOKEN || '', }, debug: true, }, ``` ## LinkedIn API Endpoints The LinkedIn API uses the following endpoints for posting content: - `/me` - Get the current user's profile - `/rest/posts` - Create a new post ## Authentication Update To update the LinkedIn authentication with the new credentials provided: 1. Client ID: `78io7mffdgsnd9` 2. Client Secret: `WPL_AP1.MWpTSh50eL9Lv4kM.Lr5d8Q==` These have been updated in the configuration file. However, LinkedIn requires a proper OAuth 2.0 access token, which cannot be obtained programmatically without user interaction. ### Getting a Valid Access Token To get a valid access token, use the OAuth helper script: 1. Navigate to the scripts directory: ```bash cd scripts ``` 2. Install dependencies: ```bash npm install ``` 3. Run the LinkedIn OAuth script: ```bash npm run linkedin-oauth ``` 4. Follow the instructions in the terminal: - The script will open a browser window to the LinkedIn authorization page - Log in to LinkedIn and authorize the application - LinkedIn will display the authorization code on their page - Copy the authorization code and paste it back into the terminal - The script will exchange the code for an access token - The access token will be displayed in the terminal 5. Update the access token in the configuration: - Option 1: Add it to your `.env` file: ``` LINKEDIN_ACCESS_TOKEN=your_access_token_here ``` - Option 2: Update it directly in `src/config/index.ts` 6. Navigate back to the main project directory and rebuild the application: ```bash cd .. npm run build ``` 7. Run the application again to test the LinkedIn integration ### Troubleshooting OAuth - **Redirect URI Error**: Make sure your LinkedIn application is properly configured with the correct redirect URI (`https://www.linkedin.com/developers/tools/oauth/redirect`). For detailed instructions on fixing redirect URI issues, see [LinkedIn Redirect URI Configuration](./linkedin-redirect-uri.md). - **Scope Error**: If you encounter a "unauthorized_scope_error" error, it means the scope you're requesting is not authorized for your application. See [LinkedIn OAuth Scopes](./linkedin-scope.md) for information on how to fix scope-related issues. - **Token Exchange Error**: Check that your client ID and client secret are correct. - **Browser Opening Issues**: The script now includes enhanced browser detection and fallback mechanisms: - First tries to open in the default browser - If that fails, tries specific browsers (Chrome, Edge, Firefox) - If all browser attempts fail, falls back to platform-specific commands - As a last resort, displays the URL for manual opening - This helps avoid issues where LinkedIn tries to open in the app instead of a browser - **Authorization Code Not Displayed**: If LinkedIn doesn't display the authorization code after authentication: - Make sure you're using the correct redirect URI (`https://www.linkedin.com/developers/tools/oauth/redirect`) - Check that your LinkedIn application is properly configured - Try clearing your browser cookies and cache, then try again ## Troubleshooting ### Authentication Issues If you're experiencing authentication issues: 1. Check that your access token is valid 2. Verify that your client ID and client secret are correct 3. Look for authentication errors in the logs Common authentication errors: - `401 Unauthorized` - Invalid access token - `403 Forbidden` - Insufficient permissions ### Content Issues If your posts are failing: 1. Check the character count (must be under 3,000 characters) 2. Ensure there are no formatting issues 3. Check for any API-specific errors in the logs ### Mock Mode The client will fall back to mock mode if: 1. No access token is provided 2. Authentication fails 3. The API returns an error In mock mode, posts will appear successful but will have a URL like `https://www.linkedin.com/feed/update/mock/urn:li:share:mock-1234567890` and will be marked with `isMock: true` in the response. ## Current Status The LinkedIn integration is currently using mock mode due to an invalid access token. To fix this, we need to update the access token in the configuration.

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/tayler-id/social-media-mcp'

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