inseeqdocs
Go to App

MCP Server API Reference

Connect AI agents to your inseeq organization using the Model Context Protocol (MCP).

Authentication

All requests require a valid API key passed as a Bearer token in the Authorization header.

Generating an API Key

  1. Log in to the inseeq app at https://app.staging.inseeq.com
  2. Navigate to Settings in the sidebar
  3. Click the API Keys tab
  4. Click Generate API Key
  5. Copy the key — it will be visible on this page whenever you need it

Each organization can have one API key. You can regenerate or delete it at any time from the same page.

Using Your API Key

Pass the key as a Bearer token in the Authorization header of every request:

Authorization header
Authorization: Bearer inseeq_your_api_key_here

Your API key is scoped to your organization. All operations are automatically filtered to your org's data.

Endpoint

The MCP server accepts JSON-RPC requests over HTTP POST. It follows the Model Context Protocol specification with Streamable HTTP transport.

Endpoint
POST https://api.staging.inseeq.com/mcp
Content-Type: application/json
Accept: application/json, text/event-stream
Authorization: Bearer inseeq_your_api_key_here

The server operates in stateless mode — each request is independent. No session management is required.

Quick Test

Verify your API key works by sending an initialize request:

Example request
curl -X POST https://api.staging.inseeq.com/mcp \
  -H "Authorization: Bearer INSEEQ_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'
