Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tools/src/aden_tools/credentials/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- github.py: GitHub API credentials
- hubspot.py: HubSpot CRM credentials
- slack.py: Slack workspace credentials
- x.py: X (Twitter) API credentials

Note: Tools that don't need credentials simply omit the 'credentials' parameter
from their register_tools() function. This convention is enforced by CI tests.
Expand All @@ -65,6 +66,7 @@
)
from .slack import SLACK_CREDENTIALS
from .store_adapter import CredentialStoreAdapter
from .x import X_CREDENTIALS

# Merged registry of all credentials
CREDENTIAL_SPECS = {
Expand All @@ -74,6 +76,7 @@
**GITHUB_CREDENTIALS,
**HUBSPOT_CREDENTIALS,
**SLACK_CREDENTIALS,
**X_CREDENTIALS,
}

__all__ = [
Expand Down Expand Up @@ -104,4 +107,5 @@
"GITHUB_CREDENTIALS",
"HUBSPOT_CREDENTIALS",
"SLACK_CREDENTIALS",
"X_CREDENTIALS",
]
106 changes: 106 additions & 0 deletions tools/src/aden_tools/credentials/x.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""
X (Twitter) tool credentials.

Contains credentials for X API v2 integration.
Bearer token for read-only operations, OAuth 1.0a keys for write operations.
"""

from .base import CredentialSpec

_X_TOOLS = [
"x_post_tweet",
"x_reply_tweet",
"x_delete_tweet",
"x_search_tweets",
"x_get_mentions",
"x_send_dm",
]

X_CREDENTIALS = {
"x_bearer_token": CredentialSpec(
env_var="X_BEARER_TOKEN",
tools=_X_TOOLS,
required=True,
startup_required=False,
help_url="https://developer.x.com/en/portal/dashboard",
description="X (Twitter) API v2 Bearer Token for read-only operations",
direct_api_key_supported=True,
api_key_instructions="""To get an X API Bearer Token:
1. Go to https://developer.x.com/en/portal/dashboard
2. Create a Project & App (or select existing)
3. Go to Keys & Tokens tab
4. Copy the Bearer Token
5. Set it as X_BEARER_TOKEN environment variable""",
health_check_endpoint="https://api.x.com/2/users/me",
health_check_method="GET",
credential_id="x_bearer_token",
credential_key="api_key",
credential_group="x",
),
"x_api_key": CredentialSpec(
env_var="X_API_KEY",
tools=_X_TOOLS,
required=False,
startup_required=False,
help_url="https://developer.x.com/en/portal/dashboard",
description="X (Twitter) API Consumer Key for OAuth 1.0a write operations",
direct_api_key_supported=True,
api_key_instructions="""To get your X API Consumer Key:
1. Go to https://developer.x.com/en/portal/dashboard
2. Select your app > Keys and Tokens
3. Under Consumer Keys, copy the API Key""",
credential_id="x_api_key",
credential_key="api_key",
credential_group="x",
),
"x_api_secret": CredentialSpec(
env_var="X_API_SECRET",
tools=_X_TOOLS,
required=False,
startup_required=False,
help_url="https://developer.x.com/en/portal/dashboard",
description="X (Twitter) API Consumer Secret for OAuth 1.0a write operations",
direct_api_key_supported=True,
api_key_instructions="""To get your X API Consumer Secret:
1. Go to https://developer.x.com/en/portal/dashboard
2. Select your app > Keys and Tokens
3. Under Consumer Keys, copy the API Secret""",
credential_id="x_api_secret",
credential_key="api_key",
credential_group="x",
),
"x_access_token": CredentialSpec(
env_var="X_ACCESS_TOKEN",
tools=_X_TOOLS,
required=False,
startup_required=False,
help_url="https://developer.x.com/en/portal/dashboard",
description="X (Twitter) User Access Token for OAuth 1.0a write operations",
direct_api_key_supported=True,
api_key_instructions="""To get your X Access Token:
1. Go to https://developer.x.com/en/portal/dashboard
2. Select your app > Keys and Tokens
3. Under Authentication Tokens, generate Access Token and Secret
4. Copy the Access Token""",
credential_id="x_access_token",
credential_key="api_key",
credential_group="x",
),
"x_access_token_secret": CredentialSpec(
env_var="X_ACCESS_TOKEN_SECRET",
tools=_X_TOOLS,
required=False,
startup_required=False,
help_url="https://developer.x.com/en/portal/dashboard",
description="X (Twitter) User Access Token Secret for OAuth 1.0a write operations",
direct_api_key_supported=True,
api_key_instructions="""To get your X Access Token Secret:
1. Go to https://developer.x.com/en/portal/dashboard
2. Select your app > Keys and Tokens
3. Under Authentication Tokens, generate Access Token and Secret
4. Copy the Access Token Secret""",
credential_id="x_access_token_secret",
credential_key="api_key",
credential_group="x",
),
}
9 changes: 9 additions & 0 deletions tools/src/aden_tools/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
from .slack_tool import register_tools as register_slack
from .web_scrape_tool import register_tools as register_web_scrape
from .web_search_tool import register_tools as register_web_search
from .x_tool import register_tools as register_x


def register_all_tools(
Expand Down Expand Up @@ -75,6 +76,7 @@ def register_all_tools(
register_email(mcp, credentials=credentials)
register_hubspot(mcp, credentials=credentials)
register_slack(mcp, credentials=credentials)
register_x(mcp, credentials=credentials)

# Register file system toolkits
register_view_file(mcp)
Expand Down Expand Up @@ -198,6 +200,13 @@ def register_all_tools(
"slack_kick_user_from_channel",
"slack_delete_file",
"slack_get_team_stats",
# X (Twitter) tools
"x_search_tweets",
"x_get_mentions",
"x_post_tweet",
"x_reply_tweet",
"x_delete_tweet",
"x_send_dm",
]


Expand Down
84 changes: 84 additions & 0 deletions tools/src/aden_tools/tools/x_tool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# X (Twitter) Tool

Hive integration for the X (Twitter) API v2.

Enables agents to post tweets, reply to users, search recent tweets, and monitor mentions — allowing social automation workflows directly inside Hive.

## Features

- Post tweets
- Reply to tweets
- Delete tweets
- Search recent tweets
- Fetch user mentions

## Tools

| Tool | Description |
|--------|-------------|
| x_post_tweet | Post a new tweet |
| x_reply_tweet | Reply to an existing tweet |
| x_delete_tweet | Delete a tweet |
| x_search_tweets | Search recent tweets by query |
| x_get_mentions | Fetch mentions for a user |


## Authentication

This integration uses an **X API v2 Bearer Token**.

### Option 1 — Environment variable

export X_BEARER_TOKEN=your_token_here

### Option 2 — Hive credential store (recommended)

Configure credential id:

x

Hive will automatically inject credentials into all `x_*` tools.

## How to get a Bearer Token

1. Go to https://developer.x.com/
2. Create a Project & App
3. Enable API v2 access
4. Open **Keys & Tokens**
5. Copy the **Bearer Token**

## Example Usage

### Post a tweet

x_post_tweet("Hello from Hive 🚀")

### Reply to a tweet

x_reply_tweet(tweet_id="123456789", text="Thanks for the mention!")

### Search tweets

x_search_tweets(query="AI agents", max_results=5)

### Get mentions

x_get_mentions(user_id="2244994945")

## Notes

- Uses lightweight httpx client (no external SDK)
- Follows HubSpot tool architecture for consistency
- Compatible with Hive CredentialStoreAdapter
- Handles rate limits and common HTTP errors gracefully
- Max results capped at 100 per request (API limit)

## Development

Run tests:

pytest

Start MCP server:

python mcp_server.py
11 changes: 11 additions & 0 deletions tools/src/aden_tools/tools/x_tool/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
X (Twitter) Tool - Post tweets, reply, search, and read mentions via X API v2.

Supports:
- Bearer tokens (X_BEARER_TOKEN)
- OAuth2 tokens via credential store
"""

from .x_tool import register_tools

__all__ = ["register_tools"]
9 changes: 9 additions & 0 deletions tools/src/aden_tools/tools/x_tool/test/test_x_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from aden_tools.credentials.integrations import INTEGRATION_CREDENTIALS


def test_x_credential_spec_exists():
assert "x" in INTEGRATION_CREDENTIALS
spec = INTEGRATION_CREDENTIALS["x"]

assert spec.env_var == "X_BEARER_TOKEN"
assert "x_post_tweet" in spec.tools
23 changes: 23 additions & 0 deletions tools/src/aden_tools/tools/x_tool/test/test_x_tool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import unittest
from unittest.mock import patch

import httpx

from aden_tools.tools.x_tool.x_tool import (
_XClient,
)


class TestXClient(unittest.TestCase):
@patch("httpx.request")
def test_post(self, mock_req):
mock_req.return_value = httpx.Response(200, json={"data": {"id": "1", "text": "hi"}})

client = _XClient("fake")
res = client.request("POST", "/tweets", json={"text": "hi"})

self.assertIn("data", res)


if __name__ == "__main__":
unittest.main()
Loading
Loading