UNPKG

@maheidem/linkedin-mcp

Version:

Comprehensive LinkedIn API MCP server with automatic Claude configuration

654 lines 27.1 kB
#!/usr/bin/env node "use strict"; /** * Comprehensive LinkedIn API MCP Server * Exposes ALL LinkedIn API endpoints through Model Context Protocol * Requires LinkedIn Partner Program approval for full functionality */ Object.defineProperty(exports, "__esModule", { value: true }); const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js"); const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js"); const types_js_1 = require("@modelcontextprotocol/sdk/types.js"); const linkedin_client_js_1 = require("./api/linkedin-client.js"); const server = new index_js_1.Server({ name: 'linkedin-api-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, }); // Initialize LinkedIn API client const linkedinClient = new linkedin_client_js_1.LinkedInAPIClient({ clientId: process.env.LINKEDIN_CLIENT_ID || '', clientSecret: process.env.LINKEDIN_CLIENT_SECRET || '', redirectUri: process.env.LINKEDIN_REDIRECT_URI || 'http://localhost:3000/callback', apiVersion: '202504', // Latest 2025 version }); // Complete LinkedIn API tools catalog const LINKEDIN_API_TOOLS = [ // AUTHENTICATION & AUTHORIZATION { name: 'linkedin_oauth_get_auth_url', description: 'Generate OAuth 2.0 authorization URL for LinkedIn authentication', inputSchema: { type: 'object', properties: { scopes: { type: 'array', items: { type: 'string' }, description: 'LinkedIn API scopes (r_liteprofile, r_emailaddress, w_member_social, etc.)' }, state: { type: 'string', description: 'CSRF protection state parameter' }, usePKCE: { type: 'boolean', description: 'Use PKCE flow for native apps' } }, required: ['scopes'] } }, { name: 'linkedin_oauth_exchange_code', description: 'Exchange authorization code for access token', inputSchema: { type: 'object', properties: { code: { type: 'string', description: 'Authorization code from callback' }, state: { type: 'string', description: 'State parameter for verification' }, codeVerifier: { type: 'string', description: 'PKCE code verifier (if used)' } }, required: ['code'] } }, { name: 'linkedin_oauth_refresh_token', description: 'Refresh expired access token', inputSchema: { type: 'object', properties: { refreshToken: { type: 'string', description: 'Valid refresh token' } }, required: ['refreshToken'] } }, // PROFILE & PEOPLE APIs { name: 'linkedin_people_get_profile', description: 'Get member profile information', inputSchema: { type: 'object', properties: { personId: { type: 'string', description: 'LinkedIn person ID (optional, defaults to authenticated user)' }, fields: { type: 'array', items: { type: 'string' }, description: 'Profile fields to retrieve (id, firstName, lastName, headline, etc.)' } } } }, { name: 'linkedin_people_search_members', description: 'Search for LinkedIn members', inputSchema: { type: 'object', properties: { keywords: { type: 'string', description: 'Search keywords' }, facets: { type: 'object', description: 'Search facets (location, industry, etc.)' }, start: { type: 'number', description: 'Pagination start' }, count: { type: 'number', description: 'Number of results (max 100)' } } } }, // ORGANIZATIONS & COMPANIES APIs { name: 'linkedin_organizations_get_company', description: 'Get organization/company information', inputSchema: { type: 'object', properties: { organizationId: { type: 'string', description: 'LinkedIn organization ID' }, fields: { type: 'array', items: { type: 'string' }, description: 'Organization fields (id, name, description, industry, etc.)' } }, required: ['organizationId'] } }, { name: 'linkedin_organizations_get_follower_stats', description: 'Get organization follower statistics', inputSchema: { type: 'object', properties: { organizationId: { type: 'string', description: 'LinkedIn organization ID' }, timeIntervals: { type: 'object', description: 'Time range for statistics' } }, required: ['organizationId'] } }, // CONTENT APIs (POSTS, UGC, ASSETS) { name: 'linkedin_posts_create', description: 'Create a new LinkedIn post using Posts API', inputSchema: { type: 'object', properties: { author: { type: 'string', description: 'Author URN (person or organization)' }, postType: { type: 'string', enum: ['TEXT', 'IMAGE', 'VIDEO', 'ARTICLE', 'POLL', 'MULTI_IMAGE'], description: 'Type of post to create' }, text: { type: 'string', description: 'Post text content' }, media: { type: 'array', items: { type: 'object', properties: { type: { type: 'string', enum: ['IMAGE', 'VIDEO'] }, url: { type: 'string' }, altText: { type: 'string' } } }, description: 'Media attachments' }, articleLink: { type: 'string', description: 'Article URL for article posts' }, pollOptions: { type: 'array', items: { type: 'string' }, description: 'Poll options for poll posts' }, visibility: { type: 'string', enum: ['PUBLIC', 'CONNECTIONS', 'LOGGED_IN_USERS'], description: 'Post visibility' } }, required: ['author', 'postType'] } }, { name: 'linkedin_posts_get', description: 'Retrieve LinkedIn posts', inputSchema: { type: 'object', properties: { postId: { type: 'string', description: 'Specific post ID to retrieve' }, author: { type: 'string', description: 'Filter by author URN' }, start: { type: 'number', description: 'Pagination start' }, count: { type: 'number', description: 'Number of posts to retrieve' } } } }, { name: 'linkedin_posts_update', description: 'Update an existing LinkedIn post', inputSchema: { type: 'object', properties: { postId: { type: 'string', description: 'Post ID to update' }, text: { type: 'string', description: 'New post text' }, visibility: { type: 'string', description: 'New visibility setting' } }, required: ['postId'] } }, { name: 'linkedin_posts_delete', description: 'Delete a LinkedIn post', inputSchema: { type: 'object', properties: { postId: { type: 'string', description: 'Post ID to delete' } }, required: ['postId'] } }, { name: 'linkedin_ugc_create', description: 'Create UGC post (legacy API, mainly for video)', inputSchema: { type: 'object', properties: { author: { type: 'string', description: 'Author URN' }, text: { type: 'string', description: 'Post text' }, media: { type: 'array', description: 'Media assets' }, visibility: { type: 'object', description: 'Visibility settings' } }, required: ['author'] } }, { name: 'linkedin_assets_upload', description: 'Upload media assets (images/videos)', inputSchema: { type: 'object', properties: { mediaType: { type: 'string', enum: ['IMAGE', 'VIDEO'], description: 'Type of media' }, uploadUrl: { type: 'string', description: 'Pre-signed upload URL' }, filePath: { type: 'string', description: 'Local file path to upload' }, owner: { type: 'string', description: 'Owner URN (person or organization)' } }, required: ['mediaType', 'owner'] } }, { name: 'linkedin_assets_get_upload_url', description: 'Get pre-signed URL for media upload', inputSchema: { type: 'object', properties: { mediaType: { type: 'string', enum: ['IMAGE', 'VIDEO'] }, owner: { type: 'string', description: 'Owner URN' }, filename: { type: 'string', description: 'Original filename' } }, required: ['mediaType', 'owner'] } }, // SOCIAL ACTIONS APIs { name: 'linkedin_social_actions_like', description: 'Like a LinkedIn post or comment', inputSchema: { type: 'object', properties: { targetUrn: { type: 'string', description: 'URN of content to like' }, actor: { type: 'string', description: 'Actor URN (person)' } }, required: ['targetUrn', 'actor'] } }, { name: 'linkedin_social_actions_comment', description: 'Comment on a LinkedIn post', inputSchema: { type: 'object', properties: { targetUrn: { type: 'string', description: 'Post URN to comment on' }, actor: { type: 'string', description: 'Commenter URN' }, text: { type: 'string', description: 'Comment text' } }, required: ['targetUrn', 'actor', 'text'] } }, { name: 'linkedin_social_actions_share', description: 'Share a LinkedIn post', inputSchema: { type: 'object', properties: { targetUrn: { type: 'string', description: 'Post URN to share' }, actor: { type: 'string', description: 'Sharer URN' }, commentary: { type: 'string', description: 'Optional commentary' } }, required: ['targetUrn', 'actor'] } }, // MARKETING & ADVERTISING APIs { name: 'linkedin_ads_create_campaign', description: 'Create advertising campaign', inputSchema: { type: 'object', properties: { account: { type: 'string', description: 'Ad account URN' }, name: { type: 'string', description: 'Campaign name' }, type: { type: 'string', enum: ['SPONSORED_CONTENT', 'SPONSORED_MESSAGING', 'TEXT_ADS'] }, status: { type: 'string', enum: ['ACTIVE', 'PAUSED', 'DRAFT'] }, budget: { type: 'object', description: 'Campaign budget settings' }, targeting: { type: 'object', description: 'Targeting criteria' } }, required: ['account', 'name', 'type'] } }, { name: 'linkedin_ads_get_campaigns', description: 'Retrieve advertising campaigns', inputSchema: { type: 'object', properties: { account: { type: 'string', description: 'Ad account URN' }, campaignIds: { type: 'array', items: { type: 'string' }, description: 'Specific campaign IDs' }, status: { type: 'string', description: 'Filter by campaign status' } } } }, { name: 'linkedin_ads_update_campaign', description: 'Update advertising campaign', inputSchema: { type: 'object', properties: { campaignId: { type: 'string', description: 'Campaign ID to update' }, name: { type: 'string', description: 'New campaign name' }, status: { type: 'string', description: 'New campaign status' }, budget: { type: 'object', description: 'Updated budget settings' } }, required: ['campaignId'] } }, { name: 'linkedin_ads_get_analytics', description: 'Get advertising analytics', inputSchema: { type: 'object', properties: { campaigns: { type: 'array', items: { type: 'string' }, description: 'Campaign URNs' }, dateRange: { type: 'object', description: 'Analytics date range' }, fields: { type: 'array', items: { type: 'string' }, description: 'Metrics to retrieve' }, pivot: { type: 'string', description: 'Pivot dimension' } }, required: ['campaigns', 'dateRange'] } }, { name: 'linkedin_ads_get_targeting_facets', description: 'Get available targeting options', inputSchema: { type: 'object', properties: { facetType: { type: 'string', enum: ['LOCATIONS', 'INDUSTRIES', 'JOB_FUNCTIONS', 'SENIORITIES', 'SKILLS', 'COMPANIES'], description: 'Type of targeting facet' }, locale: { type: 'string', description: 'Locale for results' } }, required: ['facetType'] } }, // TALENT SOLUTIONS APIs { name: 'linkedin_jobs_post', description: 'Post a job to LinkedIn', inputSchema: { type: 'object', properties: { companyId: { type: 'string', description: 'Company URN' }, title: { type: 'string', description: 'Job title' }, description: { type: 'string', description: 'Job description' }, location: { type: 'object', description: 'Job location' }, employmentType: { type: 'string', enum: ['FULL_TIME', 'PART_TIME', 'CONTRACT', 'TEMPORARY', 'INTERNSHIP'], description: 'Employment type' }, workRemoteAllowed: { type: 'boolean', description: 'Remote work allowed' }, salary: { type: 'object', description: 'Salary information' }, applyMethod: { type: 'object', description: 'How to apply' } }, required: ['companyId', 'title', 'description', 'location'] } }, { name: 'linkedin_jobs_search', description: 'Search for jobs on LinkedIn', inputSchema: { type: 'object', properties: { keywords: { type: 'string', description: 'Job search keywords' }, location: { type: 'object', description: 'Location filter' }, company: { type: 'string', description: 'Company filter' }, datePosted: { type: 'string', description: 'Date posted filter' }, experienceLevel: { type: 'string', description: 'Experience level filter' } } } }, { name: 'linkedin_talent_unified_search', description: 'Enhanced talent search (2025 feature)', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query' }, facets: { type: 'object', description: 'Search facets' }, sortBy: { type: 'string', description: 'Sort criteria' } }, required: ['query'] } }, // LEARNING APIs { name: 'linkedin_learning_get_courses', description: 'Get LinkedIn Learning courses', inputSchema: { type: 'object', properties: { q: { type: 'string', enum: ['search', 'updated'], description: 'Query type' }, keywords: { type: 'string', description: 'Search keywords' }, classification: { type: 'string', description: 'Content classification' }, start: { type: 'number', description: 'Pagination start' }, count: { type: 'number', description: 'Number of results' } } } }, { name: 'linkedin_learning_get_classifications', description: 'Get learning content taxonomy', inputSchema: { type: 'object', properties: { classificationType: { type: 'string', description: 'Type of classification' } } } }, // MESSAGING APIs { name: 'linkedin_messaging_send_message', description: 'Send direct message (first-degree connections only)', inputSchema: { type: 'object', properties: { recipients: { type: 'array', items: { type: 'string' }, description: 'Recipient URNs' }, subject: { type: 'string', description: 'Message subject' }, body: { type: 'string', description: 'Message body' }, attachments: { type: 'array', description: 'Message attachments' } }, required: ['recipients', 'body'] } }, { name: 'linkedin_messaging_get_conversations', description: 'Get message conversations', inputSchema: { type: 'object', properties: { participantId: { type: 'string', description: 'Conversation participant' }, start: { type: 'number', description: 'Pagination start' }, count: { type: 'number', description: 'Number of conversations' } } } }, // EVENTS APIs { name: 'linkedin_events_create', description: 'Create LinkedIn event', inputSchema: { type: 'object', properties: { organizer: { type: 'string', description: 'Event organizer URN' }, name: { type: 'string', description: 'Event name' }, description: { type: 'string', description: 'Event description' }, startTime: { type: 'string', description: 'Event start time (ISO 8601)' }, endTime: { type: 'string', description: 'Event end time (ISO 8601)' }, location: { type: 'object', description: 'Event location' }, eventType: { type: 'string', enum: ['ONLINE', 'OFFLINE'], description: 'Event type' } }, required: ['organizer', 'name', 'startTime', 'endTime'] } }, { name: 'linkedin_events_get', description: 'Get LinkedIn events', inputSchema: { type: 'object', properties: { eventId: { type: 'string', description: 'Specific event ID' }, organizer: { type: 'string', description: 'Filter by organizer' }, start: { type: 'number', description: 'Pagination start' }, count: { type: 'number', description: 'Number of events' } } } }, // SALES NAVIGATOR APIs (Limited Availability) { name: 'linkedin_sales_navigator_profile_association', description: 'Sales Navigator profile association', inputSchema: { type: 'object', properties: { profileId: { type: 'string', description: 'LinkedIn profile ID' }, associationType: { type: 'string', description: 'Type of association' } }, required: ['profileId'] } }, // COMPLIANCE APIs { name: 'linkedin_compliance_get_events', description: 'Get compliance events for monitoring', inputSchema: { type: 'object', properties: { eventType: { type: 'string', description: 'Type of compliance event' }, timeRange: { type: 'object', description: 'Time range for events' } } } }, // RATE LIMITING & UTILITY { name: 'linkedin_get_rate_limits', description: 'Check current rate limit status', inputSchema: { type: 'object', properties: { apiCategory: { type: 'string', description: 'Specific API category to check' } } } }, { name: 'linkedin_get_api_health', description: 'Check LinkedIn API health status', inputSchema: { type: 'object', properties: {} } } ]; // Handler for listing available tools server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => { return { tools: LINKEDIN_API_TOOLS, }; }); // Handler for tool execution server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { // Route to appropriate API handler based on tool name switch (name) { // Authentication tools case 'linkedin_oauth_get_auth_url': return await linkedinClient.getAuthorizationUrl(args); case 'linkedin_oauth_exchange_code': return await linkedinClient.exchangeCodeForToken(args); case 'linkedin_oauth_refresh_token': return await linkedinClient.refreshAccessToken(args); // Profile & People APIs case 'linkedin_people_get_profile': return await linkedinClient.people.getProfile(args); case 'linkedin_people_search_members': return await linkedinClient.people.searchMembers(args); // Organizations APIs case 'linkedin_organizations_get_company': return await linkedinClient.organizations.getCompany(args); case 'linkedin_organizations_get_follower_stats': return await linkedinClient.organizations.getFollowerStats(args); // Content APIs case 'linkedin_posts_create': return await linkedinClient.content.createPost(args); case 'linkedin_posts_get': return await linkedinClient.content.getPosts(args); case 'linkedin_posts_update': return await linkedinClient.content.updatePost(args); case 'linkedin_posts_delete': return await linkedinClient.content.deletePost(args); case 'linkedin_ugc_create': return await linkedinClient.content.createUGCPost(args); case 'linkedin_assets_upload': return await linkedinClient.content.uploadAsset(args); case 'linkedin_assets_get_upload_url': return await linkedinClient.content.getUploadUrl(args); // Social Actions APIs case 'linkedin_social_actions_like': return await linkedinClient.socialActions.like(args); case 'linkedin_social_actions_comment': return await linkedinClient.socialActions.comment(args); case 'linkedin_social_actions_share': return await linkedinClient.socialActions.share(args); // Marketing APIs case 'linkedin_ads_create_campaign': return await linkedinClient.marketing.createCampaign(args); case 'linkedin_ads_get_campaigns': return await linkedinClient.marketing.getCampaigns(args); case 'linkedin_ads_update_campaign': return await linkedinClient.marketing.updateCampaign(args); case 'linkedin_ads_get_analytics': return await linkedinClient.marketing.getAnalytics(args); case 'linkedin_ads_get_targeting_facets': return await linkedinClient.marketing.getTargetingFacets(args); // Talent APIs case 'linkedin_jobs_post': return await linkedinClient.talent.postJob(args); case 'linkedin_jobs_search': return await linkedinClient.talent.searchJobs(args); case 'linkedin_talent_unified_search': return await linkedinClient.talent.unifiedSearch(args); // Learning APIs case 'linkedin_learning_get_courses': return await linkedinClient.learning.getCourses(args); case 'linkedin_learning_get_classifications': return await linkedinClient.learning.getClassifications(args); // Messaging APIs case 'linkedin_messaging_send_message': return await linkedinClient.messaging.sendMessage(args); case 'linkedin_messaging_get_conversations': return await linkedinClient.messaging.getConversations(args); // Events APIs case 'linkedin_events_create': return await linkedinClient.events.createEvent(args); case 'linkedin_events_get': return await linkedinClient.events.getEvents(args); // Sales Navigator APIs case 'linkedin_sales_navigator_profile_association': return await linkedinClient.salesNavigator.profileAssociation(args); // Compliance APIs case 'linkedin_compliance_get_events': return await linkedinClient.compliance.getEvents(args); // Utility APIs case 'linkedin_get_rate_limits': return await linkedinClient.getRateLimits(args); case 'linkedin_get_api_health': return await linkedinClient.getApiHealth(args); default: throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown LinkedIn API tool: ${name}`); } } catch (error) { if (error instanceof types_js_1.McpError) throw error; throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Error executing LinkedIn API tool ${name}: ${error}`); } }); // Start the server async function main() { const transport = new stdio_js_1.StdioServerTransport(); await server.connect(transport); console.error('LinkedIn API MCP server running on stdio'); } main().catch((error) => { console.error('Fatal error:', error); process.exit(1); }); //# sourceMappingURL=linkedin-api-mcp.js.map