Expected response
event: message
data: {"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"inseeq","version":"0.1.0"}},"jsonrpc":"2.0","id":1}

Permissions

Your API key grants access to the following capabilities:

CapabilityAccess
Read organization & brand profileAllowed
List, read, create, update articlesAllowed
Change article statusAllowed
List, add, resolve commentsAllowed
Read, write, sync context (knowledge base)Allowed
Read performance metrics & goalsAllowed
Upload imagesAllowed
Publish to CMS (WordPress, Webflow, etc.)Allowed
Send email notificationsNot available

Rate Limits

API keys are rate-limited to 60 requests per minute. If you exceed this limit, the server returns a 429 error. Implement exponential backoff: wait 1s, then 2s, then 4s before retrying. Most MCP clients handle this automatically.

Error Responses

All errors follow the standard MCP JSON-RPC error format. The message field contains a human-readable description of what went wrong.

Error response format
{
  "error": {
    "code": -32602,
    "message": "Article not found"
  }
}
HTTP StatusMeaningCommon Causes
401UnauthorizedMissing or invalid API key
403ForbiddenWriting to a frozen or human_only context entry; calling an internal-only tool
404Not FoundArticle, comment, or context entry does not exist
422Validation ErrorInvalid parameter type, missing required field, or invalid status transition
429Rate LimitedExceeded 60 requests/minute — back off and retry
500Server ErrorInternal error — retry once, then contact support

Article Status Lifecycle

Articles and LinkedIn posts progress through a linear workflow. Use inseeq_update_article_status to transition between states. Calendar events do not use this flow — they have their own two-state toggle (scheduleddone) via inseeq_update_event_status.

Status flow
draft → ready_to_write → writing → generating → in_review → approved → published

You can move articles forward or backward through this workflow. Some transitions trigger automatic side effects:

Transition toSide effect
writingSets writing_started_at timestamp
in_reviewSends review request emails to org reviewers; sets review_requested_at
approvedSets approved_at and approved_by
publishedSets published_at and published_by

To publish to a CMS, first transition to approved, then call inseeq_publish_article.

Article URLs

Every article response includes an app_url field — the direct link to view or edit the article in inseeq. Use this when sharing links with users.

URL format
https://app.inseeq.com/review/{article_id}

The app_url field is returned on every article object in inseeq_list_articles, inseeq_get_article, and inseeq_create_article.

Tools Reference

Each tool is called via the MCP protocol. Your MCP client handles the JSON-RPC framing — you just need to know the tool names and parameters.

Identity

inseeq_agent_whoami

Returns the authenticated agent's identity and organization binding. Call this first to get your organization_id.

No parameters

Response

{
  "agent_id": "a1b2c3d4-...",
  "agent_name": "My Agent",
  "organization_id": "org-uuid-...",
  "key_type": "external"
}

Organization

inseeq_get_organization

Get organization details by ID.

ParameterTypeRequiredDescription
organization_idstring (UUID)YesYour organization ID (from inseeq_agent_whoami)

Response

{
  "id": "org-uuid-...",
  "name": "Acme Corp",
  "slug": "acme-corp",
  "settings": { ... },
  "created_at": "2025-01-01T00:00:00Z",
  "updated_at": "2025-03-15T12:00:00Z"
}

inseeq_get_brand_profile

Get the brand profile for an organization — voice, tone, vocabulary rules, and writing guidelines.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes

Response

{
  "profile": {
    "id": "uuid",
    "organization_id": "uuid",
    "brand_voice": "Professional yet approachable...",
    "tone_guidelines": "Use active voice...",
    "vocabulary_rules": "Never use 'synergy'..."
  }
}

inseeq_resolve_slack_channel

Look up which inseeq organization a Slack channel is mapped to.

ParameterTypeRequiredDescription
slack_channel_idstringYesSlack channel ID (e.g. C01234ABCDE)
workspace_idstringNoSlack workspace ID for disambiguation

Response

{
  "organization_id": "org-uuid-...",
  "agent_name": "My Agent",
  "external_channel_id": "C01234ABCDE",
  "external_workspace_id": "T01234ABCDE",
  "github_context_repo": "acme/content-repo"
}

Articles

Three content types, three tool surfaces

Inseeq manages three content types with separate tool surfaces:

  • Articles — long-form blog content with SEO fields, single featured image, CMS publishing. Use the article tools below.
  • LinkedIn Posts — social posts with a multi-image carousel (up to 20), no SEO fields, no CMS publishing. See the LinkedIn Posts section.
  • Calendar Events — lightweight markers for podcasts, press releases, and custom events. No publishing, no images, no comments. See the Calendar Events section.

The list/get/create/update tools are type-specific and reject IDs of the wrong type with a clear pointer to the correct tool. inseeq_update_article_status handles the article workflow (draft → published); events use the dedicated inseeq_update_event_status (scheduled ↔ done). Comments and image uploads work for articles and LinkedIn posts only — events reject both.

Pagination

inseeq_list_articles returns { articles: [...], total: N }. If total exceeds your limit, paginate by incrementing offset:

  • Page 1: limit=100, offset=0
  • Page 2: limit=100, offset=100
  • Continue until offset >= total

inseeq_list_articles

List long-form articles for your organization, optionally filtered by status. Returns up to 100 items by default. For LinkedIn posts, use inseeq_list_linkedin_posts.

ParameterTypeRequiredDescription
organization_idstring (UUID)YesYour organization ID
statusstringNoFilter: draft, ready_to_write, writing, generating, in_review, approved, published
limitnumber (1–1000)NoMax items per page (default: 100)
offsetnumberNoSkip this many items for pagination (default: 0)

Response

{
  "articles": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "title": "Getting Started with SEO",
      "description": "A beginner's guide to search engine optimization",
      "meta_description": "Learn the fundamentals of SEO...",
      "status": "in_review",
      "word_count": 1850,
      "language": "English",
      "created_at": "2025-01-15T10:30:00Z",
      "updated_at": "2025-02-01T14:22:00Z",
      "scheduled_publish_date": null,
      "target_keyword": "seo basics",
      "outline": "## Introduction\n## What is SEO?\n...",
      "cluster_topic": "SEO Fundamentals",
      "unresolved_comment_count": 2,
      "app_url": "https://app.inseeq.com/review/3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "total": 42
}

inseeq_get_article

Get a long-form article by ID. The `format` parameter controls body inclusion: 'markdown' (default) returns rendered content, 'structured' returns intro/sections/sources, 'metadata' omits the body entirely. Rejects LinkedIn post IDs with a pointer to inseeq_get_linkedin_post.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
format'markdown' | 'structured' | 'metadata'NoBody format. Default: 'markdown' (metadata + rendered content). 'structured' returns intro/sections/sources instead of content. 'metadata' omits the body.

Default ('markdown') returns the 28 metadata columns plus the rendered `content` field. 'structured' swaps `content` for `intro`, `sections`, `sources`. 'metadata' returns no body. The `research` and `generation_costs` columns are always excluded.

Response

// Default — format='markdown':
{
  "article": {
    "id": "uuid",
    "title": "Getting Started with SEO",
    "content_type": "article",
    "status": "in_review",
    "word_count": 1850,
    "version": 3,
    "content": "# Getting Started with SEO\n\nSEO stands for...",
    "excerpt": "A beginner's guide...",
    "description": "Internal brief for the writing team",
    "meta_description": "Learn the fundamentals of SEO...",
    "seo_title": "SEO Basics: A Complete Guide",
    "focus_keyphrase": "seo basics",
    "wordpress_slug": "seo-basics-guide",
    "featured_image_url": "https://...",
    "featured_image_alt_text": "SEO diagram",
    "language": "English",
    "language_code": "en",
    "target_keyword": "seo basics",
    "outline": "## Introduction\n...",
    "cluster_topic": "SEO Fundamentals",
    "scheduled_publish_date": null,
    "wordpress_post_id": null,
    "wordpress_post_url": null,
    "app_url": "https://app.inseeq.com/review/article-uuid",
    "created_at": "2025-01-15T10:30:00Z",
    "updated_at": "2025-02-01T14:22:00Z"
  }
}

// format='structured':
// Same metadata columns, but swaps the content field for:
//   "intro": "SEO stands for Search Engine Optimization...",
//   "sections": [ { "heading": "...", "content": "..." }, ... ],
//   "sources": "- [Google Search Central](https://...)"

// format='metadata':
// Same structure but content / intro / sections / sources
// are all omitted.

inseeq_create_article

Create a new long-form article in draft status. For LinkedIn posts, use inseeq_create_linkedin_post instead.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
titlestringYesArticle title (min 1 character)
contentstringNoFull markdown content
excerptstringNoArticle summary/excerpt
descriptionstringNoInternal brief
meta_descriptionstringNoSEO meta description
seo_titlestringNoSEO title tag
slugstringNoCustom URL slug
focus_keyphrasestringNoSEO focus keyphrase
languagestringNoLanguage name (default: English)
language_codestringNoLanguage code (default: en)
featured_image_urlstringNoFeatured image URL
featured_image_alt_textstringNoImage alt text
featured_image_titlestringNoImage title attribute
featured_image_captionstringNoImage caption
featured_image_descriptionstringNoImage description
scheduled_publish_datestring (ISO 8601)NoWhen to publish
target_keywordstringNoPrimary target keyword
outlinestringNoArticle outline/structure
cluster_topicstringNoTopic cluster this belongs to

Response

{
  "article": {
    "id": "new-article-uuid",
    "organization_id": "org-uuid",
    "title": "Getting Started with SEO",
    "status": "draft",
    "word_count": 0,
    "version": 1,
    "app_url": "https://app.inseeq.com/review/new-article-uuid",
    "created_at": "2025-03-15T10:00:00Z",
    "updated_at": "2025-03-15T10:00:00Z"
  }
}

Article updates are split across four surgical tools

The legacy inseeq_update_article kitchen-sink tool has been split into four intent-bearing tools below. Each owns one slice of the article: body, metadata, SEO, or featured image. The body writer is the only tool that accepts content and refuses empty bodies — which makes the "image update accidentally wipes the article body" failure mode structurally impossible. The legacy tool still exists as a deprecated routing shim for backward compatibility (see below) but new integrations should target the surgical tools.

inseeq_write_article_body

Write or rewrite the full article body. The only tool that accepts the content field. Refuses empty bodies.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
contentstringYesFull markdown body (auto-parsed into intro/sections/sources). Must be non-empty after H1-strip and trim.

Always pass the complete body — partial-body updates are not supported. If the body is empty after stripping the H1 and surrounding whitespace, the tool refuses with an error and writes nothing. Re-read the draft from disk before calling under context pressure. For LinkedIn posts, use inseeq_update_linkedin_post.

Side effects

  • Always creates a version snapshot in gen_article_versions before writing
  • Version number is incremented
  • Logs an edit_made entry to the article activity audit trail

Response

{
  "article": {
    "id": "article-uuid",
    "title": "Getting Started with SEO",
    "version": 4,
    "word_count": 1842,
    "updated_at": "2025-03-15T14:30:00Z"
  }
}

inseeq_update_article_metadata

Update non-SEO, non-image metadata fields. Snapshots only on title change.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
titlestringNoArticle title (visible to readers)
excerptstringNoArticle summary/excerpt
descriptionstringNoInternal brief / description
languagestringNoLanguage name (default: English)
language_codestringNoLanguage code (default: en)
scheduled_publish_datestring | nullNoISO 8601 date or null to clear
target_keywordstringNoPrimary target keyword
outlinestringNoArticle outline / structure
cluster_topicstringNoTopic cluster this belongs to

Does not accept content — for body changes use inseeq_write_article_body. SEO fields (meta description, focus keyphrase, SEO title, slug) live in inseeq_update_article_seo. Image fields live in inseeq_set_featured_image.

Side effects

  • Creates a version snapshot only when title is in the params
  • Logs an edit_made activity entry only when title is in the params
  • No snapshot or log for metadata-only changes (matches prior behavior)

Response

{
  "article": {
    "id": "article-uuid",
    "title": "Updated Title",
    "version": 4,
    "word_count": 1842,
    "updated_at": "2025-03-15T14:30:00Z"
  }
}

inseeq_update_article_seo

Update SEO-only fields. Never snapshots, never logs.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
meta_descriptionstringNoSEO meta description
focus_keyphrasestringNoSEO focus keyphrase
seo_titlestringNoSEO title tag
slugstringNoCustom URL slug

At least one SEO field must be provided. Does not touch content, metadata, or image fields.

Response

{
  "article": {
    "id": "article-uuid",
    "version": 4,
    "updated_at": "2025-03-15T14:30:00Z"
  }
}

inseeq_set_featured_image

Set or update featured-image fields. Cannot accept content — image updates can never wipe the body.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
featured_image_urlstringNoFeatured image URL
featured_image_alt_textstringNoImage alt text
featured_image_titlestringNoImage title attribute
featured_image_captionstringNoImage caption
featured_image_descriptionstringNoImage description

At least one featured-image field must be provided. The lack of a content parameter is intentional — it makes the historical bug shape (image update with stub content wiping the body) structurally unrepresentable. For body edits, use inseeq_write_article_body.

Response

{
  "article": {
    "id": "article-uuid",
    "version": 4,
    "updated_at": "2025-03-15T14:30:00Z"
  }
}

Deprecated: inseeq_update_article (routing shim)

The original kitchen-sink update tool is preserved as a routing shim that dispatches to the four surgical tools above. New integrations should target the surgical tools directly. The shim refuses any call that mixes content with any featured_image_* field — that combination was the failure shape that motivated this split. Cross-category combinations (for example content + meta_description) are split into sequenced internal calls and are not atomic; if the body write succeeds and the SEO write fails, the article is partially updated.

inseeq_update_article

[deprecated] Routing shim — dispatches to inseeq_write_article_body / inseeq_update_article_metadata / inseeq_update_article_seo / inseeq_set_featured_image. Refuses content + featured_image_* in the same call.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
titlestringNo
contentstringNoFull markdown body. Forwarded to inseeq_write_article_body.
excerptstringNo
descriptionstringNo
languagestringNo
language_codestringNo
meta_descriptionstringNo
seo_titlestringNo
slugstringNo
focus_keyphrasestringNo
featured_image_urlstringNo
featured_image_alt_textstringNo
featured_image_titlestringNo
featured_image_captionstringNo
featured_image_descriptionstringNo
scheduled_publish_datestring | nullNo
target_keywordstringNo
outlinestringNo
cluster_topicstringNo

Deprecated. Migrate to the four surgical tools above. Calls combining content with any featured_image_* field are rejected outright; other multi-category calls are split into sequenced internal dispatches and are not atomic. Behavior across categories matches the surgical tools individually (snapshots on body/title; no snapshot for SEO or image). For LinkedIn posts, use inseeq_update_linkedin_post.

Side effects

  • Refuses with an error if content and any featured_image_* field are both present
  • Forwards body changes to inseeq_write_article_body (with empty-body refusal)
  • Per-delegate snapshot/audit semantics inherit from each surgical tool

Response

{
  "article": {
    "id": "article-uuid",
    "version": 4,
    "updated_at": "2025-03-15T14:30:00Z"
  }
}

inseeq_update_article_status

Change an article's workflow status. See Article Status Lifecycle above for the full flow and side effects.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
statusstringYesdraft, ready_to_write, writing, generating, in_review, approved, published
scheduled_publish_datestring (ISO 8601)NoSet a scheduled publish date

Side effects

  • Transitioning to writing sets writing_started_at
  • Transitioning to in_review sends email notifications to org reviewers
  • Transitioning to approved/published sets timestamp and actor fields
  • All transitions are logged in the article activity audit trail

Response

{
  "article": {
    "id": "article-uuid",
    "status": "in_review",
    "updated_at": "2025-03-15T14:30:00Z",
    "version": 4
  }
}

inseeq_publish_article

Publish an approved article to the organization's active CMS platform (WordPress, Webflow, Contentful, or emdash). Articles only — LinkedIn posts cannot be auto-published and must be posted manually (fetch content + post_images, then post on LinkedIn). Article must be in 'approved' status.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
statusstringNoPost status (WordPress only): publish (default), draft, or pending
categoriesnumber[]NoCategory IDs (WordPress only)
tagsnumber[]NoTag IDs (WordPress only)

The article must be in 'approved' status. Call inseeq_update_article_status first if needed. The categories and tags parameters only apply to WordPress.

Response

{
  "post_id": "12345",
  "url": "https://example.com/blog/seo-basics-guide",
  "platform": "wordpress",
  "published_at": "2025-03-15T15:00:00Z"
}

inseeq_create_image_upload

Create a presigned upload URL for an image attached to an article or LinkedIn post. Returns both the upload URL (PUT binary) and the final public URL in one call. After PUTing the file binary, pass public_url into inseeq_set_featured_image for articles, or include it in post_images[] for inseeq_update_linkedin_post.

ParameterTypeRequiredDescription
content_idstring (UUID)YesArticle or LinkedIn post ID
content_typestringYesimage/png, image/jpeg, image/gif, or image/webp

Single-tool flow: (1) call this; (2) PUT the file binary to upload_url; (3) pass public_url into the relevant update tool. The public URL is deterministic from the storage path, so no separate finalize step is needed. Storage objects live in the article-images bucket at {organization_id}/{content_id}/{uuid}.{ext}.

Response

{
  "upload_url": "https://storage.supabase.co/...?token=...",
  "public_url": "https://storage.inseeq.com/article-images/org-uuid/content-uuid/abc123.png",
  "storage_path": "org-uuid/content-uuid/abc123.png",
  "token": "upload-token",
  "content_type": "image/png"
}

inseeq_delete_article

Delete a long-form article. Irreversible. Deletes the article row and its featured_image_url storage object. External keys can only delete drafts; approved or published articles require an internal/admin key. Rejects LinkedIn post IDs with a pointer to inseeq_delete_linkedin_post.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes

Move the article back to draft first if an external agent needs to delete an approved/published article, or escalate to an Inseeq admin. Inline body images embedded inside content (if any) are NOT auto-deleted — only the featured image. Comments, versions, and activity rows cascade automatically.

Side effects

  • Deletes the storage object at featured_image_url (best-effort)
  • Cascade-deletes gen_article_versions, article_comments, and article_review_activity

Response

{
  "deleted": true,
  "article_id": "uuid"
}

LinkedIn Posts

LinkedIn post workflow

LinkedIn posts share the review/approval lifecycle with articles (draft → in_review → approved → published) but differ in content shape:

  • Body — flat text (no headings/sections). Up to 3,000 characters recommended (LinkedIn's soft limit).
  • Images — ordered array of up to 20 {url, alt_text} objects in the post_images field. Upload via inseeq_create_image_upload first to obtain URLs.
  • No SEO fields — meta_description, slug, focus_keyphrase are not applicable.
  • Manual publishing — LinkedIn posts cannot be auto-published. inseeq_publish_article rejects them. The approved post + images are downloaded by the user and posted manually on LinkedIn.
  • Image cleanup is automatic — when you remove an image URL from post_images via inseeq_update_linkedin_post, the underlying storage object is deleted as part of the update. Deleting the post via inseeq_delete_linkedin_post also removes all referenced storage objects. For uploaded-but-never-attached orphans, use inseeq_delete_linkedin_post_image.

inseeq_list_linkedin_posts

List LinkedIn posts for your organization, optionally filtered by status. Returns up to 100 items by default. For long-form articles, use inseeq_list_articles.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
statusstringNoFilter: draft, ready_to_write, writing, generating, in_review, approved, published
limitnumber (1–1000)NoMax items per page (default: 100)
offsetnumberNoSkip this many items for pagination (default: 0)

Response

{
  "posts": [
    {
      "id": "4a1b2c3d-...",
      "title": "Guess what I just found out...",
      "content": "Guess what I just found out?\n\nThe people behind...",
      "description": null,
      "status": "approved",
      "word_count": 42,
      "language": "English",
      "created_at": "2025-02-10T09:00:00Z",
      "updated_at": "2025-02-11T15:30:00Z",
      "scheduled_publish_date": "2025-02-15T09:00:00Z",
      "post_images": [
        { "url": "https://storage.../01.png", "alt_text": "Diagram" },
        { "url": "https://storage.../02.png", "alt_text": "Chart" }
      ],
      "unresolved_comment_count": 0,
      "app_url": "https://app.inseeq.com/review/4a1b2c3d-..."
    }
  ],
  "total": 8
}

inseeq_get_linkedin_post

Get a LinkedIn post by ID. Returns content, post_images, and metadata. Rejects article IDs with a pointer to inseeq_get_article.

ParameterTypeRequiredDescription
post_idstring (UUID)Yes

Always returns full content (post bodies are short — no format flag needed).

Response

{
  "post": {
    "id": "uuid",
    "title": "Guess what I just found out...",
    "content_type": "linkedin_post",
    "content": "Guess what I just found out?\n\nThe people behind...",
    "description": null,
    "status": "approved",
    "word_count": 42,
    "version": 2,
    "language": "English",
    "language_code": "en",
    "post_images": [
      { "url": "https://storage.../01.png", "alt_text": "Diagram" },
      { "url": "https://storage.../02.png", "alt_text": "Chart" }
    ],
    "scheduled_publish_date": "2025-02-15T09:00:00Z",
    "review_requested_at": "2025-02-10T10:00:00Z",
    "approved_at": "2025-02-11T15:30:00Z",
    "published_at": null,
    "app_url": "https://app.inseeq.com/review/uuid",
    "created_at": "2025-02-10T09:00:00Z",
    "updated_at": "2025-02-11T15:30:00Z"
  }
}

inseeq_create_linkedin_post

Create a new LinkedIn post in draft status. Title is auto-derived from the first non-empty line of content if omitted.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
contentstringNoPost body (plain text or light markdown)
titlestringNoDisplay title. Auto-derived from content if omitted.
post_imagesarray of {url, alt_text}NoOrdered carousel images, max 20. Upload via inseeq_create_image_upload first.
scheduled_publish_datestring (ISO 8601)No
descriptionstringNoInternal brief (not published)
languagestringNoLanguage name (default: English)
language_codestringNoLanguage code (default: en)

Response

{
  "post": {
    "id": "new-post-uuid",
    "organization_id": "org-uuid",
    "content_type": "linkedin_post",
    "title": "Guess what I just found out...",
    "content": "Guess what I just found out?\n\nThe people behind...",
    "post_images": [
      { "url": "https://storage.../01.png", "alt_text": "Diagram" }
    ],
    "status": "draft",
    "version": 1,
    "app_url": "https://app.inseeq.com/review/new-post-uuid",
    "created_at": "2025-03-15T10:00:00Z",
    "updated_at": "2025-03-15T10:00:00Z"
  }
}

inseeq_update_linkedin_post

Update a LinkedIn post. Creates a version snapshot on content/title changes.

ParameterTypeRequiredDescription
post_idstring (UUID)Yes
contentstringNoPost body
titlestringNoExplicit title. If omitted and content is updated, title is auto-derived from the first line.
post_imagesarray of {url, alt_text}NoReplaces the full ordered carousel array. Pass [] to clear all images.
scheduled_publish_datestring | nullNoISO 8601 timestamp, or null to clear

post_images is a full-array replacement — pass the complete desired ordering. There is no partial add/remove/reorder API; for any change, send the full new array.

Side effects

  • Creates a version snapshot before content or title changes
  • Version number is incremented on each update
  • Title auto-refreshes from content when content is updated and title is not supplied
  • Rejects with an error if the provided ID belongs to an article (use inseeq_write_article_body / inseeq_update_article_metadata / inseeq_update_article_seo / inseeq_set_featured_image instead)
  • Storage objects for image URLs dropped from post_images are deleted automatically (best-effort)

Response

{
  "post": {
    "id": "post-uuid",
    "version": 3,
    "updated_at": "2025-03-15T14:30:00Z"
  }
}

inseeq_delete_linkedin_post

Delete a LinkedIn post. Irreversible. Deletes the post row and every storage object referenced by its post_images. External keys can only delete drafts; approved or published posts require an internal/admin key. Rejects article IDs with a pointer to inseeq_delete_article.

ParameterTypeRequiredDescription
post_idstring (UUID)Yes

Move the post back to draft first if an external agent needs to delete an approved/published post, or escalate to an Inseeq admin. Comments, versions, and activity rows cascade automatically.

Side effects

  • Deletes all storage objects referenced by post_images (best-effort)
  • Cascade-deletes gen_article_versions, article_comments, and article_review_activity

Response

{
  "deleted": true,
  "post_id": "uuid"
}

inseeq_delete_linkedin_post_image

Delete a LinkedIn post image from storage by storage_path. Use this for images uploaded via inseeq_create_image_upload that were never attached to the post (orphans).

ParameterTypeRequiredDescription
post_idstring (UUID)Yes
storage_pathstringYesPath returned by inseeq_create_image_upload; must start with {organization_id}/{post_id}/

If the image is still referenced in the post's post_images array, this tool rejects the call — detach it first via inseeq_update_linkedin_post, which handles cleanup automatically. Use this tool only for uploaded-but-never-attached images.

Response

{
  "deleted": true,
  "storage_path": "org/post/uuid.png"
}

Calendar Events

Lightweight calendar markers

Events are calendar items the team uses to plan around things that aren't written content — podcasts they're recording, press releases they're publishing, webinars they're hosting. Compared to articles and LinkedIn posts, events are intentionally minimal:

  • No featured image or carousel
  • No SEO fields, no CMS publishing
  • No version history, no comments
  • Status is a simple two-state toggle: scheduleddone

Three subtypes share one tool family because their shape is uniform — only custom_event carries an extra custom_event_label field for the free-text type label (e.g. "Webinar", "Trade Show").

event_typeDisplay labelNotes
podcastPodcastFixed label
press_releasePress ReleaseFixed label
custom_eventUser-suppliedRequires custom_event_label

The app_url returned on event responses points to /calendar. Events open in an inline edit modal when their card is clicked, so there's no per-event deep link.

inseeq_list_events

List calendar events for your organization. Filter by event_type and/or status. Returns up to 100 items by default. For articles use inseeq_list_articles; for LinkedIn posts use inseeq_list_linkedin_posts.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
event_type'podcast' | 'press_release' | 'custom_event'NoFilter to a single subtype
status'scheduled' | 'done'No
limitnumber (1–1000)NoMax items per page (default: 100)
offsetnumberNoSkip this many items for pagination (default: 0)

Response

{
  "events": [
    {
      "id": "ev-uuid-1",
      "content_type": "podcast",
      "title": "Marketing AI on the Acme Show",
      "content": "Topics: agent workflows, distribution...",
      "status": "scheduled",
      "scheduled_publish_date": "2025-04-20T03:00:00Z",
      "custom_event_label": null,
      "created_at": "2025-03-01T12:00:00Z",
      "updated_at": "2025-03-01T12:00:00Z",
      "app_url": "https://app.inseeq.com/calendar"
    },
    {
      "id": "ev-uuid-2",
      "content_type": "custom_event",
      "title": "Spring Trade Show booth",
      "content": "",
      "status": "scheduled",
      "scheduled_publish_date": "2025-05-10T03:00:00Z",
      "custom_event_label": "Trade Show",
      "created_at": "2025-03-02T09:00:00Z",
      "updated_at": "2025-03-02T09:00:00Z",
      "app_url": "https://app.inseeq.com/calendar"
    }
  ],
  "total": 2
}

inseeq_get_event

Get a calendar event by ID. Rejects IDs belonging to articles or LinkedIn posts with a pointer to the correct tool.

ParameterTypeRequiredDescription
event_idstring (UUID)Yes

Response

{
  "event": {
    "id": "ev-uuid-1",
    "content_type": "podcast",
    "title": "Marketing AI on the Acme Show",
    "content": "Topics: agent workflows, distribution. Host: Jane Doe.",
    "status": "scheduled",
    "scheduled_publish_date": "2025-04-20T03:00:00Z",
    "custom_event_label": null,
    "created_at": "2025-03-01T12:00:00Z",
    "updated_at": "2025-03-01T12:00:00Z",
    "app_url": "https://app.inseeq.com/calendar"
  }
}

inseeq_create_event

Create a calendar event. Events start in 'scheduled' status. For custom_event, custom_event_label is required.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
event_type'podcast' | 'press_release' | 'custom_event'Yes
titlestringYesEvent title
contentstringNoFree-text notes attached to the event
custom_event_labelstringNoRequired for custom_event. Must be omitted for other types.
scheduled_publish_datestring (ISO 8601)NoWhen the event occurs

Events bypass the article workflow entirely — no credits, no review, no version snapshot.

Response

{
  "event": {
    "id": "new-event-uuid",
    "content_type": "custom_event",
    "title": "Spring Trade Show booth",
    "content": "",
    "status": "scheduled",
    "scheduled_publish_date": "2025-05-10T03:00:00Z",
    "custom_event_label": "Trade Show",
    "created_at": "2025-03-02T09:00:00Z",
    "updated_at": "2025-03-02T09:00:00Z",
    "app_url": "https://app.inseeq.com/calendar"
  }
}

inseeq_update_event

Update editable fields on a calendar event: title, content (notes), scheduled date, and (for custom_event only) custom_event_label. Status changes go through inseeq_update_event_status. Rejects non-event IDs.

ParameterTypeRequiredDescription
event_idstring (UUID)Yes
titlestringNo
contentstringNoNotes. Pass an empty string to clear.
custom_event_labelstringNoOnly valid on custom_event rows. Cannot be empty.
scheduled_publish_datestring (ISO 8601) | nullNoPass null to clear.

Response

{
  "event": {
    "id": "ev-uuid-1",
    "content_type": "podcast",
    "title": "Updated podcast title",
    "content": "Updated notes.",
    "status": "scheduled",
    "scheduled_publish_date": "2025-04-21T03:00:00Z",
    "custom_event_label": null,
    "updated_at": "2025-03-15T16:30:00Z",
    "app_url": "https://app.inseeq.com/calendar"
  }
}

inseeq_update_event_status

Toggle an event between 'scheduled' and 'done'. Rejects article/LinkedIn-post IDs (those use inseeq_update_article_status with the article-status set).

ParameterTypeRequiredDescription
event_idstring (UUID)Yes
status'scheduled' | 'done'Yes

Response

{
  "event": {
    "id": "ev-uuid-1",
    "status": "done",
    "updated_at": "2025-04-20T18:00:00Z"
  }
}

inseeq_delete_event

Delete a calendar event. Irreversible. Events have no associated storage objects, version history, or comments to clean up. Both external and internal keys can delete events regardless of status.

ParameterTypeRequiredDescription
event_idstring (UUID)Yes

Response

{
  "deleted": true,
  "event_id": "ev-uuid-1"
}

Comments

inseeq_list_comments

List all comments for an article, organized into threads with unresolved count.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes

Response

{
  "authors": {
    "user-uuid-1": { "email": "alice@example.com", "full_name": "Alice Smith" },
    "user-uuid-2": { "email": "bob@example.com", "full_name": null }
  },
  "comments": [
    {
      "id": "comment-uuid",
      "content": "This intro needs more context about the target audience.",
      "author_id": "user-uuid-1",
      "parent_id": null,
      "is_resolved": false,
      "resolved_by": null,
      "created_at": "2025-02-10T09:15:00Z",
      "selection_start": 0,
      "selection_end": 145,
      "selected_text": "SEO stands for Search Engine Optimization...",
      "replies": [
        {
          "id": "reply-uuid",
          "content": "Good point — I'll add a paragraph about personas.",
          "author_id": "user-uuid-2",
          "parent_id": "comment-uuid",
          "created_at": "2025-02-10T10:30:00Z"
        }
      ]
    }
  ],
  "total": 5,
  "unresolved_count": 2
}

inseeq_poll_new_comments

Poll for new comments on a single article since a given timestamp.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
sincestring (ISO 8601)YesOnly return comments created after this time

Use this to check for new feedback on a specific article. For polling across all articles, use inseeq_poll_pending_comments instead.

Response

{
  "authors": {
    "user-uuid": { "email": "alice@example.com", "full_name": "Alice Smith" }
  },
  "new_comments": [
    {
      "id": "comment-uuid",
      "content": "Please add a sources section.",
      "author_id": "user-uuid",
      "parent_id": null,
      "is_resolved": false,
      "created_at": "2025-02-11T08:00:00Z",
      "selection_start": null,
      "selection_end": null,
      "selected_text": null
    }
  ],
  "count": 1,
  "polled_since": "2025-02-10T00:00:00Z"
}

inseeq_poll_pending_comments

Poll all unresolved top-level comment threads across an organization's articles, grouped by article. Each thread includes its full reply chain so the agent can detect new replies (for example a user accepting a proposal) without fetching threads one at a time.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
sincestring (ISO 8601)NoAccepted for backwards compatibility but ignored. Filtering by a thread's top-level created_at would hide threads with recent replies — e.g. a user accepting a proposal that was posted earlier.

Top-level threads authored by the agent itself are skipped — only human-initiated threads are returned. Replies do include agent-authored messages, flagged with is_agent_reply: true (thread context, not new triggers). Each thread's last_activity_at is the max of its reply timestamps and the top-level created_at — use it to detect what changed since the last poll.

Response

{
  "authors": {
    "user-uuid": { "email": "alice@example.com", "full_name": "Alice Smith" },
    "agent-uuid": { "email": "agent@inseeq.com", "full_name": "Inseeq Agent" }
  },
  "articles": [
    {
      "article_id": "article-uuid-1",
      "title": "Getting Started with SEO",
      "status": "in_review",
      "comments": [
        {
          "id": "comment-uuid",
          "content": "The H2 structure needs work.",
          "author_id": "user-uuid",
          "created_at": "2025-02-10T08:00:00Z",
          "selection_start": null,
          "selection_end": null,
          "selected_text": null,
          "replies": [
            {
              "id": "reply-uuid-1",
              "content": "Here's a revised outline — H2s reordered.",
              "author_id": "agent-uuid",
              "created_at": "2025-02-10T08:05:00Z",
              "is_agent_reply": true
            },
            {
              "id": "reply-uuid-2",
              "content": "Looks good, apply it.",
              "author_id": "user-uuid",
              "created_at": "2025-02-11T14:22:00Z",
              "is_agent_reply": false
            }
          ],
          "last_activity_at": "2025-02-11T14:22:00Z"
        }
      ]
    }
  ],
  "total_unresolved": 3,
  "polled_since": null
}

inseeq_add_comment

Add a comment to an article, optionally as a reply to an existing comment. Supports inline text selection.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
contentstringYesComment text (min 1 character)
parent_idstring (UUID)NoReply to this comment (creates a threaded reply)
selection_startnumberNoCharacter offset where selected text begins
selection_endnumberNoCharacter offset where selected text ends
selected_textstringNoCached copy of the selected text (for display even if content changes)

Response

{
  "comment": {
    "id": "new-comment-uuid",
    "content": "Consider adding an FAQ section.",
    "parent_id": null,
    "created_at": "2025-02-11T09:00:00Z"
  }
}

inseeq_resolve_comment

Resolve or unresolve a top-level comment thread.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
comment_idstring (UUID)Yes
resolvedbooleanNotrue to resolve, false to unresolve (default: true)

Only top-level comments can be resolved. Replies cannot be resolved individually — resolving the parent resolves the entire thread.

Response

{
  "comment": {
    "id": "comment-uuid",
    "is_resolved": true,
    "resolved_by": "agent-uuid",
    "updated_at": "2025-02-11T10:00:00Z"
  }
}

Context (Knowledge Base)

Context is your organization's knowledge base — brand guidelines, writing style, product info, and anything else your agent needs to produce on-brand content. It's organized into sections (like folders) containing entries (like files), each identified by a unique key.

Access LevelAgent Can ReadAgent Can WriteVisible in UIUse Case
allYesYesYesDefault — shared context
agent_onlyYesYesNoAgent memory, internal state
human_onlyNoNoYesPrivate human notes, internal docs
frozenYesNoYesImmutable reference (brand guidelines, legal)

Typical workflows

Full sync (easiest — like git pull/push):

  1. Call inseeq_pull_context to download everything as a flat list of { path, content } pairs
  2. Modify entries locally as needed
  3. Call inseeq_push_context with the full set — replaces all writable entries, preserves protected ones

Pull output is push input. Entries with human_only or frozen access are never overwritten or deleted.

Surgical read (discover → fetch specific entries):

  1. Call inseeq_list_context to see available sections and entries (metadata only, no content)
  2. Call inseeq_get_context with section + key to fetch a single entry

Surgical write (update specific entries without affecting others):

  1. Call inseeq_save_context with the section slug and entries to create or update
  2. Call inseeq_delete_context to remove specific entries by key

inseeq_get_context_index

Get the curated context index (map of content) if one exists. This is a hand-written overview document — for auto-generated structure, use inseeq_list_context instead.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes

Response

{
  "index": "# Context Map\n\n## Brand\n- voice: Brand voice guidelines\n...",
  "message": null
}
// Returns { "index": null, "message": "No index found" }
// if no curated index exists.

inseeq_list_context

List context sections and entry metadata without content. Use to discover available context before fetching.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
sectionstringNoFilter by section slug

Response

{
  "sections": [
    {
      "slug": "brand",
      "label": "Brand",
      "description": "Brand identity and guidelines",
      "entries": [
        {
          "key": "voice",
          "name": "Brand Voice",
          "description": "Tone and voice guidelines",
          "type": "guideline",
          "access": "frozen",
          "updated_at": "2025-01-10T00:00:00Z"
        },
        {
          "key": "vocabulary",
          "name": "Vocabulary Rules",
          "description": null,
          "type": null,
          "access": "all",
          "updated_at": "2025-02-05T00:00:00Z"
        }
      ]
    }
  ]
}

inseeq_pull_context

Download all context entries as a flat list. Each entry has a path (section/key), content, and access level. Output format matches inseeq_push_context input.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes

Response

{
  "context": [
    {
      "path": "brand/voice",
      "content": "# Brand Voice\n\nWe write in a professional...",
      "access": "frozen"
    },
    {
      "path": "memory/last-review",
      "content": "Reviewed 5 articles on 2025-02-10...",
      "access": "agent_only"
    }
  ],
  "total": 12
}

inseeq_push_context

Upload a full set of context entries, replacing all writable content. Entries with human_only or frozen access are preserved. Entries in the DB but not in your payload are deleted.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
contextarray of {path, content}YesFull context set. path format: "section/key" (e.g. "brand/voice")

Side effects

  • Writable entries in the DB that are NOT in your payload are deleted
  • Sections referenced in paths but not yet existing are created automatically
  • Entries with human_only or frozen access are preserved (skipped, not overwritten)

Response

{
  "pushed": 8,
  "deleted": 2,
  "skipped": [
    { "path": "brand/voice", "reason": "frozen" },
    { "path": "internal/notes", "reason": "human_only" }
  ]
}

inseeq_get_context

Get context entries with full content. Fetch a single entry by section + key, filter by section, or get everything.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
sectionstringNoFilter by section slug (e.g. "brand", "memory")
keystringNoFetch a single entry by key (requires section)
compactbooleanNoReturn only essential fields per entry (default: false)

When key is provided, returns a single { entry } object instead of { sections }. Compact mode omits display_order, metadata, last_modified_by, and UI-specific fields.

Response

// Single entry (section + key provided):
{
  "entry": {
    "key": "voice",
    "content": "# Brand Voice\n\nWe write in a professional...",
    "name": "Brand Voice",
    "description": "Tone and voice guidelines",
    "type": "guideline",
    "access": "frozen",
    "updated_at": "2025-01-10T00:00:00Z"
  }
}

// Multiple entries (section only, or no filters):
{
  "sections": [
    {
      "slug": "brand",
      "label": "Brand",
      "description": "Brand identity and guidelines",
      "entries": [
        {
          "key": "voice",
          "content": "# Brand Voice\n...",
          "access": "frozen",
          "updated_at": "2025-01-10T00:00:00Z"
        }
      ]
    }
  ]
}

inseeq_save_context

Create or update context entries within a section. Auto-creates the section if it doesn't exist. Rejects writes to entries marked as human_only or frozen.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
sectionstringYesSection slug (e.g. "brand", "memory")
entriesarray of {key, content, label?, description?, access?}YesEntries to upsert. key is the unique identifier within the section.

Access values: all (default), agent_only. You cannot set access to human_only or frozen via this tool — those are managed in the inseeq UI. Writes to existing human_only or frozen entries are rejected.

Response

{
  "saved": 3,
  "section": "memory",
  "keys": ["last-review", "article-notes", "pending-tasks"]
}

inseeq_delete_context

Delete context entries by key within a section. Rejects deletes on entries marked as human_only or frozen.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
sectionstringYesSection slug
keysstring[]YesEntry keys to delete

Response

{
  "deleted": 2,
  "section": "memory",
  "keys": ["old-notes", "stale-cache"]
}

inseeq_log_context_read

Log that the agent read a context file, for activity tracking.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
pathstringYesContext file path, e.g. /context/visual/brand-kit.md
session_idstringYesYour session/conversation ID
platformstringYes"slack" or "web"

Response

{ "logged": true }

Performance

inseeq_get_article_queries

Get stored search query data for an article. Aggregated from daily Search Console ingestion.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
start_datestring (YYYY-MM-DD)Yes
end_datestring (YYYY-MM-DD)Yes
sort_bystringNoimpressions, clicks, or position (default: impressions)
limitnumber (1–200)NoDefault: 50

Data comes from daily GSC ingestion (top N queries per article). For live GSC queries with custom filters, internal agents can use inseeq_search_console_query.

Response

{
  "queries": [
    {
      "query": "seo basics",
      "impressions": 1250,
      "clicks": 89,
      "avg_position": 4.2,
      "ctr": 0.071,
      "trend_percent": -12.5
    },
    {
      "query": "what is seo",
      "impressions": 980,
      "clicks": 45,
      "avg_position": 8.7,
      "ctr": 0.046,
      "trend_percent": 5.3
    }
  ],
  "total_queries": 47,
  "date_range": {
    "start": "2025-01-01",
    "end": "2025-01-31"
  }
}
// trend_percent: negative = position improved,
// positive = position worsened (vs. prior period)

inseeq_get_article_performance

Get GA4 page-level metrics for an article over a date range. Reads from stored daily data.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
start_datestring (YYYY-MM-DD)Yes
end_datestring (YYYY-MM-DD)Yes
granularitystringNodaily, weekly, or monthly (default: weekly)

Response

{
  "periods": [
    {
      "period_start": "2025-01-06",
      "pageviews": 320,
      "organic_pageviews": 245,
      "entrances": 198,
      "avg_time_on_page_seconds": 142,
      "bounce_rate": 0.38
    },
    {
      "period_start": "2025-01-13",
      "pageviews": 410,
      "organic_pageviews": 312,
      "entrances": 256,
      "avg_time_on_page_seconds": 158,
      "bounce_rate": 0.35
    }
  ],
  "totals": {
    "pageviews": 730,
    "organic_pageviews": 557,
    "organic_share": 0.76,
    "avg_bounce_rate": 0.365,
    "avg_time_on_page_seconds": 150
  }
}

inseeq_list_portfolio_performance

Aggregate performance across all published articles for your organization. Returns inseeq-managed articles only.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
periodstringYeslast_7d, last_30d, or last_90d
sort_bystringNopageviews, trend, or position (default: pageviews)
limitnumber (1–200)NoDefault: 100

Response

{
  "org_totals": {
    "total_pageviews": 15420,
    "total_organic_pageviews": 11890,
    "organic_share": 0.77,
    "trend_percent": 12.3,
    "published_article_count": 24,
    "traffic_goals": null
  },
  "articles": [
    {
      "article_id": "uuid",
      "title": "Getting Started with SEO",
      "slug": "seo-basics-guide",
      "days_since_published": 45,
      "pageviews": 2150,
      "organic_pageviews": 1820,
      "trend_percent": 8.5,
      "avg_position": 4.2,
      "protected": false,
      "has_traffic_goals": true,
      "pending_recommendation": false
    }
  ]
}

inseeq_get_traffic_goals

Get traffic goals for an article with organization-level defaults as fallback.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes
article_idstring (UUID)Yes

Response

{
  "article_goals": {
    "protected": false,
    "protect_reason": null,
    "target_keyword": "seo basics",
    "target_position": 3,
    "monthly_traffic_target": 5000,
    "notes": "Key landing page for organic funnel"
  },
  "org_goals": {
    "monthly_organic_sessions": 50000,
    "monthly_organic_growth_pct": 10,
    "notes": null
  }
}
// Either field can be null if no goals are configured.

inseeq_get_review_settings

Get the review configuration for your organization. Returns all settings with defaults applied.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes

Response

{
  "review_enabled": true,
  "articles_per_cycle": 5,
  "review_cadence_days": 7,
  "min_article_age_days": 30,
  "notification_channel": "slack",
  "full_site_insights": false,
  "queries_per_article": 50
}

inseeq_get_article_recommendations

Get existing optimization recommendations for an article. Use to check for pending recommendations before submitting new ones.

ParameterTypeRequiredDescription
article_idstring (UUID)Yes
statusstringNoFilter: pending, accepted, rejected, applied, reverted
limitnumber (1–50)NoDefault: 10

Response

{
  "recommendations": [
    {
      "id": "rec-uuid",
      "recommendation_type": "update",
      "diagnosis": ["declining_traffic", "keyword_cannibalization"],
      "priority": "high",
      "status": "pending",
      "justification": "Traffic dropped 25% over 30 days...",
      "performance_summary": { ... },
      "content_changes": null,
      "created_at": "2025-02-15T10:00:00Z",
      "reviewed_at": null,
      "applied_at": null
    }
  ],
  "total": 3
}

Skills

inseeq_get_enabled_skills

Get the list of enabled skills for your organization.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes

Response

{
  "skills": [
    {
      "skill_slug": "article-writer",
      "is_active": true,
      "activated_at": "2025-01-15T00:00:00Z"
    },
    {
      "skill_slug": "seo-reviewer",
      "is_active": true,
      "activated_at": "2025-02-01T00:00:00Z"
    }
  ]
}

inseeq_get_skill_content

Get enabled skills with full file content for your organization. Returns skill definitions including file paths, content, and metadata.

ParameterTypeRequiredDescription
organization_idstring (UUID)Yes

Automatically merges global skill definitions with per-organization overrides. Organization-specific overrides take precedence.

Response

{
  "skills": [
    {
      "skill_slug": "article-writer",
      "files": [
        {
          "path": "skills/article-writer/prompt.md",
          "content": "# Article Writer\n\nYou are an expert...",
          "name": "Article Writer",
          "description": "Writes SEO-optimized articles",
          "node_type": "skill",
          "version": 2
        }
      ]
    }
  ]
}

Internal-Only Tools

The following tools appear in the MCP schema but are restricted to internal (first-party) inseeq agents. Calling them with an external API key returns an authorization error.

ToolPurpose
inseeq_search_console_queryLive proxy to Google Search Console API
inseeq_update_heartbeatAgent liveness heartbeat
inseeq_get_agent_deploymentDeployment status and config
inseeq_get_agent_configPer-org agent configuration overrides
inseeq_submit_learning_reportDaily learning report submission
inseeq_submit_optimization_recommendationArticle optimization recommendations
inseeq_send_review_notificationEmail notifications for review cycles
inseeq_save_chat_messagePersist assistant text and artifact rows to the in-app chat UI

Workflow Recipes

Common multi-step patterns for working with the inseeq MCP server.

Create and publish an article

1. inseeq_agent_whoami
   → get your organization_id

2. inseeq_create_article
   → { organization_id, title, content, meta_description, ... }
   → returns { article: { id } }

3. inseeq_update_article_status
   → { article_id, status: "in_review" }
   → triggers review emails to org members

4. (Wait for human approval — poll with inseeq_get_article)

5. inseeq_publish_article
   → { article_id }
   → publishes to configured CMS

Monitor and respond to feedback

1. inseeq_poll_pending_comments
   → { organization_id }
   → returns unresolved threads (with replies + last_activity_at) grouped by article
   → use last_activity_at per thread to decide what's new since the previous poll

2. inseeq_get_article
   → { article_id }
   → returns metadata + markdown content by default

3. inseeq_add_comment
   → { article_id, content: "response...", parent_id: "original-comment-id" }
   → reply to the feedback

4. inseeq_resolve_comment
   → { article_id, comment_id }
   → mark the thread as resolved once addressed

Upload and set the featured image

Three steps: get a presigned URL, PUT the binary, then attach the resulting public URL to the article via inseeq_set_featured_image. The upload tool returns both URLs in one call — no separate finalize step.

1. inseeq_create_image_upload
   → { content_id: <article_id>, content_type: "image/png" }
   → returns { upload_url, public_url, storage_path, token, content_type }

2. HTTP PUT to upload_url with raw binary body
   (your MCP client handles this — no base64 through the LLM)

3. inseeq_set_featured_image
   → { article_id, featured_image_url: <public_url>, featured_image_alt_text: "..." }
   → image is now attached to the article. If a previous featured_image_url
     existed, its storage object is auto-deleted.

Schedule a calendar event

Events are direct one-shot creates — no review, no publish, no images. Useful when an agent wants to place a marker on the team's calendar (an upcoming podcast recording, a press release going out, a trade show).

1. inseeq_create_event
   → { organization_id, event_type: "podcast",
       title: "AI on the Acme Show",
       content: "Topics: agent workflows, ...",
       scheduled_publish_date: "2025-04-20T03:00:00Z" }
   → returns { event: { id } }

2. (Event runs as planned)

3. inseeq_update_event_status
   → { event_id, status: "done" }
   → marks the event complete; calendar dims the card

Sync context from an external source

// Full sync (replaces all writable entries):
1. inseeq_pull_context
   → { organization_id }
   → returns all entries as { path, content, access } pairs

2. Modify entries locally (add, update, remove)

3. inseeq_push_context
   → { organization_id, context: [{ path, content }, ...] }
   → returns { pushed, deleted, skipped }
   ⚠️  Entries NOT in your payload are deleted (except protected ones)

// Surgical update (modify specific entries only):
1. inseeq_save_context
   → { organization_id, section: "memory", entries: [{ key, content }] }
   → creates or updates without affecting other entries

inseeq MCP Server API Reference

Need help? Contact peter@inseeq.com