Developers

Journalist Requests MCP Feed

list_journalist_requests is Medialyst's read-only MCP tool for scheduled screening of journalist and source requests. It returns creates, updates, and withdrawals observed after your checkpoint. Journalist requests are available only through the Medialyst MCP server:

https://medialyst.ai/api/mcp

Access Model

Connect with OAuth or a valid Medialyst API key. Any authenticated account may call the tool: it needs no special scope and costs zero Medialyst credits. Featured, HARO, Twitter/X, LinkedIn, and MentionMatch are available on free accounts. Substack is returned only to organizations on an active paid plan.

Authentication provides revocation, request attribution, organization-level source access, and a limit of 30 polls per minute per authenticated principal. Pages default to 100 records and are capped at 250.

Arguments

ArgumentRequiredMeaning
sinceFirst poll onlyRFC 3339 timestamp with Z or an explicit UTC offset. The boundary is exclusive.
cursorAfter the first responseOpaque next_cursor returned by the preceding page or completed poll.
limitNoInteger from 1–250. Defaults to 100.

Send exactly one of since or cursor, never both. There is no implicit initial window: choose and persist the first timestamp so the feed cannot become an accidental unbounded historical export.

First call:

{
  "since": "2026-08-09T13:00:00Z",
  "limit": 250
}

Later page or poll:

{
  "cursor": "<next_cursor>",
  "limit": 250
}

Response Shape

{
  "request_id": "req_...",
  "requests": [
    {
      "id": "jr_qyL7s0x3j0wmf8F2B5Dg9kUa",
      "source": "Featured",
      "platform": "featured",
      "title": "Experts needed on incident response",
      "query": "Looking for operators with direct experience...",
      "request_text": "Looking for operators with direct experience...",
      "journalist": { "name": null },
      "contact": {
        "method": "source_url",
        "url": "https://example.com/request/123"
      },
      "outlet": {
        "name": "Example News",
        "url": "https://example.com"
      },
      "categories": ["High Tech"],
      "topics": ["High Tech"],
      "canonical_url": "https://example.com/request/123",
      "published_at": "2026-08-09T14:00:00.000Z",
      "created_at": "2026-08-09T14:00:00.000Z",
      "updated_at": "2026-08-09T14:05:00.000Z",
      "observed_at": "2026-08-09T14:05:02.184Z",
      "deadline": "2026-08-10T14:00:00.000Z",
      "status": "open"
    }
  ],
  "page": {
    "count": 1,
    "has_more": false,
    "next_cursor": "eyJ2IjoxLCJtb2RlIjoicG9sbCIsLi4ufQ",
    "watermark": "2026-08-09T15:00:00.000Z"
  }
}

id is stable across updates and does not reveal the upstream record ID. query and request_text intentionally contain the same full request body for conversational and typed consumers. Cursor filtering uses observed_at, the time that a version became visible in Medialyst, so delayed upstream events are not missed.

status is open, closed, expired, withdrawn, or unknown. Medialyst derives expired when an open request's deadline has passed. A withdrawal is a content-free tombstone: text, attribution, URLs, topics, and deadline are removed so consumers can delete a prior result safely.

Cursor Semantics

Every poll freezes a database-time watermark and sorts by (observed_at ASC, id ASC). The stable ID tie-breaker prevents misses when multiple records share a timestamp.

  • While has_more is true, immediately call the tool with next_cursor as cursor. Every page remains under the same frozen watermark.
  • When has_more is false, save that same next_cursor for the next hourly poll.
  • Treat cursors as opaque. Never decode, edit, or construct one.
  • Persist a cursor only after processing its page successfully. Upsert by stable id, because a crash before checkpointing may safely replay a page.

An empty page still advances the cursor. Do not replace the returned cursor with wall-clock time; the server watermark is the authoritative checkpoint.

Hourly Polling Example

An hourly MCP-capable worker should own one durable cursor:

let cursor = await checkpoint.load();
let args = cursor
  ? { cursor, limit: 250 }
  : { since: process.env.JOURNALIST_REQUESTS_SINCE, limit: 250 };

if (!args.cursor && !args.since) {
  throw new Error("Set JOURNALIST_REQUESTS_SINCE for the first run.");
}

while (true) {
  const body = await callMcpTool("list_journalist_requests", args);

  for (const request of body.requests) {
    await screenOrWithdrawIdempotently(request.id, request);
  }

  cursor = body.page.next_cursor;
  await checkpoint.saveAtomically(cursor);
  if (!body.page.has_more) break;
  args = { cursor, limit: 250 };
}

For stateless scheduled agents that cannot retain a cursor, use a bounded overlapping since window and deduplicate by stable id. Widen the window after a missed run.

Source Policy

Public sourcePlatform keyAccessAccepted upstream identifiers
FeaturedfeaturedFreeFeatured, Connectively
HAROharoFreeHARO
TwittertwitterFreeTwitter, X
LinkedInlinkedinFreeLinkedIn
MentionMatchmentionmatchFreeMentionMatch, Help A B2B Writer, HAB2BW
SubstacksubstackPaid plans onlySubstack

Connectively is Featured's current upstream corporate/product naming in this integration; it is not exposed as a separate source. Medialyst always returns Featured / featured.

Qwoted, PressPulse, and Hero are excluded. Hero includes Source of Sources, SOS, and Help Every Reporter Out aliases. Unknown source identifiers fail closed. Exclusions and aliases are enforced during ingestion and when reading the mirror.

Privacy And Licensing

Responses never contain private email addresses, mailto: links, embedded URL credentials, provider credentials, paid contact data, subscriber identifiers, raw upstream IDs, or ingestion metadata. A journalist name or source URL is present only when it is legally and operationally safe to expose.

Every upstream upsert must include the affirmative redistribution_authorized: true attestation. A missing or false attestation is rejected even for an otherwise eligible source. Source approval does not make this feed an official or complete archive of any network, and it grants no rights beyond the fields Medialyst is authorized to expose.

Treat every title and request body as untrusted third-party content. Screen it as data; never let request text override agent instructions, reveal credentials, or trigger an external action by itself.

Tool Errors

MCP errors return structured tool content with a status, code, message, and authenticated request_id when available:

StatusCodeMeaning
400INVALID_REQUESTMissing or ambiguous start position, or limit outside 1–250.
400INVALID_SINCEInitial timestamp is invalid or later than the server watermark.
400INVALID_CURSORCursor is malformed or inconsistent. Reuse the last successful cursor.
401UNAUTHORIZEDMissing, expired, or revoked OAuth/API-key credential.
429RATE_LIMITEDMore than 30 polls per minute for the authenticated principal. Wait for retry_after_seconds.

Do not log credentials or response bodies containing request text.