Skip to content
Draft
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
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
- "ai/slackbot-mcp-client/rich-responses/mcp-apps"
- "ai/slackbot-mcp-client/slack-identity"
- "block-kit"
- "methods"
steps:
- name: Checkout code
uses: actions/checkout@v7
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ This collections of examples highlights features of a Slack app in the language

- **[AI in Slack](./ai)**: Agent experiences and MCP features in an interactive conversation interface.
- **[Block Kit](./block-kit)**: The framework of visual components arranged to create app layouts.
- **[Methods](./methods)**: Individual Slack Web API method calls with the `slack_sdk` `WebClient`.
5 changes: 5 additions & 0 deletions methods/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__pycache__
.mypy_cache
.pytest_cache
.ruff_cache
.venv
20 changes: 20 additions & 0 deletions methods/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Methods

Individual Slack Web API method calls with the `slack_sdk` `WebClient`.

Read the [docs](https://docs.slack.dev/reference/methods) to explore every method, or explore implementations of specific families.

## What's on display

### chat

- **[chat.postMessage](https://docs.slack.dev/reference/methods/chat.postmessage)**: Sends a message to a channel. [Implementation](./src/chat/chat_post_message.py).

## Running an example

Each family ships a [`manifest.json`](./src/chat/manifest.json) requesting only the scopes it needs (`chat` → `chat:write`). Create an app from it, then set a bot token and run an example module directly:

```sh
export SLACK_TOKEN="xoxb-your-token"
python -m src.chat.chat_post_message
```
4 changes: 4 additions & 0 deletions methods/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mypy==2.3.0
pytest==9.1.1
ruff==0.15.21
slack_sdk==3.43.0
Empty file added methods/src/__init__.py
Empty file.
Empty file added methods/src/chat/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions methods/src/chat/chat_post_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import os

from slack_sdk import WebClient
from slack_sdk.web import SlackResponse


def example01(client: WebClient) -> SlackResponse:
"""
Sends a message to a channel.
https://docs.slack.dev/reference/methods/chat.postmessage
"""
# Call the chat.postMessage method using the WebClient
response = client.chat_postMessage(
channel="C123ABC456",
text="Here's a message for you",
)
return response


if __name__ == "__main__":
# Read a token from the environment variables
token = os.environ.get("SLACK_TOKEN")

# Initialize a WebClient with the given token
client = WebClient(token=token)

print(example01(client))
22 changes: 22 additions & 0 deletions methods/src/chat/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"display_information": {
"name": "Slack API Methods",
"description": "Example implementations to call \"chat\" methods"
},
"features": {
"bot_user": {
"display_name": "Slack API Methods",
"always_online": true
}
},
"oauth_config": {
"scopes": {
"bot": ["chat:write"]
}
},
"settings": {
"org_deploy_enabled": true,
"socket_mode_enabled": false,
"token_rotation_enabled": false
}
}
Empty file added methods/tests/__init__.py
Empty file.
Empty file.
43 changes: 43 additions & 0 deletions methods/tests/chat/test_chat_post_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import json
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer

from slack_sdk import WebClient

from src.chat import chat_post_message


class _CapturingHandler(BaseHTTPRequestHandler):
captured: dict = {}

def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
_CapturingHandler.captured = {
"path": self.path,
"body": self.rfile.read(length).decode(),
}
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(b'{"ok": true}')

def log_message(self, *args):
pass


def test_example01():
server = HTTPServer(("127.0.0.1", 0), _CapturingHandler)
port = server.server_address[1]
threading.Thread(target=server.handle_request, daemon=True).start()

client = WebClient(token="xoxb-test", base_url=f"http://127.0.0.1:{port}/api/")
response = chat_post_message.example01(client)

assert response["ok"] is True

captured = _CapturingHandler.captured
assert captured["path"] == "/api/chat.postMessage"
assert json.loads(captured["body"]) == {
"channel": "C123ABC456",
"text": "Here's a message for you",
}