# Directory Structure
```
├── .gitignore
├── LICENSE
├── package.json
├── pnpm-lock.yaml
├── README.md
├── src
│ ├── index.ts
│ ├── interfaces
│ │ └── index.ts
│ ├── schema
│ │ └── index.ts
│ ├── tools
│ │ └── twitter.ts
│ └── types
│ └── index.ts
└── tsconfig.json
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
1 | # compiled output
2 | **/build
3 | **/node_modules
4 | **/.turbo
5 | .env
6 |
7 | # Client
8 | /client/.next
9 | /client/node_modules
10 | /client/dist
11 | /client/.env.local
12 |
13 | # Logs
14 | logs
15 | *.log
16 | npm-debug.log*
17 | pnpm-debug.log*
18 | yarn-debug.log*
19 | yarn-error.log*
20 | lerna-debug.log*
21 |
22 | # OS
23 | .DS_Store
24 |
25 | # Tests
26 | /coverage
27 | /.nyc_output
28 |
29 | # IDEs and editors
30 | /.idea
31 | .project
32 | .classpath
33 | .c9/
34 | *.launch
35 | .settings/
36 | *.sublime-workspace
37 |
38 | # IDE - VSCode
39 | .vscode/*
40 | !.vscode/settings.json
41 | !.vscode/tasks.json
42 | !.vscode/launch.json
43 | !.vscode/extensions.json
44 |
45 | # TS config
46 | *.tsbuildinfo
47 | tsconfig.build.tsbuildinfo
48 | tsconfig.tsbuildinfo
49 |
50 | *.tgz
51 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # MCP Twitter
2 |
3 | ## Description
4 | MCP Twitter is a server based on the Model Context Protocol that allows direct interaction with Twitter/X. It exposes various Twitter API functionalities through a standardized set of tools, enabling AI models and applications to perform actions on Twitter.
5 |
6 | ## Features
7 |
8 | This MCP server provides the following actions:
9 |
10 | - **`create_twitter_post`**: Create a new X/Twitter post
11 | - **`reply_twitter_tweet`**: Reply to a specific X/Twitter post by ID
12 | - **`get_last_tweet`**: Get the most recent post from a specified X/Twitter account
13 | - **`get_last_tweets_options`**: Get a specified number of posts matching a search query
14 | - **`create_and_post_twitter_thread`**: Create and publish an X/Twitter thread
15 | - **`follow_twitter_from_username`**: Follow an X/Twitter user by username
16 | - **`get_twitter_profile_from_username`**: Get complete X/Twitter profile data by username
17 | - **`get_twitter_user_id_from_username`**: Get X/Twitter user ID from username
18 | - **`get_last_tweet_and_replies_from_user`**: Get recent X/Twitter posts and replies from a user
19 | - **`get_last_tweet_from_user`**: Get recent X/Twitter posts from a user
20 | - **`get_own_twitter_account_info`**: Get current account profile data
21 |
22 | ## Installation and Usage
23 |
24 | ### Local Installation
25 |
26 | ```bash
27 | # Clone the repository
28 | git clone https://github.com/0xhijo/mcp_twitter.git
29 |
30 | # Install dependencies and build the project
31 | pnpm build
32 |
33 | # Launch the server
34 | node ./build/index.js
35 | ```
36 | ### Installation via NPX
37 | ```bash
38 | npx mcp_twitter
39 | ```
40 |
41 | ## Configuration
42 |
43 | ### Configuration via Twitter Scraper
44 |
45 | 1. Configure the .env file:
46 |
47 | ```sh
48 | TWITTER_AUTH_MODE = "CREDENTIALS" # Credentials mode
49 |
50 | # Your Twitter credentials
51 |
52 | TWITTER_USERNAME="YOUR_TWITTER_USERNAME"
53 | TWITTER_PASSWORD="YOUR_TWITTER_PASSWORD"
54 | TWITTER_EMAIL="YOUR_TWITTER_EMAIL"
55 | ```
56 |
57 | You need to configure Twitter authentication by creating a `.env` file or directly adding the variables to your environment.
58 |
59 | ### Configuration via Twitter API
60 |
61 | 1. Create a Developer Account:
62 |
63 | Make sure you have a Twitter account
64 | Visit the Developer Platform
65 | Get your API credentials
66 | Follow this guide if you need help creating your developer account
67 |
68 | 2. Configure the .env file
69 |
70 | ```sh
71 | TWITTER_AUTH_MODE = "API" # API mode
72 |
73 | # Your CREDENTIALS obtained from the Developer Platform
74 |
75 | TWITTER_API="YOUR_TWITTER_API"
76 | TWITTER_API_SECRET="YOUR_TWITTER_API_SECRET"
77 | TWITTER_ACCESS_TOKEN="YOUR_TWITTER_ACCESS_TOKEN"
78 | TWITTER_ACCESS_TOKEN_SECRET="YOUR_TWITTER_ACCESS_TOKEN_SECRET"
79 | ```
80 | ## Integrating with Claude
81 | To use MCP Twitter with Claude, you need to add it to your `claude_mcp_config.json` file. This will allow Claude to interact with Twitter through the MCP server.
82 |
83 | ### Adding to Claude's MCP Configuration
84 | Add the following entry to your `claude_mcp_config.json` file:
85 |
86 | ```json
87 | "mcp_twitter": {
88 | "command": "npx",
89 | "args": ["mcp_twitter"],
90 | "env": {
91 | "TWITTER_AUTH_MODE": "CREDENTIALS",
92 | "TWITTER_USERNAME": "YOUR_TWITTER_USERNAME",
93 | "TWITTER_PASSWORD": "YOUR_TWITTER_PASSWORD",
94 | "TWITTER_EMAIL": "YOUR_TWITTER_EMAIL"
95 | }
96 | }
97 | ```
98 | Replace the placeholder credentials with your actual Twitter account information. This configuration will launch the MCP Twitter server using npx when Claude needs to interact with Twitter.
99 |
100 | ### Usage with Claude
101 | Once configured, Claude will be able to use all the Twitter functionalities provided by the MCP server, such as creating posts, retrieving tweets, and more. You can simply ask Claude to perform Twitter actions, and it will utilize the MCP server to execute them.
102 |
103 |
104 |
105 |
106 | ## Important Notes
107 | - Choose the authentication mode (API or CREDENTIALS) based on your needs
108 | - Verify that your credentials are properly configured in the .env file
109 | - Check the official documentation for more details about API limitations
110 |
111 |
112 |
113 |
114 |
115 |
```
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | export type TweetType = {
2 | id: string;
3 | content: string;
4 | };
5 |
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "outDir": "./build",
7 | "rootDir": "./src",
8 | "strict": true,
9 | "esModuleInterop": true,
10 | "skipLibCheck": true,
11 | "forceConsistentCasingInFileNames": true
12 | },
13 | "include": ["src/**/*"],
14 | "exclude": ["node_modules"]
15 | }
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "mcp_twitter",
3 | "version": "1.0.1",
4 | "main": "index.js",
5 | "type": "module",
6 | "bin": {
7 | "mcp_twitter": "./build/index.js"
8 | },
9 | "scripts": {
10 | "build": "tsc && chmod 755 build/index.js",
11 | "clean": "rm -rf build",
12 | "clean:all": "rm -rf build node_modules",
13 | "start": "node build/index.js"
14 | },
15 | "files": [
16 | "build"
17 | ],
18 | "keywords": [
19 | "twitter",
20 | "agent",
21 | "mcp"
22 | ],
23 | "author": "0xhijo",
24 | "license": "MIT",
25 | "description": "",
26 | "dependencies": {
27 | "@modelcontextprotocol/sdk": "^1.7.0",
28 | "agent-twitter-client": "^0.0.18",
29 | "dotenv": "^16.4.7",
30 | "twitter-api-v2": "^1.19.1",
31 | "zod": "^3.24.2"
32 | },
33 | "devDependencies": {
34 | "@types/node": "^22.13.10",
35 | "typescript": "^5.8.2"
36 | }
37 | }
38 |
```
--------------------------------------------------------------------------------
/src/schema/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { z } from 'zod';
2 |
3 | export const createTwitterpostSchema = z.object({
4 | post: z.string().describe('This is the string you want to post on X'),
5 | });
6 |
7 | export const getLastUserXTweetSchema = z.object({
8 | account_name: z
9 | .string()
10 | .describe('This is the account_name you want to get the latest tweet'),
11 | });
12 |
13 | export const ReplyTweetSchema = z.object({
14 | tweet_id: z.string().describe('The tweet id you want to reply'),
15 | response_text: z
16 | .string()
17 | .describe('This is the response you will send to the tweet'),
18 | });
19 |
20 | export const getLastTweetsOptionsSchema = z.object({
21 | query: z
22 | .string()
23 | .describe(
24 | 'The search query . Any Twitter-compatible query format can be used'
25 | ),
26 | maxTeets: z.number().describe('The max tweets you want to get'),
27 | reply: z
28 | .boolean()
29 | .describe('If you want to include replyed tweet in your request'),
30 | });
31 |
32 | export const FollowXUserFromUsernameSchema = z.object({
33 | username: z.string().describe('The username you want to follow'),
34 | });
35 |
36 | export const getTwitterProfileFromUsernameSchema = z.object({
37 | username: z.string().describe('The username you want to get the profile'),
38 | });
39 |
40 | export const getTwitterUserIdFromUsernameSchema = z.object({
41 | username: z.string().describe('The username you want get the user_id'),
42 | });
43 |
44 | export const getLastTweetsAndRepliesFromUserSchema = z.object({
45 | username: z
46 | .string()
47 | .describe('The username you want to get last tweets and replies'),
48 | maxTweets: z
49 | .number()
50 | .describe('The number of tweets/replies you want to get from a User')
51 | .optional(),
52 | });
53 |
54 | export const getLastTweetsFromUserSchema = z.object({
55 | username: z.string().describe('The username you want to get last tweets'),
56 | maxTweets: z
57 | .number()
58 | .describe('The number of tweets you want to get from a User')
59 | .optional(),
60 | });
61 |
62 | export const createAndPostTwitterThreadSchema = z.object({
63 | thread: z
64 | .array(z.string())
65 | .describe(
66 | 'This is the array of where every index of this array contain a part of your thread'
67 | ),
68 | });
69 |
70 | export type getLastUserXTweetParams = z.infer<typeof getLastUserXTweetSchema>;
71 | export type ReplyTweetParams = z.infer<typeof ReplyTweetSchema>;
72 | export type getLastTweetsOptionsParams = z.infer<
73 | typeof getLastTweetsOptionsSchema
74 | >;
75 | export type FollowXUserFromUsernameParams = z.infer<
76 | typeof FollowXUserFromUsernameSchema
77 | >;
78 | export type getTwitterProfileFromUsernameParams = z.infer<
79 | typeof getTwitterProfileFromUsernameSchema
80 | >;
81 | export type getTwitterUserIdFromUsernameParams = z.infer<
82 | typeof getTwitterUserIdFromUsernameSchema
83 | >;
84 | export type getLastTweetsAndRepliesFromUserParams = z.infer<
85 | typeof getLastTweetsAndRepliesFromUserSchema
86 | >;
87 | export type getLastTweetsFromUserParams = z.infer<
88 | typeof getLastTweetsFromUserSchema
89 | >;
90 | export type createAndPostTwitterThreadParams = z.infer<
91 | typeof createAndPostTwitterThreadSchema
92 | >;
93 | export type creatTwitterPostParams = z.infer<typeof createTwitterpostSchema>;
94 |
```
--------------------------------------------------------------------------------
/src/interfaces/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { Scraper } from "agent-twitter-client";
2 | import { TwitterApi } from "twitter-api-v2";
3 |
4 | export interface TwitterScraperConfig {
5 | twitter_scraper: Scraper;
6 | twitter_id: string;
7 | twitter_username: string;
8 | }
9 |
10 | export interface TwitterApiConfig {
11 | twitter_api: string;
12 | twitter_api_secret: string;
13 | twitter_access_token: string;
14 | twitter_access_token_secret: string;
15 | twitter_api_client: TwitterApi;
16 | }
17 |
18 | export class TwitterManager {
19 | twitterManager: TwitterScraperConfig | TwitterApiConfig | undefined;
20 | twitter_auth_mode: "API" | "CREDENTIALS";
21 | constructor() {
22 | this.twitterManager = undefined;
23 | this.twitter_auth_mode = "API";
24 | }
25 |
26 | public async initializeTwitterManager(): Promise<void> {
27 | if (process.env.TWITTER_AUTH_MODE === "CREDENTIALS") {
28 | const username = process.env.TWITTER_USERNAME;
29 | const password = process.env.TWITTER_PASSWORD;
30 | const email = process.env.TWITTER_EMAIL;
31 |
32 | if (!username || !password) {
33 | throw new Error(
34 | "Error when try to initializeTwitterManager in CREDENTIALS twitter_auth_mode check your .env"
35 | );
36 | }
37 | const user_client = new Scraper();
38 |
39 | await user_client.login(username, password, email);
40 | const account = await user_client.me();
41 | if (!account) {
42 | throw new Error("Impossible to get your twitter account information");
43 | }
44 | const userClient: TwitterScraperConfig = {
45 | twitter_scraper: user_client,
46 | twitter_id: account?.userId as string,
47 | twitter_username: account?.username as string,
48 | };
49 | this.twitterManager = userClient;
50 | this.twitter_auth_mode = "CREDENTIALS";
51 | } else if (process.env.TWITTER_AUTH_MODE === "API") {
52 | const twitter_api = process.env.TWITTER_API;
53 | const twitter_api_secret = process.env.TWITTER_API_SECRET;
54 | const twitter_access_token = process.env.TWITTER_ACCESS_TOKEN;
55 | const twitter_access_token_secret =
56 | process.env.TWITTER_ACCESS_TOKEN_SECRET;
57 |
58 | if (
59 | !twitter_api ||
60 | !twitter_api_secret ||
61 | !twitter_access_token ||
62 | !twitter_access_token_secret
63 | ) {
64 | throw new Error(
65 | "Error when try to initializeTwitterManager in API twitter_auth_mode check your .env"
66 | );
67 | }
68 |
69 | const userClient = new TwitterApi({
70 | appKey: twitter_api,
71 | appSecret: twitter_api_secret,
72 | accessToken: twitter_access_token,
73 | accessSecret: twitter_access_token_secret,
74 | });
75 | if (!userClient) {
76 | throw new Error(
77 | "Error when trying to createn you Twitter API Account check your API Twitter CREDENTIALS"
78 | );
79 | }
80 |
81 | const apiConfig: TwitterApiConfig = {
82 | twitter_api: twitter_api,
83 | twitter_api_secret: twitter_api_secret,
84 | twitter_access_token: twitter_access_token,
85 | twitter_access_token_secret: twitter_access_token_secret,
86 | twitter_api_client: userClient,
87 | };
88 | this.twitterManager = apiConfig;
89 | this.twitter_auth_mode = "API";
90 | } else {
91 | throw new Error(
92 | "Error when try to initializeTwitterManager check your .env"
93 | );
94 | }
95 | }
96 | public getTwitterManager(): TwitterScraperConfig | TwitterApiConfig {
97 | if (!this.twitterManager) {
98 | throw new Error("Twitter Manager is undefined");
99 | }
100 | return this.twitterManager;
101 | }
102 | public getTwitterAuthMode(): "API" | "CREDENTIALS" {
103 | return this.twitter_auth_mode;
104 | }
105 | }
106 |
107 |
108 | export interface TwitterTool<P = any> {
109 | name: string;
110 | description: string;
111 | schema?: Zod.AnyZodObject;
112 | execute: (
113 | twitter: TwitterManager,
114 | params: P,
115 | plugins_manager?: any
116 | ) => Promise<unknown>;
117 | }
118 |
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
1 | #!/usr/bin/env node
2 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4 | import { TwitterManager, TwitterTool } from "./interfaces/index.js";
5 | import dotenv from "dotenv";
6 | import {
7 | createAndPostTwitterThread,
8 | createTwitterpost,
9 | FollowXUserFromUsername,
10 | getLastTweetsAndRepliesFromUser,
11 | getLastTweetsFromUser,
12 | getLastTweetsOptions,
13 | getLastUserTweet,
14 | getOwnTwitterAccountInfo,
15 | getTwitterProfileFromUsername,
16 | getTwitterUserIdFromUsername,
17 | ReplyTweet,
18 | } from "./tools/twitter.js";
19 | import {
20 | createAndPostTwitterThreadSchema,
21 | createTwitterpostSchema,
22 | FollowXUserFromUsernameSchema,
23 | getLastTweetsAndRepliesFromUserSchema,
24 | getLastTweetsFromUserSchema,
25 | getLastTweetsOptionsSchema,
26 | getLastUserXTweetSchema,
27 | getTwitterProfileFromUsernameSchema,
28 | getTwitterUserIdFromUsernameSchema,
29 | ReplyTweetSchema,
30 | } from "./schema/index.js";
31 |
32 | dotenv.config();
33 |
34 | // Create server instance
35 | const server = new McpServer({
36 | name: "twitter",
37 | version: "1.0.0",
38 | });
39 |
40 | export const registerTools = (TwitterToolRegistry: TwitterTool[]) => {
41 | TwitterToolRegistry.push({
42 | name: "create_twitter_post",
43 | description: "Create new X/Twitter post",
44 | schema: createTwitterpostSchema,
45 | execute: createTwitterpost,
46 | });
47 |
48 | TwitterToolRegistry.push({
49 | name: "reply_twitter_tweet",
50 | description: "Reply to specific X/Twitter post by ID",
51 | schema: ReplyTweetSchema,
52 | execute: ReplyTweet,
53 | });
54 |
55 | TwitterToolRegistry.push({
56 | name: "get_last_tweet",
57 | description: "Get most recent post from specified X/Twitter account",
58 | schema: getLastUserXTweetSchema,
59 | execute: getLastUserTweet,
60 | });
61 |
62 | TwitterToolRegistry.push({
63 | name: "get_last_tweets_options",
64 | description: "Get specified number of posts matching search query",
65 | schema: getLastTweetsOptionsSchema,
66 | execute: getLastTweetsOptions,
67 | });
68 |
69 | TwitterToolRegistry.push({
70 | name: "create_and_post_twitter_thread",
71 | description: "Create and publish X/Twitter thread",
72 | schema: createAndPostTwitterThreadSchema,
73 | execute: createAndPostTwitterThread,
74 | });
75 |
76 | TwitterToolRegistry.push({
77 | name: "follow_twitter_from_username",
78 | description: "Follow X/Twitter user by username",
79 | schema: FollowXUserFromUsernameSchema,
80 | execute: FollowXUserFromUsername,
81 | });
82 |
83 | TwitterToolRegistry.push({
84 | name: "get_twitter_profile_from_username",
85 | description: "Get full X/Twitter profile data by username",
86 | schema: getTwitterProfileFromUsernameSchema,
87 | execute: getTwitterProfileFromUsername,
88 | });
89 |
90 | TwitterToolRegistry.push({
91 | name: "get_twitter_user_id_from_username",
92 | description: "Get X/Twitter user ID from username",
93 | schema: getTwitterUserIdFromUsernameSchema,
94 | execute: getTwitterUserIdFromUsername,
95 | });
96 |
97 | TwitterToolRegistry.push({
98 | name: "get_last_tweet_and_replies_from_user",
99 | description: "Get recent X/Twitter posts and replies from user",
100 | schema: getLastTweetsAndRepliesFromUserSchema,
101 | execute: getLastTweetsAndRepliesFromUser,
102 | });
103 |
104 | TwitterToolRegistry.push({
105 | name: "get_last_tweet_from_user",
106 | description: "Get recent X/Twitter posts from user",
107 | schema: getLastTweetsFromUserSchema,
108 | execute: getLastTweetsFromUser,
109 | });
110 |
111 | TwitterToolRegistry.push({
112 | name: "get_own_twitter_account_info",
113 | description: "Get current account profile data",
114 | execute: getOwnTwitterAccountInfo,
115 | });
116 | };
117 |
118 | export const RegisterToolInServer = async (twitter: TwitterManager) => {
119 | const tools: TwitterTool[] = [];
120 | await registerTools(tools);
121 | for (const tool of tools) {
122 | if (!tool.schema) {
123 | server.tool(tool.name, tool.description, async () => {
124 | const result = await tool.execute(twitter, {});
125 | return {
126 | content: [
127 | {
128 | type: "text",
129 | text: JSON.stringify(result),
130 | },
131 | ],
132 | };
133 | });
134 | } else {
135 | server.tool(
136 | tool.name,
137 | tool.description,
138 | tool.schema.shape,
139 | async (params: any, extra: any) => {
140 | const result = await tool.execute(twitter, params);
141 | return {
142 | content: [
143 | {
144 | type: "text",
145 | text: JSON.stringify(result),
146 | },
147 | ],
148 | };
149 | }
150 | );
151 | }
152 | }
153 | };
154 |
155 | const checkEnv = (auth_mode: string): boolean => {
156 | let key;
157 | if (auth_mode === "CREDENTIALS") {
158 | key = ["TWITTER_USERNAME", "TWITTER_PASSWORD", "TWITTER_EMAIL"];
159 | } else if (auth_mode === "API") {
160 | key = [
161 | "TWITTER_API",
162 | "TWITTER_API_SECRET",
163 | "TWITTER_ACCESS_TOKEN",
164 | "TWITTER_ACCESS_TOKEN_SECRET",
165 | ];
166 | } else {
167 | console.error(`Invalid auth_mode: ${auth_mode}`);
168 | return false;
169 | }
170 | for (const k of key) {
171 | const value = process.env[k];
172 | if (!value) {
173 | console.error(`Missing required environment variable: ${k}`);
174 | return false;
175 | }
176 | return true;
177 | }
178 | return true;
179 | };
180 |
181 | async function main() {
182 | const transport = new StdioServerTransport();
183 | if (!checkEnv(process.env.TWITTER_AUTH_MODE as string)) {
184 | console.error("Failed to initialize TwitterManager");
185 | process.exit(1);
186 | }
187 | const twitter = new TwitterManager();
188 | twitter.initializeTwitterManager();
189 | await RegisterToolInServer(twitter);
190 | await server.connect(transport);
191 | console.error("Weather MCP Server running on stdio");
192 | }
193 |
194 | main().catch((error) => {
195 | console.error("Fatal error in main():", error);
196 | process.exit(1);
197 | });
198 |
```
--------------------------------------------------------------------------------
/src/tools/twitter.ts:
--------------------------------------------------------------------------------
```typescript
1 | import { TwitterManager } from "../interfaces/index.js";
2 | import {
3 | createAndPostTwitterThreadParams,
4 | creatTwitterPostParams,
5 | FollowXUserFromUsernameParams,
6 | getLastTweetsAndRepliesFromUserParams,
7 | getLastTweetsFromUserParams,
8 | getLastTweetsOptionsParams,
9 | getLastUserXTweetParams,
10 | getTwitterProfileFromUsernameParams,
11 | getTwitterUserIdFromUsernameParams,
12 | ReplyTweetParams,
13 | } from "../schema/index.js";
14 | import { TweetType } from "../types/index.js";
15 |
16 | /**
17 | * Retrieves the latest tweet from a specified user
18 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
19 | * @param {getLastUserXTweetParams} params - Parameters containing the account name to fetch from
20 | * @returns {Promise<{status: string, post_id?: string, post_text?: string, error?: any}>} The latest tweet information or error
21 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
22 | */
23 | export const getLastUserTweet = async (
24 | twitter: TwitterManager,
25 | params: getLastUserXTweetParams
26 | ) => {
27 | try {
28 | console.log("GetLastUserTweet");
29 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
30 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
31 | }
32 | const twitter_manager = twitter.getTwitterManager();
33 | if (!twitter_manager) {
34 | throw new Error("twitter_client is undefined");
35 | }
36 | if (!("twitter_scraper" in twitter_manager)) {
37 | throw new Error(
38 | "Invalid twitter client configuration for this operation"
39 | );
40 | }
41 | const twitter_client = twitter_manager.twitter_scraper;
42 | if (!twitter_client) {
43 | throw new Error("twitter_client is undefined");
44 | }
45 | if (!twitter_client) {
46 | throw new Error("twitter_client is undefined");
47 | }
48 |
49 | const lastestTweet = await twitter_client.getLatestTweet(
50 | params.account_name
51 | );
52 | if (!lastestTweet) {
53 | throw new Error("Error trying to get the latest tweet");
54 | }
55 | return {
56 | status: "success",
57 | post_id: lastestTweet.id,
58 | post_text: lastestTweet.text,
59 | };
60 | } catch (error) {
61 | console.log(error);
62 | return {
63 | status: "failure",
64 | error: error,
65 | };
66 | }
67 | };
68 |
69 | /**
70 | * Searches tweets based on specific query and maximum tweet count
71 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
72 | * @param {getLastTweetsOptionsParams} params - Parameters containing search query and maximum tweets to fetch
73 | * @returns {Promise<{status: string, result?: TweetType[], error?: any}>} Collection of matching tweets or error
74 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
75 | */
76 | export const getLastTweetsOptions = async (
77 | twitter: TwitterManager,
78 | params: getLastTweetsOptionsParams
79 | ) => {
80 | try {
81 | console.log("GetLastTweetsOptions");
82 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
83 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
84 | }
85 | const twitter_manager = twitter.getTwitterManager();
86 | if (!twitter_manager) {
87 | throw new Error("twitter_client is undefined");
88 | }
89 | if (!("twitter_scraper" in twitter_manager)) {
90 | throw new Error(
91 | "Invalid twitter client configuration for this operation"
92 | );
93 | }
94 | const twitter_client = twitter_manager.twitter_scraper;
95 | if (!twitter_client) {
96 | throw new Error("twitter_client is undefined");
97 | }
98 | const collectedTweets: TweetType[] = [];
99 |
100 | const tweets = twitter_client.searchTweets(params.query, params.maxTeets);
101 | for await (const tweet of tweets) {
102 | const tweet_type: TweetType = {
103 | id: tweet.id as string,
104 | content: tweet.text as string,
105 | };
106 | console.log(tweet.id);
107 | console.log(tweet.text);
108 | collectedTweets.push(tweet_type);
109 | }
110 | console.log(collectedTweets);
111 | return {
112 | status: "success",
113 | result: collectedTweets,
114 | };
115 | } catch (error) {
116 | console.log(error);
117 | return {
118 | status: "failure",
119 | error: error,
120 | };
121 | }
122 | };
123 |
124 | /**
125 | * Retrieves information about the authenticated Twitter account set in .env
126 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
127 | * @returns {Promise<{status: string, my_account_username?: string, error?: any}>} Account information or error
128 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
129 | */
130 | export const getOwnTwitterAccountInfo = async (twitter: TwitterManager) => {
131 | try {
132 | console.log("getOwnTwitterAccountInfo");
133 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
134 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
135 | }
136 | const twitter_manager = twitter.getTwitterManager();
137 | if (!twitter_manager) {
138 | throw new Error("twitter_client is undefined");
139 | }
140 | if (!("twitter_scraper" in twitter_manager)) {
141 | throw new Error(
142 | "Invalid twitter client configuration for this operation"
143 | );
144 | }
145 | const twitter_client = twitter_manager.twitter_scraper;
146 | if (!twitter_client) {
147 | throw new Error("twitter_client is undefined");
148 | }
149 | if (!twitter_client) {
150 | throw new Error("twitter_client is undefined");
151 | }
152 |
153 | const my_twitter_account = await twitter_client.me();
154 | console.log(my_twitter_account);
155 | return {
156 | status: "success",
157 | my_account_username: my_twitter_account,
158 | };
159 | } catch (error) {
160 | console.log(error);
161 | return {
162 | status: "failure",
163 | error: error,
164 | };
165 | }
166 | };
167 |
168 | /**
169 | * Fetches recent tweets from a specified user
170 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
171 | * @param {getLastTweetsFromUserParams} params - Parameters containing username and optional tweet limit
172 | * @returns {Promise<{status: string, tweets?: TweetType[], error?: any}>} Collection of user's tweets or error
173 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
174 | */
175 | export const getLastTweetsFromUser = async (
176 | twitter: TwitterManager,
177 | params: getLastTweetsFromUserParams
178 | ) => {
179 | console.log("getLastTweetsFromUser");
180 | try {
181 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
182 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
183 | }
184 | const twitter_manager = twitter.getTwitterManager();
185 | if (!twitter_manager) {
186 | throw new Error("twitter_client is undefined");
187 | }
188 | if (!("twitter_scraper" in twitter_manager)) {
189 | throw new Error(
190 | "Invalid twitter client configuration for this operation"
191 | );
192 | }
193 | const twitter_client = twitter_manager.twitter_scraper;
194 | if (!twitter_client) {
195 | throw new Error("twitter_client is undefined");
196 | }
197 | if (!twitter_client) {
198 | throw new Error("twitter_client is undefined");
199 | }
200 | const tweets = params.maxTweets
201 | ? twitter_client.getTweets(params.username, params.maxTweets)
202 | : twitter_client.getTweets(params.username);
203 | const collectedTweets: TweetType[] = [];
204 | for await (const tweet of tweets) {
205 | const tweet_type: TweetType = {
206 | id: tweet.id as string,
207 | content: tweet.text as string,
208 | };
209 | collectedTweets.push(tweet_type);
210 | }
211 |
212 | return {
213 | status: "success",
214 | tweets: collectedTweets,
215 | };
216 | } catch (error) {
217 | console.log(error);
218 | return {
219 | status: "failure",
220 | error: error,
221 | };
222 | }
223 | };
224 |
225 | /**
226 | * Retrieves recent tweets and replies from a specified user
227 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
228 | * @param {getLastTweetsAndRepliesFromUserParams} params - Parameters containing username and optional tweet limit
229 | * @returns {Promise<{status: string, tweets?: TweetType[], error?: any}>} Collection of user's tweets and replies or error
230 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
231 | */
232 | export const getLastTweetsAndRepliesFromUser = async (
233 | twitter: TwitterManager,
234 | params: getLastTweetsAndRepliesFromUserParams
235 | ) => {
236 | try {
237 | console.log("getLastTweetsAndRepliesFromUser");
238 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
239 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
240 | }
241 | const twitter_manager = twitter.getTwitterManager();
242 | if (!twitter_manager) {
243 | throw new Error("twitter_client is undefined");
244 | }
245 | if (!("twitter_scraper" in twitter_manager)) {
246 | throw new Error(
247 | "Invalid twitter client configuration for this operation"
248 | );
249 | }
250 | const twitter_client = twitter_manager.twitter_scraper;
251 | if (!twitter_client) {
252 | throw new Error("twitter_client is undefined");
253 | }
254 | if (!twitter_client) {
255 | throw new Error("twitter_client is undefined");
256 | }
257 | const tweets = params.maxTweets
258 | ? twitter_client.getTweetsAndReplies(params.username, params.maxTweets)
259 | : twitter_client.getTweetsAndReplies(params.username);
260 |
261 | const collectedTweets: TweetType[] = [];
262 | for await (const tweet of tweets) {
263 | const tweet_type: TweetType = {
264 | id: tweet.id as string,
265 | content: tweet.text as string,
266 | };
267 | collectedTweets.push(tweet_type);
268 | }
269 |
270 | return {
271 | status: "success",
272 | tweets: collectedTweets,
273 | };
274 | } catch (error) {
275 | console.log(error);
276 | return {
277 | status: "failure",
278 | error: error,
279 | };
280 | }
281 | };
282 |
283 | /**
284 | * Gets Twitter user ID from a username
285 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
286 | * @param {getTwitterUserIdFromUsernameParams} params - Parameters containing the username to look up
287 | * @returns {Promise<{status: string, user_id?: string, error?: any}>} User ID information or error
288 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
289 | */
290 | export const getTwitterUserIdFromUsername = async (
291 | twitter: TwitterManager,
292 | params: getTwitterUserIdFromUsernameParams
293 | ) => {
294 | try {
295 | console.log("getTwitterUserIdFromUsername");
296 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
297 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
298 | }
299 | const twitter_manager = twitter.getTwitterManager();
300 | if (!twitter_manager) {
301 | throw new Error("twitter_client is undefined");
302 | }
303 | if (!("twitter_scraper" in twitter_manager)) {
304 | throw new Error(
305 | "Invalid twitter client configuration for this operation"
306 | );
307 | }
308 | const twitter_client = twitter_manager.twitter_scraper;
309 | if (!twitter_client) {
310 | throw new Error("twitter_client is undefined");
311 | }
312 | if (!twitter_client) {
313 | throw new Error("twitter_client is undefined");
314 | }
315 | const userId = await twitter_client.getUserIdByScreenName(params.username);
316 | return {
317 | status: "success",
318 | user_id: userId,
319 | };
320 | } catch (error) {
321 | console.log(error);
322 | return {
323 | status: "failure",
324 | error: error,
325 | };
326 | }
327 | };
328 |
329 | /**
330 | * Retrieves Twitter profile information from a username
331 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
332 | * @param {getTwitterProfileFromUsernameParams} params - Parameters containing the username to fetch profile for
333 | * @returns {Promise<{status: string, user_id?: any, error?: any}>} Profile information or error
334 | * @throws {Error} When not in CREDENTIALS mode, client is undefined, or account doesn't exist
335 | */
336 | export const getTwitterProfileFromUsername = async (
337 | twitter: TwitterManager,
338 | params: getTwitterProfileFromUsernameParams
339 | ) => {
340 | try {
341 | console.log("geTwitterUserIdFromUsername");
342 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
343 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
344 | }
345 | const twitter_manager = twitter.getTwitterManager();
346 | if (!twitter_manager) {
347 | throw new Error("twitter_client is undefined");
348 | }
349 | if (!("twitter_scraper" in twitter_manager)) {
350 | throw new Error(
351 | "Invalid twitter client configuration for this operation"
352 | );
353 | }
354 | const twitter_client = twitter_manager.twitter_scraper;
355 | if (!twitter_client) {
356 | throw new Error("twitter_client is undefined");
357 | }
358 | if (!twitter_client) {
359 | throw new Error("twitter_client is undefined");
360 | }
361 | const userId = await twitter_client.getProfile(params.username);
362 | if (!userId) {
363 | throw new Error(`Account don't exist`);
364 | }
365 | return {
366 | status: "success",
367 | user_id: userId,
368 | };
369 | } catch (error) {
370 | console.log(error);
371 | return {
372 | status: "failure",
373 | error: error,
374 | };
375 | }
376 | };
377 |
378 | /**
379 | * Creates a new Twitter post using either credentials or API authentication
380 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
381 | * @param {creatTwitterPostParams} params - Parameters containing the post content
382 | * @returns {Promise<{status: string, result?: any}>} Result object indicating success/failure and optional API response
383 | * @throws {Error} When neither Twitter API nor Account credentials are set
384 | */
385 | export const createTwitterpost = async (
386 | twitter: TwitterManager,
387 | params: creatTwitterPostParams
388 | ) => {
389 | try {
390 | const twitter_auth_mode = twitter.getTwitterAuthMode();
391 | if (twitter_auth_mode === "CREDENTIALS") {
392 | console.log("CREDENTIALS");
393 | const twitter_manager = twitter.getTwitterManager();
394 | if (!twitter_manager) {
395 | throw new Error("twitter_client is undefined");
396 | }
397 | if (!("twitter_scraper" in twitter_manager)) {
398 | throw new Error(
399 | "Invalid twitter client configuration for this operation"
400 | );
401 | }
402 | const twitter_client = twitter_manager.twitter_scraper;
403 | if (!twitter_client) {
404 | throw new Error("twitter_client is undefined");
405 | }
406 | await twitter_client.sendTweet(params.post);
407 | return {
408 | status: "success",
409 | };
410 | }
411 | if (twitter_auth_mode === "API") {
412 | const twitter_manager = twitter.getTwitterManager();
413 | if (!twitter_manager) {
414 | throw new Error("twitter_client is undefined");
415 | }
416 | if (!("twitter_api_client" in twitter_manager)) {
417 | throw new Error(
418 | "Invalid twitter client configuration for this operation"
419 | );
420 | }
421 | const twitter_client = twitter_manager.twitter_api_client;
422 | if (!twitter_client) {
423 | throw new Error("twitter_client is undefined");
424 | }
425 |
426 | const result = await twitter_client.v2.tweet({
427 | text: params.post,
428 | });
429 | return {
430 | status: "success",
431 | result: result,
432 | };
433 | } else {
434 | throw new Error(`You don't set Twitter API or Twitter Account`);
435 | }
436 | } catch (error) {
437 | console.log(error);
438 | return {
439 | status: "failed",
440 | };
441 | }
442 | };
443 |
444 | /**
445 | * Replies to a specific tweet using Twitter credentials
446 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
447 | * @param {ReplyTweetParams} params - Parameters containing the tweet ID to reply to and response text
448 | * @returns {Promise<{status: string, tweet_id?: string, response_text?: string, error?: any}>} Result object with operation status
449 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
450 | */
451 | export const ReplyTweet = async (
452 | twitter: TwitterManager,
453 | params: ReplyTweetParams
454 | ) => {
455 | try {
456 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
457 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
458 | }
459 | const twitter_manager = twitter.getTwitterManager();
460 | if (!twitter_manager) {
461 | throw new Error("twitter_client is undefined");
462 | }
463 | if (!("twitter_scraper" in twitter_manager)) {
464 | throw new Error(
465 | "Invalid twitter client configuration for this operation"
466 | );
467 | }
468 | const twitter_client = twitter_manager.twitter_scraper;
469 | if (!twitter_client) {
470 | throw new Error("twitter_client is undefined");
471 | }
472 | await twitter_client.sendTweet(params.response_text, params.tweet_id);
473 | return {
474 | status: "success",
475 | tweet_id: params.tweet_id,
476 | response_text: params.response_text,
477 | };
478 | } catch (error) {
479 | console.log(error);
480 | return {
481 | status: "failure",
482 | error: error,
483 | };
484 | }
485 | };
486 |
487 | /**
488 | * Creates and posts a Twitter thread from an array of messages
489 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
490 | * @param {createAndPostTwitterThreadParams} params - Parameters containing array of thread messages
491 | * @returns {Promise<{status: string, error?: any}>} Result object indicating thread posting status
492 | * @throws {Error} When thread is empty, not in CREDENTIALS mode, or client is undefined
493 | */
494 | export const createAndPostTwitterThread = async (
495 | twitter: TwitterManager,
496 | params: createAndPostTwitterThreadParams
497 | ) => {
498 | try {
499 | console.log("CreateTwitterThread");
500 | const thread_size = params.thread.length;
501 | if (thread_size <= 0) {
502 | throw new Error("Your array of thread is empty");
503 | }
504 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
505 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
506 | }
507 | const twitter_manager = twitter.getTwitterManager();
508 | if (!twitter_manager) {
509 | throw new Error("twitter_client is undefined");
510 | }
511 | if (!("twitter_scraper" in twitter_manager)) {
512 | throw new Error(
513 | "Invalid twitter client configuration for this operation"
514 | );
515 | }
516 | const twitter_client = twitter_manager.twitter_scraper;
517 | if (!twitter_client) {
518 | throw new Error("twitter_client is undefined");
519 | }
520 | for (const [index, thread] of params.thread.entries()) {
521 | if (index === 0) {
522 | await twitter_client.sendTweet(thread);
523 | console.log(`Thread part ${index} = ${thread}`);
524 | continue;
525 | }
526 | let last_tweet_id;
527 | let conversation_id;
528 | const tweets = twitter_client.getTweetsAndRepliesByUserId(
529 | twitter_manager.twitter_id,
530 | 10
531 | );
532 | let i = 0;
533 | for await (const tweet of tweets) {
534 | if (i === 0) {
535 | last_tweet_id = tweet.id;
536 | conversation_id = tweet.conversationId;
537 | i = 1;
538 | continue;
539 | }
540 | if (tweet.conversationId === conversation_id) {
541 | last_tweet_id = tweet.id;
542 | continue;
543 | }
544 | }
545 |
546 | await twitter_client.sendTweet(thread, last_tweet_id);
547 | }
548 | return {
549 | status: "success",
550 | };
551 | } catch (error) {
552 | console.log(error);
553 | return {
554 | status: "failure",
555 | error: error,
556 | };
557 | }
558 | };
559 |
560 | /**
561 | * Follows a Twitter user specified by username
562 | * @param {TwitterManager} twitter - The Starknet twitter instance containing Twitter authentication
563 | * @param {FollowXUserFromUsernameParams} params - Parameters containing the username to follow
564 | * @returns {Promise<{status: string, error?: any}>} Result object indicating follow operation status
565 | * @throws {Error} When not in CREDENTIALS mode or client is undefined
566 | */
567 | export const FollowXUserFromUsername = async (
568 | twitter: TwitterManager,
569 | params: FollowXUserFromUsernameParams
570 | ) => {
571 | try {
572 | console.log("getXUserIdFromUsername");
573 | if (twitter.getTwitterAuthMode() != "CREDENTIALS") {
574 | throw new Error("You need to be in CREDENTIALS twitter_auth_mode");
575 | }
576 | const twitter_manager = twitter.getTwitterManager();
577 | if (!twitter_manager) {
578 | throw new Error("twitter_client is undefined");
579 | }
580 | if (!("twitter_scraper" in twitter_manager)) {
581 | throw new Error(
582 | "Invalid twitter client configuration for this operation"
583 | );
584 | }
585 | const twitter_client = twitter_manager.twitter_scraper;
586 | if (!twitter_client) {
587 | throw new Error("twitter_client is undefined");
588 | }
589 | await twitter_client.followUser(params.username);
590 | return {
591 | status: "success",
592 | };
593 | } catch (error) {
594 | console.log(error);
595 | return {
596 | status: "failure",
597 | error: error,
598 | };
599 | }
600 | };
601 |
```