ContentIn — LinkedIn Ghostwriter
What this MCP does
Creates LinkedIn post ideas and drafts in a user's voice, stores content, attaches images, schedules or publishes posts, and retrieves post analytics.
Tools
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['post_id', 'images'], 'properties': {'mode': {'enum': ['replace', 'append'], 'type': 'string', 'description': "'replace' (default) â\x80\x94 the post's images become exactly these, and the previous ones are deleted. 'append' â\x80\x94 keep what is there and add these, total still capped at 5."}, 'images': {'type': 'array', 'items': {'type': 'object', 'properties': {'url': {'type': 'string', 'description': 'A public http(s) URL pointing straight at the image file. Not a page that contains an image, and not a private or internal address.'}, 'base64': {'type': 'string', 'description': 'The image encoded as base64 (a data: URI is accepted too). Use this when you hold the bytes rather than a link. Keep it under 8 MB decoded.'}, 'filename': {'type': 'string', 'description': "Optional original filename, used as the file's label in ContentIn."}, 'mime_type': {'type': 'string', 'description': 'image/jpeg, image/png or image/webp, for the base64 form. Advisory only â\x80\x94 ContentIn checks the actual file contents and refuses anything that is not one of those three.'}}, 'additionalProperties': False}, 'maxItems': 5, 'minItems': 1, 'description': 'The images, in the order they should appear on LinkedIn. Exactly one of url or base64 per entry. Maximum 5.'}, 'post_id': {'type': 'integer', 'description': 'The ContentIn post id (from list_posts or write_post_in_my_voice). The post must not be published yet.'}, 'alt_texts': {'type': 'array', 'items': {'type': 'string'}, 'description': "Optional alt text per image, same order and same length as images. Describe what is actually in the picture, in the user's language, 300 characters or fewer."}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['content_pillar', 'substance_type', 'content'], 'properties': {'content': {'type': 'string', 'minLength': 1, 'description': "The substance itself, cleaned into one clear self-contained piece â\x80\x94 but in the user's own words and with their own specifics intact. Do not generalise the detail out of it."}, 'content_pillar': {'type': 'string', 'minLength': 1, 'description': "The content pillar's name or id. The name is fine â\x80\x94 it is matched either way."}, 'substance_type': {'enum': ['stories', 'opinions', 'data_points', 'frameworks'], 'type': 'string', 'description': 'stories = personal or client anecdotes; opinions = beliefs and contrarian takes; data_points = numbers, metrics, results; frameworks = step-by-step processes and mental models.'}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['topic'], 'properties': {'count': {'type': 'integer', 'maximum': 10, 'minimum': 1, 'description': 'How many ideas (1-10, default 5).'}, 'style': {'enum': ['authority', 'proof', 'growth'], 'type': 'string', 'description': 'Optional. Omit to get a mix across all three styles, which is usually what the user wants.'}, 'topic': {'type': 'string', 'minLength': 1, 'description': 'The topic or theme to generate ideas about.'}, 'content_pillar': {'type': 'string', 'description': "Name of one of the user's content pillars that matches this topic. Omit if none fits."}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['post_id'], 'properties': {'post_id': {'type': 'integer', 'description': 'The ContentIn post id, from list_posts.'}, 'include_history': {'type': 'boolean', 'description': 'Include the metric time-series (up to 60 snapshots) instead of just the latest figures. Default false.'}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'sort': {'enum': ['last_interacted', 'icp_score', 'total_interactions'], 'type': 'string', 'description': "Ordering, always descending. Default 'last_interacted' (most recent engagement first)."}, 'limit': {'type': 'integer', 'maximum': 100, 'minimum': 1, 'description': 'How many leads to return (1-100, default 50).'}, 'before': {'anyOf': [{'type': ['string', 'number']}, {'type': 'null'}], 'description': 'Paging cursor: pass back the next_before value from the previous response, VERBATIM, together with before_id. Do not build this yourself, and do not reuse a cursor across a different sort or filter set.'}, 'search': {'type': 'string', 'description': "Free-text match against the lead's name and headline."}, 'status': {'type': 'array', 'items': {'enum': ['new', 'contacted', 'snoozed', 'dismissed', 'converted'], 'type': 'string'}, 'description': "Filter by the user's lead funnel state. Default is everything EXCEPT 'dismissed' â\x80\x94 the user already said no to those, so ask for them explicitly if you really need them."}, 'before_id': {'type': 'string', 'description': 'Paging cursor: the next_before_id from the previous response. Always send it alongside before, otherwise leads sharing a score or a timestamp can be skipped.'}, 'min_icp_score': {'type': 'integer', 'maximum': 100, 'minimum': 0, 'description': "Only leads scoring at least this (0-100). Applied to the user's override where they set one, otherwise to ContentIn's score. Leads that have not been scored yet are excluded by this filter."}, 'interacted_since': {'type': 'string', 'description': 'ISO-8601 date. Only leads who engaged on or after this.'}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'to': {'type': 'string', 'description': 'ISO-8601 date. Only comments written on or before this.'}, 'from': {'type': 'string', 'description': 'ISO-8601 date. Only comments written on or after this.'}, 'limit': {'type': 'integer', 'maximum': 100, 'minimum': 1, 'description': 'How many comments to return (1-100, default 50).'}, 'before': {'type': ['string', 'null'], 'description': 'Paging cursor: pass back the next_before value from the previous response, VERBATIM, together with before_id. Do not build this yourself and do not reuse a cursor from a different query â\x80\x94 it is only valid for the same filters and sort.'}, 'search': {'type': 'string', 'description': 'Free-text match against the comment text and the excerpt of the post it was left on.'}, 'before_id': {'type': 'integer', 'description': 'Paging cursor: the next_before_id from the previous response. Always send it alongside before, otherwise comments written in the same second can be skipped.'}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'to': {'type': 'string', 'description': 'ISO-8601 date. Only posts created on or before this.'}, 'from': {'type': 'string', 'description': 'ISO-8601 date. Only posts created on or after this.'}, 'limit': {'type': 'integer', 'maximum': 50, 'minimum': 1, 'description': 'How many posts to return (1-50, default 20).'}, 'search': {'type': 'string', 'description': 'Free-text match against the post body and title.'}, 'status': {'type': 'array', 'items': {'enum': ['idea', 'suggestion', 'planned', 'draft', 'scheduled', 'posted', 'declined'], 'type': 'string'}, 'description': "Filter by post status. Omit for all statuses. 'draft' = written but not queued, 'scheduled' = queued for automatic publishing, 'posted' = already live on LinkedIn, 'planned' = a slot the ContentIn week planner has reserved (it holds a brief, not a finished post â\x80\x94 it CANNOT be scheduled or published until the user turns it into a draft in ContentIn)."}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'properties': {'post_id': {'type': 'integer', 'description': 'A ContentIn post id (from list_posts or write_post_in_my_voice).'}, 'post_content': {'type': 'string', 'description': 'Full post text the user wrote in this conversation. Saved as a ContentIn draft first â\x80\x94 nothing is ever published without a post record. Ignored when post_id is provided.'}, 'confirm_token': {'type': 'string', 'description': 'The token from the previous confirmation_required response. Omit on the first call.'}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['new_angle', 'style'], 'properties': {'style': {'enum': ['authority', 'proof', 'growth'], 'type': 'string', 'description': 'Writing style. Infer it from the material: results / case studies / client wins = proof, educational / frameworks = authority, viral / trending / broad-resonance = growth.'}, 'post_id': {'type': 'integer', 'description': 'A ContentIn post id (from list_posts). Its current body is read from ContentIn and used as the original.'}, 'new_angle': {'type': 'string', 'minLength': 1, 'description': 'What should change: the new angle, perspective, focus or audience. Be specific about what to keep and what to shift.'}, 'original_post': {'type': 'string', 'description': 'The full text of a post that is NOT in ContentIn. Ignored when post_id is provided and resolves.'}, 'content_pillar': {'type': 'string', 'description': 'Name of the content pillar this belongs to, so the draft is tagged correctly.'}, 'user_constraints': {'type': 'string', 'description': 'Stated user preferences that override defaults for this post.'}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['post_time'], 'properties': {'title': {'type': 'string', 'description': "Optional internal label for the user's ContentIn list. This is NEVER shown on LinkedIn."}, 'post_id': {'type': 'integer', 'description': 'A ContentIn post id (from list_posts or write_post_in_my_voice).'}, 'post_time': {'type': 'string', 'minLength': 1, 'description': "When to publish. ISO-8601 WITH AN EXPLICIT UTC OFFSET, e.g. 2026-08-04T09:00:00+02:00, or 2026-08-04T07:00:00Z. A naive local time (2026-08-04T09:00:00) is REJECTED â\x80\x94 ContentIn cannot know the user's timezone, so guessing would publish hours off. If you don't know their offset, ask."}, 'post_content': {'type': 'string', 'description': 'Full post text, when it is not already in ContentIn. Ignored when post_id is provided.'}, 'confirm_token': {'type': 'string', 'description': 'The token from the previous confirmation_required response. Omit on the first call.'}}, 'additionalProperties': False}
Input schema
{'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['user_idea', 'style'], 'properties': {'style': {'enum': ['authority', 'proof', 'growth'], 'type': 'string', 'description': 'Writing style. Infer it from the material: results / case studies / client wins = proof, educational / frameworks = authority, viral / trending / broad-resonance = growth.'}, 'user_idea': {'type': 'string', 'minLength': 1, 'description': "The user's complete description of the post they want, in THEIR words. Include their full intent, context, specific details, names and numbers. Verbatim is better than tidy."}, 'user_constraints': {'type': 'string', 'description': "Any preferences the user has stated that override defaults â\x80\x94 e.g. 'no hashtags', 'no call to action, this is a connection post', 'keep it under 800 characters'. These take priority over their usual voice defaults."}}, 'additionalProperties': False}
Recent tool changes
Similar MCP servers
mcp
Searches YouTube sponsors and channels, identifies sponsorship relationships, and supports advertiser and creator discovery and a…
Cadencz
Uses website context to plan, draft, schedule, publish and analyze social media posts across connected channels.
autowhisper-mcp
Uses an AI marketing workspace to generate, review, publish, and measure advertising and social content across connected platform…
hooklayer
Analyzes short-form creators and videos, researches trends and viral templates, scores hooks and scripts, tracks creator changes,…
Shorti
Finds short-form video trends and formats, explains how videos were made, and supports creator checks and brand campaign planning.
LinkedIn Content Planner
Drafts, revises, and reviews LinkedIn posts with human approval before publication.
Social Fetch
Retrieves public content and metadata from social networks, music services, Facebook Marketplace, events, profiles, posts, commen…
Hermoso
Supports ad research, competitor analysis, video and static ad creation, campaign policy checks, content publishing, and performa…