Slackbot
A Slackbot to execute Carrier Risk Assessments directly in your Public or Private channels via MyCarrierPortal API
Ask AI about Slackbot
Powered by Claude Β· Grounded in docs
I know everything about Slackbot. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
MCP Slackbot
A Slack bot for executing Carrier Risk Assessments using the MyCarrierPortal API within your Slack environment.
Brought to you by Anthony Fecarotta of linehaul.ai & linehaul.ai

Prerequisites
- Docker and Docker Compose (Recommended)
- A Slack workspace with permissions to add apps
- MyCarrierPortal API access (including Bearer Token, Refresh Token, and Token Endpoint URL)
- Bun >= 1.0.0 (if not using Docker)
Architecture
This application uses a dual-container architecture with Docker Compose and connects to Slack via Bolt Socket Mode:
- mcpslackbot: Bun application running the Slack Bolt Socket Mode client and MyCarrierPortal API integration
- libsql: Database server (Turso libSQL) for persistent token storage
Token persistence ensures OAuth refresh tokens survive container restarts and enables automatic token rotation without manual intervention.
Quick Start with Docker Compose
1. Clone the repository
git clone https://github.com/linehaul.ai/mcp-slackbot.git
cd mcp-slackbot
2. Configure environment variables
Copy the example file:
cp .env.example .env
Edit .env and fill in your credentials:
# MyCarrierPortal API Configuration
BEARER_TOKEN=your_bearer_token_here
REFRESH_TOKEN=your_refresh_token_here
TOKEN_ENDPOINT_URL=https://api.mycarrierpackets.com/token
CLIENT_ID=your_mcp_username
CLIENT_SECRET=your_mcp_password
# Slack Configuration
SLACK_BOT_TOKEN=xoxb-your-slack-bot-token
SLACK_SIGNING_SECRET=your_slack_signing_secret
SLACK_APP_TOKEN=xapp-your-slack-app-token
# Application Configuration
NODE_ENV=production
# Database Configuration (optional - defaults shown)
LIBSQL_URL=http://libsql:8081
Important Notes:
CLIENT_IDandCLIENT_SECRETare your MyCarrierPortal username and password (used for initial token generation only)- These credentials are NOT sent with refresh token requests
- Initial
BEARER_TOKENandREFRESH_TOKENvalues are only used on first startup to seed the database
3. Start the application
Production mode:
docker compose up -d
This command will:
- Pull the libSQL server image
- Build the Bun application image
- Create a persistent volume for token storage
- Start both containers in the background
Development mode (with logs visible):
docker compose up
4. Verify deployment
Check that both containers are running:
docker compose ps
Expected output:
NAME IMAGE STATUS
libsql ghcr.io/tursodatabase/libsql-server:latest Up
mcpslackbot mcpslackbot Up
View application logs:
# All logs
docker compose logs -f
# Just the app
docker compose logs -f mcpslackbot
# Just the database
docker compose logs -f libsql
Look for these startup messages:
Database initializedLoaded tokens from databaseORNo tokens in database, saving from environmentSlack Bolt app is running in Socket Mode
5. Test token refresh functionality
docker compose exec mcpslackbot node tests/test_refresh.js
Expected output:
Starting token refresh test...
Loaded tokens from database
Current Bearer Token (first 20 chars): 2_HG7Zvg3wqYkqtXxKge...
Current Refresh Token: a2afa1653b4b4b048398...
Attempting to refresh access token...
Response received: { ... }
Access token refreshed successfully.
New refresh token received.
Tokens saved to database
Test successful!
Token Persistence & Rotation
How It Works
- First Startup: Tokens from environment variables are saved to the libSQL database
- Subsequent Startups: Tokens are loaded from the database (not environment variables)
- Token Refresh: When access token expires (14 days), the app automatically:
- Detects 401 error from MyCarrierPortal API
- Calls refresh endpoint with current refresh token
- Receives new access token and refresh token
- Saves both to database
- Retries the failed API call
- Container Restart: Tokens persist in the libSQL volume and are automatically loaded
Database Management
View current tokens:
docker compose exec mcpslackbot node -e "
const { createClient } = require('@libsql/client');
const db = createClient({ url: 'http://libsql:8081' });
db.execute('SELECT bearer_token, refresh_token, updated_at FROM tokens').then(r => console.log(r.rows));
"
Manually update tokens in database:
docker compose exec mcpslackbot node -e "
const { saveTokens } = require('./db');
saveTokens('new_bearer_token', 'new_refresh_token').then(() => console.log('Done'));
"
Backup database:
# Stop containers first
docker compose down
# Copy the volume data
docker run --rm -v mcp-slackbot_libsql-data:/data -v $(pwd):/backup alpine \
tar czf /backup/libsql-backup-$(date +%Y%m%d).tar.gz -C /data .
# Restart containers
docker compose up -d
Restore database:
docker compose down
docker run --rm -v mcp-slackbot_libsql-data:/data -v $(pwd):/backup alpine \
tar xzf /backup/libsql-backup-YYYYMMDD.tar.gz -C /data
docker compose up -d
Deployment with GitHub Actions
This repository includes a self-hosted GitHub Actions workflow for automatic deployment.
Setup Self-Hosted Runner
- Install GitHub Actions runner on your server (Proxmox VM, etc.)
- Configure the runner for your repository
- Add required secrets to your GitHub repository
Required GitHub Secrets
Navigate to Settings > Secrets and variables > Actions and add:
| Secret Name | Description | Example |
|---|---|---|
BEARER_TOKEN | Initial MyCarrierPortal access token | VyTeZfFdtMagZ03J... |
REFRESH_TOKEN | Initial MyCarrierPortal refresh token | a2afa1653b4b4b04... |
TOKEN_ENDPOINT_URL | MyCarrierPortal token endpoint | https://api.mycarrierpackets.com/token |
CLIENT_ID | MyCarrierPortal username | your_username |
CLIENT_SECRET | MyCarrierPortal password | your_password |
SLACK_SIGNING_SECRET | Slack app signing secret | 1234567890abcdef... |
SLACK_BOT_TOKEN | Slack bot token | xoxb-... |
SLACK_APP_TOKEN | Slack app-level token (Socket Mode) | xapp-... |
Note: After the first deployment, tokens will be managed automatically via the database. GitHub Secrets only provide initial values.
Deployment Workflow
The workflow triggers on:
- Push to
socket-modebranch - Manual trigger via GitHub Actions UI
The deploy job only runs when all of the following are true:
- The ref is
refs/heads/socket-mode - The repository is
freightCognition/mcp-slackbot - The event is not from a fork
- Any required
productionenvironment approvals have been granted
Deployment steps:
- Checkout the repository
- Create
.envfile from GitHub Secrets - Build and start containers with
docker compose -f docker-compose.yml -f docker-compose.runner.yml up -d --build - Remove
.envfrom the workspace
View deployment logs:
- Go to Actions tab in GitHub
- Click on the latest workflow run
- Expand each step to see detailed logs
Manual deployment:
- Go to Actions tab
- Select Deploy (self-hosted) workflow
- Click Run workflow
- Select the
socket-modebranch in the branch dropdown - Approve the
productionenvironment deployment if prompted
Updating Tokens
Scenario 1: First-Time Setup
If you're starting fresh or need to reset tokens:
-
Obtain fresh tokens from MyCarrierPortal using password grant:
curl -X POST https://api.mycarrierpackets.com/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password&username=YOUR_USERNAME&password=YOUR_PASSWORD" -
Update
.envfile with the response tokens:BEARER_TOKEN=<access_token from response> REFRESH_TOKEN=<refresh_token from response> -
Restart containers:
docker compose down docker compose up -d
Scenario 2: Rotating Tokens in Production
Tokens are automatically rotated! You don't need to manually update them.
If you ever need to force a refresh:
docker compose exec mcpslackbot node tests/test_refresh.js
Scenario 3: Token Corruption or Loss
If the database becomes corrupted:
- Get fresh tokens (see Scenario 1)
- Stop containers:
docker compose down - Remove the volume:
docker volume rm mcp-slackbot_libsql-data - Update
.envwith fresh tokens - Start containers:
docker compose up -d
The database will be recreated and seeded with the new tokens.
Alternative Deployment Methods (Without Docker)
If you prefer not to use Docker, you can run the application directly with Bun. Note: You'll need to run your own libSQL server or modify the code to use a different database.
Prerequisites for Direct Deployment
- Bun >= 1.0.0
- libSQL server running (or modify code for different database)
Setup and Running
-
Install dependencies:
bun install -
Configure environment variables: Create a
.envfile with all required variables (see section 2 above) -
Run libSQL server separately:
# Download and run sqld # See: https://github.com/tursodatabase/libsql -
Run the application:
# Development mode bun run dev # Production mode bun start # Or with PM2 bun run pm2:start bun run pm2:logs bun run pm2:stop
Slack App Configuration
To use this bot, you need to create a Slack App:
- Go to https://api.slack.com/apps and click "Create New App"
- Choose "From scratch"
- Name your app (e.g., "MCP Bot") and select your workspace
Slash Commands
- Navigate to Features > Slash Commands
- Click Create New Command
- Configure:
- Command:
/risk - Request URL: Use a placeholder URL (Socket Mode does not require a public endpoint)
- Short Description: "Fetch MCP Carrier Risk Assessment"
- Usage Hint:
[MC number]
- Command:
- Save
Socket Mode eliminates the need for a public HTTP endpoint or ngrok.
Socket Mode
- Navigate to Settings > Socket Mode
- Enable Socket Mode
- Generate an App-Level Token with the
connections:writescope - Copy the token to use as
SLACK_APP_TOKEN
Permissions (OAuth & Permissions)
- Navigate to Features > OAuth & Permissions
- Add Bot Token Scopes:
commands- Required for slash commandschat:write- Required to send messages
- Click Install to Workspace
- Copy the Bot User OAuth Token (starts with
xoxb-) to use asSLACK_BOT_TOKEN
App Credentials
- Navigate to Settings > Basic Information
- Find Signing Secret under "App Credentials"
- Copy to use as
SLACK_SIGNING_SECRET
Environment Variables Reference
| Variable | Required | Description | Example |
|---|---|---|---|
BEARER_TOKEN | Yes | MyCarrierPortal access token | VyTeZfFdtMagZ03J... |
REFRESH_TOKEN | Yes | MyCarrierPortal refresh token | a2afa1653b4b4b04... |
TOKEN_ENDPOINT_URL | Yes | Token refresh endpoint | https://api.mycarrierpackets.com/token |
CLIENT_ID | Yes | MyCarrierPortal username | your_username |
CLIENT_SECRET | Yes | MyCarrierPortal password | your_password |
SLACK_SIGNING_SECRET | Yes | Slack app signing secret | 1234567890abcdef... |
SLACK_BOT_TOKEN | Yes | Slack bot token | xoxb-... |
SLACK_APP_TOKEN | Yes | Slack app-level token (Socket Mode) | xapp-... |
NODE_ENV | No | Environment mode | production or development |
LIBSQL_URL | No | Database connection URL | http://libsql:8081 (default) |
Testing
The project includes comprehensive test scripts for verifying functionality.
Available Test Scripts
# Run all tests
bun test
# Test bearer token against API
bun run test:token
# Test refresh token functionality
bun run test:refresh
Testing Refresh Token with Docker Compose
Quick test:
docker compose exec mcpslackbot node tests/test_refresh.js
Expected success output:
Starting token refresh test...
Loaded tokens from database
Current Bearer Token (first 20 chars): 2_HG7Zvg3wqYkqtXxKge...
Current Refresh Token: a2afa1653b4b4b048398...
Attempting to refresh access token...
Response received: {
"access_token": "tTG1sIov5mITHION...",
"token_type": "bearer",
"expires_in": 1209599,
"refresh_token": "bc306b1405554e03...",
"userName": "...",
".issued": "Wed, 31 Dec 2025 04:32:53 GMT",
".expires": "Wed, 14 Jan 2026 04:32:53 GMT"
}
Access token refreshed successfully.
New refresh token received.
Tokens saved to database
Test successful!
New Bearer Token (first 20 chars): tTG1sIov5mITHIONeI1_...
New Refresh Token: bc306b1405554e038b82...
Testing After Container Restart
Verify tokens persist across restarts:
# Restart the app container (database stays running)
docker compose restart mcpslackbot
# Wait for startup
sleep 5
# Check logs - should show "Loaded tokens from database"
docker compose logs mcpslackbot | grep -i token
# Verify tokens still work
docker compose exec mcpslackbot node tests/test_refresh.js
Real-World Scenario Testing
Test automatic token refresh when access token expires:
- Use an old/expired
BEARER_TOKEN - Trigger a Slack command:
/risk MC123456 - Watch logs for automatic refresh:
docker compose logs -f mcpslackbot
Expected log sequence:
Fetching data for MC number: mc123456, attempt 1
Access token expired or invalid. Attempting refresh...
Attempting to refresh access token...
Access token refreshed successfully.
New refresh token received.
Tokens saved to database
Token refreshed. Retrying API call...
Fetching data for MC number: mc123456, attempt 2
Data received for MC number: mc123456
Sending Slack response for MC number: mc123456
Monitoring Token Activity
# Watch for refresh activity
docker compose logs -f mcpslackbot | grep -i -E "(refresh|token|401)"
# Check database last update time
docker compose exec mcpslackbot node -e "
const { createClient } = require('@libsql/client');
const db = createClient({ url: 'http://libsql:8081' });
db.execute('SELECT updated_at FROM tokens WHERE id = 1').then(r => console.log('Last updated:', r.rows[0]?.updated_at));
"
Success Indicators
β Everything working correctly:
- Database initializes on startup
- Tokens loaded from database (not environment)
- Refresh test passes
- Slack commands work
- 401 errors trigger automatic refresh
- New tokens saved to database
- Container restarts preserve tokens
β Potential issues:
REFRESH_TOKEN not found in database or environment- Need to seed databaseError refreshing access token: {"error": "invalid_grant"}- Refresh token expired/invalidError loading tokens from database- Database connection issue- Tokens revert after restart - Volume not persisting correctly
address already in use- Port 8081 is in use, checkdocker psand stop conflicting container
Troubleshooting
Containers won't start
Check logs:
docker compose logs
Common issues:
- Port 8081 already in use - change port mapping in
docker-compose.ymlfor libsql service - Missing environment variables - verify
.envfile exists and is complete - Permission issues - ensure user can access Docker socket
Database connection errors
Verify libSQL is running:
docker compose ps libsql
curl http://localhost:8081/health
Check network:
docker compose exec mcpslackbot curl -f http://libsql:8081/health
Reset database:
docker compose down
docker volume rm mcp-slackbot_libsql-data
docker compose up -d
Tokens not persisting
Check volume exists:
docker volume ls | grep libsql
Inspect volume:
docker volume inspect mcp-slackbot_libsql-data
Verify database has data:
docker compose exec mcpslackbot node -e "
const { createClient } = require('@libsql/client');
const db = createClient({ url: 'http://libsql:8081' });
db.execute('SELECT COUNT(*) as count FROM tokens').then(r => console.log('Token count:', r.rows[0]?.count));
"
Refresh token fails
Get detailed error:
docker compose exec mcpslackbot node tests/test_refresh.js
Check token endpoint URL:
docker compose exec mcpslackbot printenv TOKEN_ENDPOINT_URL
# Should be: https://api.mycarrierpackets.com/token
Check libSQL port:
docker compose exec mcpslackbot printenv LIBSQL_URL
# Should be: http://libsql:8081
Obtain fresh tokens:
curl -X POST https://api.mycarrierpackets.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password&username=YOUR_USERNAME&password=YOUR_PASSWORD"
Then update tokens in database (see "Updating Tokens" section).
Slack commands not working
Verify Slack configuration:
- Socket Mode is enabled for the app
SLACK_APP_TOKENuses an app-level token withconnections:write- Signing secret matches
- Bot token has required scopes (
commands,chat:write)
Security Best Practices
- β
Never commit
.envfiles - Already in.gitignore - β
Use Docker secrets in production - Configured in
docker compose.yml - β Rotate credentials regularly - Automatic for access/refresh tokens
- β Backup database regularly - Contains sensitive tokens
- β
Use
.env.example- Never contains real credentials - β Implement volume encryption - Consider for libsql-data volume
- β Monitor access logs - Track unusual activity
Maintenance
Updating the Application
# Pull latest code
git pull origin main
# Rebuild and restart
docker compose down
docker compose up -d --build
# Verify
docker compose logs -f
Database Maintenance
View database statistics:
docker compose exec mcpslackbot node -e "
const { createClient } = require('@libsql/client');
const db = createClient({ url: 'http://libsql:8081' });
db.execute('SELECT * FROM tokens').then(r => console.log(JSON.stringify(r.rows, null, 2)));
"
Scheduled backups:
Create a cron job:
# Edit crontab
crontab -e
# Add daily backup at 2 AM
0 2 * * * cd /path/to/mcp-slackbot && docker compose down && docker run --rm -v mcp-slackbot_libsql-data:/data -v $(pwd)/backups:/backup alpine tar czf /backup/libsql-$(date +\%Y\%m\%d).tar.gz -C /data . && docker compose up -d
License
This project is licensed under version 3 of the GNU Affero General Public License (AGPL-3.0). See the LICENSE.TXT file for details.
Support
For issues or questions:
- GitHub Issues: https://github.com/linehaul.ai/mcp-slackbot/issues
- Contact: Anthony Fecarotta (linehaul.ai / linehaul.ai)
