@twitterapis/mcp 0.6.4 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -11
- package/README.md +0 -12
- package/package.json +1 -2
- package/src/tools.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
### Added
|
|
6
|
-
|
|
7
|
-
- **`mcpName` in `package.json`, which is what the official MCP Registry checks to prove we own this npm package.** It must equal the `name` in `server.json`, and the registry reads it from the tarball on npm rather than from the repo, so 0.6.3 could not be published no matter what the repo said. This is the entire reason 0.6.4 exists as a release; there is no behaviour change and no tool change.
|
|
8
|
-
- The README now carries a Directory listings table recording, per directory, whether the server is actually listed and what that directory requires today. A descriptor file in the repo is not a listing, and the two had drifted apart.
|
|
9
|
-
|
|
10
|
-
### Fixed
|
|
11
|
-
|
|
12
|
-
- **The 0.6.3 registry descriptors were schema-invalid and would never have listed.** The official registry caps `description` at 100 characters; ours was 216, and the publish endpoint rejected it with HTTP 422. `test/registry-manifests.mjs` reported all three descriptors clean throughout, because it only checked that `description` was a non-empty string. Running the old gate against the 0.6.3 commit still passes while the registry still rejects that same file, which is the clearest statement of what was wrong with it. The gate now pins `description` and `title` at 100 and `name` at 200, the values read off the live schema, and asserts `package.json` `mcpName` equals `server.json` `name`. All four checks were red-tested against mutations before this shipped.
|
|
13
|
-
- **`smithery.yaml` was documented as the thing that gets us onto Smithery, and it is not.** Smithery retired the repo-linked build path, and the filename now appears nowhere in their documentation index. The file is kept, since a few third-party crawlers still read the old convention and it costs nothing, but its header no longer claims to be a submission. Smithery listing needs an account and either a hosted Streamable HTTP endpoint or an MCPB bundle.
|
|
3
|
+
## Unreleased
|
|
14
4
|
|
|
15
5
|
### Changed
|
|
16
6
|
|
|
@@ -20,6 +10,8 @@
|
|
|
20
10
|
|
|
21
11
|
### Fixed
|
|
22
12
|
|
|
13
|
+
- **`twitter_user_tweets` advertised a filter the endpoint does not apply.** Its description said it returns "a user's recent original tweets, excluding replies and retweets". Measured live against production on two accounts: `elonmusk` returned 9 retweets and 1 reply in 20 items, `sama` returned 5 retweets and 1 reply in 20. Counted on the payload's own `is_retweet` and `is_reply` booleans, not on a text heuristic, and both flags took both values in the sample so they are real fields rather than constants. This is the highest-leverage wrong text in the package: a tool description is what a model reads to decide how to call a tool, so an advertised filter that is never applied produces an agent that reasons over retweets and replies believing it has only the user's own posts. The description now states plainly that no server-side filtering happens, names the three booleans (`is_retweet`, `is_reply`, `is_quote`) to filter on, and warns that `author.username` must be read rather than assumed, because a retweet carries the original author inside `retweeted_tweet`.
|
|
14
|
+
- **`twitter_user_tweets_and_replies` claimed a distinction that does not exist.** It told the model "to see only original tweets, use `twitter_user_tweets`", which is the same false filter promise from the other side. On `elonmusk` both endpoints returned the same 20 tweet ids in the same order with identical reply and retweet composition. The cross-reference is replaced with an honest note that the two endpoints overlap and a pointer to the same three booleans.
|
|
23
15
|
- **The vendored spec was four endpoints behind the API**, missing `/users/by_ids`, `/user/blocking`, `/user/muting`, and `/media/status`, the four tools added after the snapshot was last refreshed. The parity check only noticed because it prefers the live spec over the vendored copy, so on any run without network access it reported four tools pointing at endpoints that "do not exist" and exited non-zero. Re-vendored; the offline path now passes.
|
|
24
16
|
- **The README was missing four of the 51 tools** (`twitter_users_by_ids`, `twitter_blocking`, `twitter_muting`, `twitter_media_status`) and still said "47 tools: 33 reads". Since the README ships inside the package and is its page on npm, those four were callable but documented nowhere. Rows added, counts corrected, and a new `test/readme-parity.mjs` compares the README against the catalog itself, so a tool can no longer ship without a row or a correct count.
|
|
25
17
|
- The changelog section describing the seven tools added in 0.6.2 was still headed "Unreleased" twelve days after it shipped. Retitled.
|
package/README.md
CHANGED
|
@@ -264,18 +264,6 @@ npm test # gates, incl. "src/tools.js matches the generator"
|
|
|
264
264
|
|
|
265
265
|
`npm test` fails if `src/tools.js` was hand-edited or left stale, if the catalog and the live spec disagree, or if the tool list and this README disagree.
|
|
266
266
|
|
|
267
|
-
### Directory listings
|
|
268
|
-
|
|
269
|
-
Where this server actually appears, and what each directory needs. A descriptor file sitting in the repo is not a listing, so this table records the listing, not the file. Checked 2026-08-02.
|
|
270
|
-
|
|
271
|
-
| Directory | State | What it takes |
|
|
272
|
-
| --- | --- | --- |
|
|
273
|
-
| Official MCP Registry | listed as `io.github.TwitterAPIs/twitterapis-mcp` | `server.json` plus `mcpName` in the **published** `package.json`. Publish with `mcp-publisher`, authenticating with a GitHub token whose account is an org **admin**. Every release needs a fresh `publish`, since the registry pins a version. |
|
|
274
|
-
| Glama | listed, crawled automatically | Nothing to submit. Glama indexed the GitHub repo on its own. `glama.json` names the maintainer for the claim, but the claim itself is completed from a signed-in Glama account. |
|
|
275
|
-
| Smithery | not listed | `smithery.yaml` no longer does anything: the repo-linked build path was retired and the filename appears nowhere in Smithery's current docs. Listing now means publishing either a public Streamable HTTP endpoint or a prebuilt MCPB bundle, both from a Smithery account with an API key. |
|
|
276
|
-
|
|
277
|
-
Two traps worth keeping in mind. The registry enforces `description` at 100 characters and `title` at 100; `test/registry-manifests.mjs` pins both, because the descriptors passed an earlier version of that gate while the registry rejected them with HTTP 422. And `mcpName` is verified against the tarball on npm, not against the working tree, so a wrong value is only visible after the release has shipped and costs another version to correct.
|
|
278
|
-
|
|
279
267
|
## License
|
|
280
268
|
|
|
281
269
|
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twitterapis/mcp",
|
|
3
|
-
"version": "0.6.
|
|
4
|
-
"mcpName": "io.github.TwitterAPIs/twitterapis-mcp",
|
|
3
|
+
"version": "0.6.5",
|
|
5
4
|
"description": "Official MCP server for twitterapis.com, the Twitter/X API (search, users, followers, tweets, threads, lists, likes, bookmarks, DMs) plus write actions (post/like/retweet/follow) as native tools for Claude, Cursor, and any MCP client.",
|
|
6
5
|
"repository": {
|
|
7
6
|
"type": "git",
|
package/src/tools.js
CHANGED
|
@@ -148,7 +148,7 @@ export const TOOLS = [
|
|
|
148
148
|
name: "twitter_user_tweets",
|
|
149
149
|
path: "/twitter/user/tweets",
|
|
150
150
|
description:
|
|
151
|
-
"Get a user's recent
|
|
151
|
+
"Get a user's recent posting timeline. IMPORTANT: this endpoint does NOT filter server-side, so the response routinely includes retweets and replies alongside original posts. Every item carries is_retweet, is_reply and is_quote booleans, so filter client-side on those flags if you need originals only, and read author.username rather than assuming every item was written by the requested user (a retweet's retweeted_tweet holds the original author). Returns tweet text, id, timestamp, and engagement metrics. Paginate with cursor to go further back. For the full back-catalogue in one call, use twitter_user_tweets_complete.",
|
|
152
152
|
shape: {
|
|
153
153
|
username: z.string().optional().describe(
|
|
154
154
|
"Twitter/X handle WITHOUT the leading @ (e.g. \"elonmusk\", \"openai\"). Provide exactly one of username or user_id.",
|
|
@@ -168,7 +168,7 @@ export const TOOLS = [
|
|
|
168
168
|
name: "twitter_user_tweets_and_replies",
|
|
169
169
|
path: "/twitter/user/tweets_and_replies",
|
|
170
170
|
description:
|
|
171
|
-
"Get a user's full activity timeline: their original tweets AND replies to others. Useful for understanding how someone engages with a community, not just what they post. Paginate with cursor.
|
|
171
|
+
"Get a user's full activity timeline: their original tweets AND replies to others. Useful for understanding how someone engages with a community, not just what they post. Paginate with cursor. Items carry is_retweet, is_reply and is_quote booleans; filter on those if you need a specific subset. Note that twitter_user_tweets does NOT filter replies or retweets out either, so on many accounts the two endpoints return overlapping or identical pages.",
|
|
172
172
|
shape: {
|
|
173
173
|
username: z.string().optional().describe(
|
|
174
174
|
"Twitter/X handle WITHOUT the leading @ (e.g. \"elonmusk\", \"openai\"). Provide exactly one of username or user_id.",
|