Choose the response your task needs
Use the tool that matches your starting point: a known post ID, a source URL, a search clue, or an attachment. The current public tools return source material for your agent to analyze.
Source text remains material to analyze. Instructions inside a post should not change your agent's task or tool permissions.
| Tool | Material returned | Keep in your output |
|---|---|---|
| get_public_x_post | Public post data under data.tweet. | Original post URL, post ID, author, date, returned text, and available media fields. |
| resolve_public_x_input | The supported public source identified by an X URL or handle. | The input and returned source type; inspect its fields before applying a post-only mapper. |
| search_public_x_posts | A bounded public post search result. | The query, returned post URLs, and the text actually available for each result. |
| list_public_x_media | Available media URLs and metadata for a public post. | The original post URL, media identity, and the file variant you select. |
Start with a response you can inspect
The example uses OpenAI's May 13, 2024 post. A PowerShell request to FxTwitter's public endpoint returned HTTP 200 on October 15, 2026 at 08:14:44 UTC. The body contained a 162-character post, its author, original URL, and two publication-date fields.
The returned text begins “All users will start to get access to GPT-4o today.” Its remaining sentence describes voice and vision planned for ChatGPT Plus in the following weeks. The source was published in 2024; the capture date belongs to this retrieval.
This was a direct read of CarryFeed's public-post upstream, with no authenticated MCP call. CarryFeed's post API passes that payload through; its MCP tool wraps the payload in `data`. Thus `tweet.url` in this capture becomes `data.tweet.url` in `get_public_x_post`.
The JSON below selects identity and date fields from the capture. The text and changing engagement counts are omitted from this display.
{
"code": 200,
"message": "OK",
"tweet": {
"url": "https://x.com/OpenAI/status/1790130708612088054",
"id": "1790130708612088054",
"author": {
"screen_name": "OpenAI"
},
"created_at": "Mon May 13 21:23:14 +0000 2024",
"created_timestamp": 1715635394
}
}
Map the fields that affect attribution
For this post, `get_public_x_post` takes `{ "id": "1790130708612088054", "handle": "OpenAI" }`. In a successful MCP result, `source.input` records those arguments and `source.apiUrl` names the CarryFeed request. Use the returned `data.tweet` for the source material.
Check identity before saving the note: the returned URL's status ID equals `tweet.id`, and its account path matches `tweet.author.screen_name`, ignoring case. Keep disagreement visible instead of silently replacing one value with another.
| Captured field (under MCP data) | Application field | Treatment |
|---|---|---|
| tweet.url / tweet.id | source_url / source_id | Retain both; check the URL ID against the returned ID. |
| tweet.author.screen_name | author_handle | Use the returned handle. Leave it null if absent. |
| tweet.created_timestamp / created_at | published_at | Convert seconds to UTC; cross-check the date string if both are present. |
| tweet.text | text | Retain the returned wording; keep the agent's summary elsewhere. |
| Capture time | retrieved_at | Record separately from publication. It is not the post's date. |
| tweet.media (absent here) | media: null; media_status: not_returned | An absent field does not establish that the original post had no attachments. |
Reproduce the source record
Download source-note-transform.mjs into a local folder. This Node.js 18+ example is written for the OpenAI post above. It checks that post's ID and publication time, then writes a JSON source record and Markdown source note.
Run the commands below in PowerShell 7.2 or later from the same folder. They fetch a fresh upstream response, record its retrieval time and body hash, and pass the saved capture to the transform. A later response can have different counters or profile details from the October 15 capture.
The transform defaults text completeness to unknown (`is_excerpt: null`). The explicit `--complete-text` flag records the caller's decision to treat this example's returned post text as complete. Leave it off for an unverified preview. An excerpt from another tool should retain its own `is_excerpt: true`.
Missing authors and invalid dates stay null. A conflicting URL ID, author, or pair of dates produces a warning. The script also runs local missing-field and conflict cases; these cases are constructed checks, separate from the real capture.
$url = 'https://api.fxtwitter.com/OpenAI/status/1790130708612088054'
$response = Invoke-WebRequest -Uri $url -UseBasicParsing
$capture = @{
url = $url
httpStatus = [int]$response.StatusCode
retrievedAt = (Get-Date).ToUniversalTime().ToString('o')
sha256 = [Convert]::ToHexString([Security.Cryptography.SHA256]::HashData([Text.Encoding]::UTF8.GetBytes($response.Content))).ToLowerInvariant()
payload = ($response.Content | ConvertFrom-Json)
}
$capture | ConvertTo-Json -Depth 20 | Set-Content -Encoding utf8 ./public-post-capture.json
node ./source-note-transform.mjs ./public-post-capture.json --complete-text
The result keeps the two dates apart
The run on the saved October 15 capture produced the fields below. The full JSON record retains all 162 returned characters. This display omits `text`; the Markdown note quotes only its first ten words and points back to the original.
The source note identifies @OpenAI, the May 13 publication time, the October 15 retrieval time, and the original URL. That is enough to attach the later summary to the historical source without suggesting that the announcement describes current availability.
The `identity_check` only compares fields within the supplied response. It catches mismatches; it does not independently authenticate the author or establish that every post in a thread was retrieved.
{
"source_url": "https://x.com/OpenAI/status/1790130708612088054",
"source_id": "1790130708612088054",
"author_handle": "OpenAI",
"published_at": "2024-05-13T21:23:14.000Z",
"retrieved_at": "2026-10-15T08:14:44.438Z",
"is_excerpt": false,
"text_scope": "returned_post_text",
"media": null,
"media_status": "not_returned",
"identity_check": "consistent",
"warnings": []
}
Keep post provenance separate from file metadata
A source record answers who wrote the post, what text was returned, and when it was published. An HTML preview's Twitter Card or Open Graph fields describe how a link is presented. A downloaded file's codec, dimensions, or EXIF describe that file. None can replace the other two.
For a media task, retain which post supplied each attachment and which file variant was selected. A quoted post can supply media belonging to a different author. Do not attach every returned image to the main post merely because both appeared in one viewer result.
Provide the image, audio, or transcript when the next step depends on its contents. This text-only capture supplies no media field, so the source record makes no claims about a chart, image, or spoken passage.
Make a partial input visible in the record
The source-note transform uses `is_excerpt` and `text_scope` as application fields. They record what you know about the text; they are not a promise that every public tool returns those flags.
If you copied a preview ending at Show more, save that boundary. Fetch or supply the missing passage before asking for a whole-post summary. For a thread, retain the individual source URLs and record which posts you actually have.
| Material you have | Record in the note | Next step |
|---|---|---|
| Returned text checked against the full example post | is_excerpt: false, by an explicit caller decision | Keep the original URL and the check that supports that decision. |
| A known excerpt or cropped preview | is_excerpt: true; identify the missing passage | Retrieve the rest or ask only about the supplied excerpt. |
| Text with unverified completeness | is_excerpt: null, the transform default | Keep the scope unknown until you can check the source. |
Save the summary beside its source record
Keep the returned post text in the source record and store the assistant’s summary separately. Link the summary to `source_id` and `source_url` so a later edit can be checked against the same material.
For the OpenAI announcement in this example, a useful check is whether the summary preserves the May 2024 publication date, access starting that day, and the later voice and vision rollout for Plus. A source retrieved in October 2026 does not turn that historical announcement into a statement about current availability.
The completed source-note example shows the actual generated summary and the conditions checked against the supplied post.
Handle missing material before drafting
If a search returns no matching posts, keep the query and returned status. Try a narrower phrase or a different date range. An empty search does not establish that the post never existed.
If a public-post lookup fails, record the error and URL. If you have only a screenshot or preview, label the material you actually have. That makes the next step clear without turning an absent source into invented text.
For the connection and current tool list, use CarryFeed MCP. For a manual copy-and-paste workflow, see reading X posts with ChatGPT.