feat: Twitter/X integration (read-only free tier)
- New client: src/clients/twitter.ts
- Tools: twitter_search_tweets, twitter_get_user_profile, twitter_get_user_tweets, twitter_create_tweet
- REST endpoints: GET /api/twitter/search, /api/twitter/user, /api/twitter/tweets, POST /api/twitter/tweet
- Multi-account env var: TWITTER_{ACCOUNT}_BEARER_TOKEN
- twitter_create_tweet returns clear error about paid tier requirement
Total tools: 36
This commit is contained in:
88
src/tools.ts
88
src/tools.ts
@@ -7,6 +7,7 @@ import { getProfile as getLinkedInProfile, createPost as createLinkedInPost, sea
|
||||
import { getMe as getTelegramMe, sendMessage as sendTelegramMessage, sendPhoto as sendTelegramPhoto, getUpdates as getTelegramUpdates, getChat as getTelegramChat } from './clients/telegram.js';
|
||||
import { getMe as getDiscordMe, getGuilds, getChannels, sendMessage as sendDiscordMessage, getMessages as getDiscordMessages } from './clients/discord.js';
|
||||
import { getProfile as getInstagramProfile, getMedia as getInstagramMedia, createPost as createInstagramPost } from './clients/instagram.js';
|
||||
import { searchTweets, getUserProfile, getUserTweets, createTweet } from './clients/twitter.js';
|
||||
|
||||
const ACCOUNT_PARAM = {
|
||||
account: {
|
||||
@@ -459,6 +460,62 @@ export const tools: Tool[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ── Twitter/X tools ──────────────────────────────────────────
|
||||
{
|
||||
name: 'twitter_search_tweets',
|
||||
description:
|
||||
'Search recent tweets on Twitter/X. Use when the user wants to find tweets about a topic, hashtag, or keyword.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
required: ['query'],
|
||||
properties: {
|
||||
query: { type: 'string', description: 'Search query (keyword, hashtag, or phrase)' },
|
||||
max_results: { type: 'number', description: 'Max tweets to return (default: 10, max: 100)' },
|
||||
account: { type: 'string', description: 'Which Twitter account to use (default: "default")' },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'twitter_get_user_profile',
|
||||
description:
|
||||
'Get a Twitter/X user profile. Use when the user wants stats, bio, or follower count for a specific account.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
required: ['username'],
|
||||
properties: {
|
||||
username: { type: 'string', description: 'Twitter username (without @)' },
|
||||
account: { type: 'string', description: 'Which Twitter account to use (default: "default")' },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'twitter_get_user_tweets',
|
||||
description:
|
||||
'Get recent tweets from a specific Twitter/X user. Use to read someones timeline.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
required: ['username'],
|
||||
properties: {
|
||||
username: { type: 'string', description: 'Twitter username (without @)' },
|
||||
max_results: { type: 'number', description: 'Max tweets (default: 10, max: 100)' },
|
||||
account: { type: 'string', description: 'Which Twitter account to use (default: "default")' },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'twitter_create_tweet',
|
||||
description:
|
||||
'Post a tweet on Twitter/X. [REQUIRES PAID TIER] The free API tier is read-only. Upgrade required to post.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
required: ['text'],
|
||||
properties: {
|
||||
text: { type: 'string', description: 'Tweet text (max 280 chars)' },
|
||||
account: { type: 'string', description: 'Which Twitter account to use (default: "default")' },
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
function acct(args: Record<string, unknown>): Account {
|
||||
@@ -689,6 +746,37 @@ export async function handleToolCall(
|
||||
});
|
||||
break;
|
||||
|
||||
// ── Twitter/X ───────────────────────────────────────────────
|
||||
case 'twitter_search_tweets':
|
||||
result = await searchTweets({
|
||||
query: args.query as string,
|
||||
max_results: (args.max_results as number) ?? 10,
|
||||
account: args.account as string | undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'twitter_get_user_profile':
|
||||
result = await getUserProfile({
|
||||
username: args.username as string,
|
||||
account: args.account as string | undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'twitter_get_user_tweets':
|
||||
result = await getUserTweets({
|
||||
username: args.username as string,
|
||||
max_results: (args.max_results as number) ?? 10,
|
||||
account: args.account as string | undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
case 'twitter_create_tweet':
|
||||
result = await createTweet({
|
||||
text: args.text as string,
|
||||
account: args.account as string | undefined,
|
||||
});
|
||||
break;
|
||||
|
||||
// Legacy Yahoo-prefixed names — keep working for any cached Claude sessions
|
||||
case 'yahoo_get_profile':
|
||||
result = await getProfile('yahoo');
|
||||
|
||||
Reference in New Issue
Block a user