Skip to main content
Glama

LinkedIn Content Creation MCP Server

by chrishayuk
draft_tools.py7.39 kB
# src/chuk_mcp_linkedin/tools/draft_tools.py """ Draft management tools for LinkedIn posts. Handles CRUD operations for draft posts. All tools require OAuth authorization to prevent server abuse and enable user-scoped data persistence across sessions. User Isolation: - Protocol handler sets user_id in context from OAuth token - get_current_manager() retrieves user-specific manager from context - No cross-user access possible - all operations are scoped to user_id - No need to pass _user_id parameter - it's automatic! """ import json from typing import Any, Dict, Optional from chuk_mcp_server.decorators import requires_auth from ..manager_factory import get_current_manager def register_draft_tools(mcp: Any) -> Dict[str, Any]: """Register draft management tools with the MCP server""" @mcp.tool # type: ignore[misc] @requires_auth() async def linkedin_create( name: str, post_type: str, theme: Optional[str] = None, _external_access_token: Optional[str] = None, ) -> str: """ Create a new LinkedIn post draft. Args: name: Draft name/identifier post_type: Type of LinkedIn post (text, document, poll, video, carousel, image) theme: Optional theme name Returns: Success message with draft ID """ manager = get_current_manager() draft = manager.create_draft( name=name, post_type=post_type, theme=theme, ) return f"Created draft '{draft.name}' (ID: {draft.draft_id})" @mcp.tool # type: ignore[misc] @requires_auth() async def linkedin_list(_external_access_token: Optional[str] = None) -> str: """ List all draft posts for the authenticated LinkedIn user. Returns: JSON list of all drafts with metadata """ manager = get_current_manager() drafts = manager.list_drafts() return json.dumps(drafts, indent=2) @mcp.tool # type: ignore[misc] @requires_auth() async def linkedin_switch( draft_id: str, _external_access_token: Optional[str] = None, ) -> str: """ Switch to a different draft. Args: draft_id: Draft ID to switch to Returns: Success or error message """ manager = get_current_manager() success = manager.switch_draft(draft_id) if success: return f"Switched to draft {draft_id}" return f"Draft {draft_id} not found" @mcp.tool # type: ignore[misc] @requires_auth() async def linkedin_get_info( draft_id: Optional[str] = None, _external_access_token: Optional[str] = None, ) -> str: """ Get detailed information about a draft. Args: draft_id: Draft ID (optional, uses current if not provided) Returns: JSON with draft details and stats """ manager = get_current_manager() draft_id = draft_id or manager.current_draft_id draft = manager.get_draft(draft_id) if draft_id else None if draft and draft_id: stats = manager.get_draft_stats(draft_id) info = {**draft.to_dict(), "stats": stats} return json.dumps(info, indent=2) return "No draft found" @mcp.tool # type: ignore[misc] @requires_auth() async def linkedin_delete( draft_id: str, _external_access_token: Optional[str] = None, ) -> str: """ Delete a draft. Args: draft_id: Draft ID to delete Returns: Success or error message """ manager = get_current_manager() success = manager.delete_draft(draft_id) if success: return f"Deleted draft {draft_id}" return f"Draft {draft_id} not found" @mcp.tool # type: ignore[misc] @requires_auth() async def linkedin_clear_all(_external_access_token: Optional[str] = None) -> str: """ Clear all drafts for the authenticated LinkedIn user. Returns: Count of drafts cleared """ manager = get_current_manager() count = manager.clear_all_drafts() return f"Cleared {count} drafts" @mcp.tool # type: ignore[misc] @requires_auth() async def linkedin_preview_url( draft_id: Optional[str] = None, base_url: Optional[str] = None, expires_in: int = 3600, _external_access_token: Optional[str] = None, ) -> str: """ Generate a shareable preview URL for a draft. Returns a URL that can be shared with anyone: - For S3/cloud storage: Returns a signed URL that expires after the specified time - For memory/filesystem: Returns a token-based URL (no expiration) No authentication required to view the preview. NOTE: For token-based URLs (memory/filesystem), the server must be running in HTTP mode. If using STDIO mode (e.g., MCP CLI), start a separate HTTP server with: linkedin-mcp http --port 8000 Args: draft_id: Draft ID (optional, uses current if not provided) base_url: Base URL of the server (optional, auto-detected from OAUTH_SERVER_URL or defaults to http://localhost:8000) expires_in: Expiration time in seconds for signed URLs (default: 3600 = 1 hour) Returns: Shareable preview URL or error message """ import os manager = get_current_manager() draft_id = draft_id or manager.current_draft_id if not draft_id: return "Error: No draft selected" # Auto-detect base_url from OAUTH_SERVER_URL environment variable if not provided if base_url is None: base_url = os.getenv("OAUTH_SERVER_URL", "http://localhost:8000") # Generate preview URL using manager's method preview_url = await manager.generate_preview_url( draft_id=draft_id, base_url=base_url, expires_in=expires_in ) if not preview_url: return "Error: Failed to generate preview URL" draft = manager.get_draft(draft_id) storage_type = ( "signed URL (S3)" if manager.artifact_provider in ("s3", "ibm-cos") else "token-based URL" ) return ( f"Preview URL: {preview_url}\n\n" f"Draft: {draft.name if draft else 'Unknown'}\n" f"Draft ID: {draft_id}\n" f"URL Type: {storage_type}\n\n" "This URL is shareable and does not require authentication.\n" "Open this URL in your browser to view the formatted preview.\n\n" f"{'NOTE: Signed URL expires in ' + str(expires_in) + ' seconds' if manager.artifact_provider in ('s3', 'ibm-cos') else 'NOTE: If the URL returns Not Found, run the server in HTTP mode: linkedin-mcp http --port 8000'}" ) return { "linkedin_create": linkedin_create, "linkedin_list": linkedin_list, "linkedin_switch": linkedin_switch, "linkedin_get_info": linkedin_get_info, "linkedin_delete": linkedin_delete, "linkedin_clear_all": linkedin_clear_all, "linkedin_preview_url": linkedin_preview_url, }

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/chrishayuk/chuk-mcp-linkedin'

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