x-mcp-server
# X MCP Server
TypeScript Model Context Protocol (MCP) server for the official X API.
This project lets MCP-compatible agents, including ChatGPT agents, safely read
from and publish to X accounts through a local server that runs on your own
computer.
The server supports:
- Reading the authenticated X account.
- Looking up X users by username.
- Reading posts by ID.
- Listing recent posts from a user.
- Searching recent posts with X search syntax.
- Creating posts and replies when write mode is explicitly enabled.
- Selecting a different X account per local computer installation.
- Running over `stdio` for local MCP hosts.
- Running over local Streamable HTTP for ChatGPT through OpenAI Secure MCP
Tunnels.
## Project Status
This is a functional MVP.
Implemented:
- MCP server over `stdio`.
- MCP server over Streamable HTTP.
- Official X API client.
- Local multi-account configuration.
- Recommended `xurl` authentication provider, using X's official CLI for OAuth
token storage, refresh and rotation.
- Safe `read-only` mode by default.
- Explicit `read-write` mode for publishing and replies.
- Legacy local OAuth 2.0 Authorization Code + PKCE helper for direct env-token
setups.
- Unit tests with Vitest.
- ChatGPT connection guide through OpenAI Secure MCP Tunnels.
- Local server lifecycle guide for manual and automatic startup on Windows.
## How It Works
For local MCP hosts:
```text
MCP host
-> stdio
-> x-mcp-server
-> official X API
```
For ChatGPT agents:
```text
ChatGPT agent
-> custom MCP app
-> OpenAI Secure MCP Tunnel
-> tunnel-client on your computer
-> http://127.0.0.1:3001/mcp
-> x-mcp-server
-> official X API
```
The X credentials stay local. ChatGPT connects to the local MCP server through
the tunnel; it does not receive your X access tokens.
## Available MCP Tools
| Tool | Type | Description |
| --- | --- | --- |
| `x_get_active_account` | Read | Returns the selected local profile, configured accounts, auth provider, mode, and authenticated X user. |
| `x_get_me` | Read | Returns the authenticated X user. |
| `x_get_user` | Read | Looks up an X user by username. |
| `x_get_post` | Read | Reads a post by ID. |
| `x_get_user_posts` | Read | Lists recent posts authored by a user ID. |
| `x_search_posts` | Read | Searches recent posts using the official X query syntax. |
| `x_create_post` | Write | Publishes a new post. Requires `X_MCP_MODE=read-write`. |
| `x_reply_post` | Write | Replies to a post. Requires `X_MCP_MODE=read-write`. |
Write tools are blocked unless `X_MCP_MODE=read-write` is set.
## Requirements
- Node.js 20 or newer.
- An X Developer account.
- An X Developer App with OAuth 2.0 enabled.
- X read scopes: `tweet.read users.read`.
- X write scope for publishing and replies: `tweet.write`.
- Recommended X token manager: X's official `xurl` CLI.
- For ChatGPT: Developer Mode enabled.
- For ChatGPT local connections: an OpenAI Secure MCP Tunnel and
`tunnel-client`.
## Step-by-Step Installation
### 1. Clone the Repository
```powershell
git clone https://github.com/lluisfont/x-mcp-server.git
cd x-mcp-server
```
If you already have the repository:
```powershell
cd C:\Repos\x-mcp-server
git pull
```
### 2. Install Dependencies
```powershell
npm install
```
### 3. Create a Local Environment File
```powershell
Copy-Item .env.example .env
```
Edit `.env` locally.
Do not commit `.env`. It may contain local app names, usernames, access tokens,
refresh tokens, client secrets, and private API keys.
### 4. Configure the Active X Account
Recommended setup: use `xurl` as the token manager.
```env
X_AUTH_PROVIDER=xurl
X_XURL_APP=fcbnews
X_XURL_USERNAME=FCBNews2026
X_MCP_ACCOUNT=fcbnews2026
X_MCP_MODE=read-only
X_API_BASE_URL=https://api.x.com
```
Configure `xurl` once outside this project:
```powershell
$secret = Read-Host "X OAuth Client Secret" -AsSecureString
$plain = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret)
)
npx -y @xdevplatform/xurl auth apps add fcbnews --client-id "<OAuth 2.0 Client ID>" --client-secret $plain --redirect-uri http://localhost:8080/callback
npx -y @xdevplatform/xurl auth oauth2 --app fcbnews FCBNews2026
```
Register this callback URI in the X Developer App:
```text
http://localhost:8080/callback
```
`xurl` stores tokens in its own local store and refreshes/persists them when
needed. The MCP server calls:
```powershell
npx -y @xdevplatform/xurl token --app fcbnews -u FCBNews2026
```
Legacy direct-token setup is still available with `X_AUTH_PROVIDER=env`:
```env
X_AUTH_PROVIDER=env
X_MCP_ACCOUNT=fcbnews2026
X_MCP_MODE=read-only
X_ACCOUNT_FCBNEWS2026_USER_ACCESS_TOKEN=
X_ACCOUNT_FCBNEWS2026_REFRESH_TOKEN=
X_ACCOUNT_LLUISFONT_USER_ACCESS_TOKEN=
X_ACCOUNT_LLUISFONT_REFRESH_TOKEN=
```
The legacy single-account env-token mode is also supported:
```env
X_AUTH_PROVIDER=env
X_MCP_ACCOUNT=default
X_USER_ACCESS_TOKEN=
```
New installations should prefer `X_AUTH_PROVIDER=xurl`.
### 5. Choose the Transport
For local MCP hosts that start the process directly:
```env
X_MCP_TRANSPORT=stdio
```
For ChatGPT through a local tunnel:
```env
X_MCP_TRANSPORT=http
X_MCP_HTTP_PORT=3001
X_MCP_HTTP_PATH=/mcp
```
### 6. Run Type Checks and Tests
```powershell
npm run typecheck
npm test
npm run build
```
### 7. Start the MCP Server
For `stdio`:
```powershell
npm run dev
```
For local HTTP:
```powershell
npm run dev:http
```
The default HTTP MCP endpoint is:
```text
http://127.0.0.1:3001/mcp
```
Health check:
```powershell
Invoke-RestMethod http://127.0.0.1:3001/healthz | ConvertTo-Json -Compress
```
Expected response:
```json
{"ok":true,"transport":"http","activeAccount":"fcbnews2026","mode":"read-only"}
```
## Local MCP Server Lifecycle
When ChatGPT uses this MCP through a tunnel, two local processes must be
running:
```text
1. The MCP HTTP server
-> npm run dev:http
-> http://127.0.0.1:3001/mcp
2. tunnel-client
-> .\.tools\tunnel-client\tunnel-client.exe run --profile <profile>
-> OpenAI Secure MCP Tunnel
```
If either process is stopped, ChatGPT cannot use the MCP tools.
### Start Manually
Terminal 1:
```powershell
cd C:\Repos\x-mcp-server
npm run dev:http
```
Terminal 2:
```powershell
cd C:\Repos\x-mcp-server
.\.tools\tunnel-client\tunnel-client.exe run --profile x-fcbnews
```
Keep both terminals open.
### Verify Local Availability
Check the MCP server:
```powershell
Invoke-RestMethod http://127.0.0.1:3001/healthz | ConvertTo-Json -Compress
```
Check the tunnel client:
```powershell
Invoke-WebRequest http://127.0.0.1:8080/readyz -UseBasicParsing
```
The tunnel readiness endpoint should return HTTP `200`.
### Stop Manually
Press `Ctrl+C` in:
- The terminal running `npm run dev:http`.
- The terminal running `tunnel-client run`.
Once both are stopped, ChatGPT no longer has access to the local MCP server.
### Change Account or Safety Mode
Edit `.env`.
Change active account:
```env
X_MCP_ACCOUNT=fcbnews2026
```
Enable write mode:
```env
X_MCP_MODE=read-write
```
Return to safe read-only mode:
```env
X_MCP_MODE=read-only
```
Restart the MCP HTTP server after changing `.env`:
```text
Ctrl+C
npm run dev:http
```
The tunnel can remain running if the local port and MCP path did not change.
### Start Automatically on Windows Login
For a computer that should regularly host this MCP, use Windows Task Scheduler.
Create a local startup script, for example:
```text
C:\Users\<user>\mcp-start\x-fcbnews-start.ps1
```
Script:
```powershell
$repo = "C:\Repos\x-mcp-server"
$profile = "x-fcbnews"
Set-Location $repo
Start-Process powershell.exe -ArgumentList @(
"-NoExit",
"-ExecutionPolicy", "Bypass",
"-Command", "cd `"$repo`"; npm run dev:http"
) -WindowStyle Minimized
Start-Sleep -Seconds 5
Start-Process powershell.exe -ArgumentList @(
"-NoExit",
"-ExecutionPolicy", "Bypass",
"-Command", "cd `"$repo`"; .\.tools\tunnel-client\tunnel-client.exe run --profile $profile"
) -WindowStyle Minimized
```
Register the scheduled task:
```powershell
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-ExecutionPolicy Bypass -File `"C:\Users\<user>\mcp-start\x-fcbnews-start.ps1`""
$trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask `
-TaskName "X MCP FCBNews2026" `
-Action $action `
-Trigger $trigger `
-Description "Starts the local X MCP server and OpenAI tunnel-client at Windows logon."
```
Disable automatic startup:
```powershell
Disable-ScheduledTask -TaskName "X MCP FCBNews2026"
```
Enable it again:
```powershell
Enable-ScheduledTask -TaskName "X MCP FCBNews2026"
```
Delete it:
```powershell
Unregister-ScheduledTask -TaskName "X MCP FCBNews2026" -Confirm:$false
```
Full lifecycle guide:
[docs/local-server-lifecycle.md](docs/local-server-lifecycle.md)
## Connect to ChatGPT
High-level flow:
```text
1. Run the MCP server over local HTTP.
2. Create a tunnel in OpenAI Platform.
3. Create a local tunnel-client profile pointing to http://127.0.0.1:3001/mcp.
4. Start tunnel-client.
5. Create a custom MCP app in the ChatGPT agent using Connection: Tunnel.
6. Test x_get_active_account or x_get_me before any write operation.
```
Recommended ChatGPT custom MCP settings:
```text
Connection: Tunnel
Tunnel: <your OpenAI tunnel>
Authentication: No authentication
```
Use `No authentication` when the MCP server manages the final service
credentials locally, for example through `.env`.
Full ChatGPT setup guide:
[docs/chatgpt-mcp-setup.md](docs/chatgpt-mcp-setup.md)
## Reauthorize an X Account
Recommended `xurl` flow:
```powershell
npx -y @xdevplatform/xurl auth oauth2 --app fcbnews FCBNews2026
```
Use the legacy helper only for `X_AUTH_PROVIDER=env`:
```powershell
$env:X_OAUTH_CLIENT_ID = "<OAuth 2.0 Client ID>"
$env:X_MCP_ACCOUNT = "fcbnews2026"
npm run x:oauth
```
Restart the MCP server after reauthorization:
```powershell
npm run dev:http
```
Then verify with:
```text
x_get_active_account
```
Detailed OAuth guide:
[docs/x-oauth.md](docs/x-oauth.md)
## Safety Model
The server starts in read-only mode by default:
```env
X_MCP_MODE=read-only
```
Write tools require:
```env
X_MCP_MODE=read-write
```
Before publishing:
- Verify the active account with `x_get_active_account`.
- Confirm the exact text to publish.
- Ensure the X token has `tweet.write`.
- Prefer `X_AUTH_PROVIDER=xurl` so X token refresh and rotation are handled by
X's official CLI.
- Ask the agent to return the generated `post_id`.
- Do not treat a post as published until X returns an ID.
## Scripts
| Script | Purpose |
| --- | --- |
| `npm run dev` | Starts the MCP server over `stdio`. |
| `npm run dev:http` | Starts the MCP server over local HTTP. |
| `npm run x:oauth` | Runs the local X OAuth authorization helper. |
| `npm run build` | Compiles TypeScript to `dist`. |
| `npm run start` | Starts the compiled server over `stdio`. |
| `npm run start:http` | Starts the compiled server over HTTP. |
| `npm run typecheck` | Runs TypeScript without emitting files. |
| `npm test` | Runs the Vitest test suite. |
## Documentation
- [docs/project-architecture.md](docs/project-architecture.md): project architecture.
- [docs/configuration.md](docs/configuration.md): environment variables and multi-account setup.
- [docs/local-server-lifecycle.md](docs/local-server-lifecycle.md): start, stop, and automate the local MCP server.
- [docs/tools.md](docs/tools.md): MCP tools and usage contracts.
- [docs/x-oauth.md](docs/x-oauth.md): X OAuth reauthorization.
- [docs/development.md](docs/development.md): development, testing, and change guidelines.
- [docs/chatgpt-mcp-setup.md](docs/chatgpt-mcp-setup.md): step-by-step ChatGPT MCP setup.
## Operational Security
- Keep credentials outside Git.
- Keep `read-only` as the default mode.
- Enable `read-write` only for controlled workflows.
- Verify the active account before publishing.
- Do not log access tokens or refresh tokens.
- Do not paste tokens into chats, issues, docs, or pull requests.
- Do not run automatic startup in `read-write` mode on shared computers.
## License
No open-source license has been selected yet.
TDQS
Scored across 8 tools
Tools have largely distinct purposes: get_active_account (local config) vs get_me (authenticated API user) vs get_user (by username) are differentiated by descriptions, and get_post vs get_user_posts vs search_posts are clearly separated. Minor potential confusion among the three user-retrieval tools, but descriptions resolve it adequately.
All tools follow a consistent snake_case pattern with an x_ prefix and verb_noun structure (e.g., x_get_user, x_create_post, x_reply_post). No deviations in style or convention.
Eight tools is well-scoped for a focused X API server covering basic read and write operations. Each tool earns its place, with no redundant or excessive entries.
The surface covers reading posts/users and creating posts/replies, but notable gaps exist: no delete or edit post, no like/retweet, and no follow/unfollow. These missing operations limit common agent workflows.