Skip to content
Merged
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
141 changes: 137 additions & 4 deletions examples/usecases/mcp_github_to_slack_agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This application creates an MCP Agent that monitors GitHub pull requests and sub
## How It Works

1. The application connects to both GitHub and Slack via their respective MCP servers
2. The agent retrieves the latest pull requests from a specified GitHub repository
2. The agent retrieves the last 10 pull requests from a specified GitHub repository
3. It analyzes each PR and prioritizes them based on importance factors:
- PRs marked as high priority or urgent
- PRs addressing security vulnerabilities
Expand All @@ -21,10 +21,9 @@ This application creates an MCP Agent that monitors GitHub pull requests and sub

- Python 3.10 or higher
- MCP Agent framework
- [GitHub MCP Server](https://github.com/github/github-mcp-server))
- GitHub Copilot access (for cloud-based GitHub MCP server)
- [Slack MCP Server](https://github.com/korotovsky/slack-mcp-server/tree/master)
- Node.js and npm (this is for the Slack server)
- [Docker](https://www.docker.com/)
- Node.js and npm (for the Slack server)
- Access to a GitHub repository
- Access to a Slack workspace

Expand Down Expand Up @@ -67,3 +66,137 @@ Run the application with:
```
uv run main.py --owner <github-owner> --repo <repository-name> --channel <slack-channel>
```

### [Beta] Deploy to the cloud

#### `a.` Log in to [MCP Agent Cloud](https://docs.mcp-agent.com/cloud/overview)

```bash
uv run mcp-agent login
```

#### `b.` Update your `mcp_agent.secrets.yaml` to mark your developer secrets (keys)

```yaml
$schema: ../../../schema/mcp-agent.config.schema.json

mcp:
servers:
slack:
env:
SLACK_MCP_XOXP_TOKEN: !developer_secret SLACK_MCP_XOXP_TOKEN

github:
headers:
Authorization: !developer_secret GITHUB_PERSONAL_ACCESS_TOKEN_WITH_BEARER_PREFIX

anthropic:
api_key: !developer_secret ANTHROPIC_API_KEY
```

#### `c.` Deploy your agent with a single command

```bash
uv run mcp-agent deploy my-first-agent
```

#### `d.` Connect to your deployed agent as an MCP server through any MCP client

##### Claude Desktop Integration

Configure Claude Desktop to access your agent servers by updating your `~/.claude-desktop/config.json`:

```json
"my-agent-server": {
"command": "/path/to/npx",
"args": [
"mcp-remote",
"https://[your-agent-server-id].deployments.mcp-agent-cloud.lastmileai.dev/sse",
"--header",
"Authorization: Bearer ${BEARER_TOKEN}"
],
"env": {
"BEARER_TOKEN": "your-mcp-agent-cloud-api-token"
}
}
```

##### MCP Inspector

Use MCP Inspector to explore and test your agent servers:

```bash
npx @modelcontextprotocol/inspector
```

Make sure to fill out the following settings:

| Setting | Value |
|---|---|
| *Transport Type* | *SSE* |
| *SSE* | *https://[your-agent-server-id].deployments.mcp-agent-cloud.lastmileai.dev/sse* |
| *Header Name* | *Authorization* |
| *Bearer Token* | *your-mcp-agent-cloud-api-token* |

> [!TIP]
> In the Configuration, change the request timeout to a longer time period. Since your agents are making LLM calls, it is expected that it should take longer than simple API calls.


##### Trigger Agent Run on Cloud

Once you are connected to the MCP Agent on cloud, you will get a list of tools as follow:
- MCP Agent Cloud Default Tools:
- workflow-list: list the workflow (you don't need this)
- workflow-run-list: list the execution runs of your agent
- workflow-run: create workflow run (you don't need this)
- workflows-get_status: get your agent run's status
- workflows-resume: signal workflow to pause run
- workflows-cancel: signal workflow to cancel run
- Tool's that your agent expose:
- github_to_slack: default of your tool name, input the parameters to trigger a workflow run


Once you run the agent, successful trigger will return a workflow_run metadata object, where you can find your run id to query status:
```json
{
"workflow_id": "github_to_slack-uuid",
"run_id": "uuid",
"execution_id": "uuid"
}
```

If this command returns error, you can tail the agent logs to investigate:

```shell
uv run mcp-agent cloud logger tail "app_id" -f
```

When you agent run successfully finishes, you will see Slack message is posted by your agent and you will also be able to see the agent's text response by using `workflows-get_status`, which will return result like:

```json
{
"result": {
"id": "run-uuid",
"name": "github_to_slack",
"status": "completed",
"running": false,
"state": {
"status": "completed",
"metadata": {},
"updated_at": 1757705891.842188,
"error": null
},
"result": "{'kind': 'workflow_result', 'value': \"I'll help you complete this workflow. Let me start by retrieving the last 10 pull requests from the GitHub repository lastmile-.......",
"completed": true,
"error": null,
"temporal": {
"id": "github_to_slack-uuid",
"workflow_id": "github_to_slack-uuid",
"run_id": "uuid",
"status": "xxxxx",
"error": "xxxxx"
}
}
}
```

14 changes: 9 additions & 5 deletions examples/usecases/mcp_github_to_slack_agent/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

app = MCPApp(name="github_to_slack")


@app.async_tool(name="github_to_slack", description="Tool to list GitHub pull requests and provides summaries to Slack")
async def github_to_slack(github_owner: str, github_repo: str, slack_channel: str):
async with app.run() as agent_app:
context = agent_app.context
Expand All @@ -19,7 +19,7 @@ async def github_to_slack(github_owner: str, github_repo: str, slack_channel: st
name="github_to_slack_agent",
instruction=f"""You are an agent that monitors GitHub pull requests and provides summaries to Slack.
Your tasks are:
1. Use the GitHub server to retrieve information about the latest pull requests for the repository {github_owner}/{github_repo}
1. Use the GitHub server to retrieve information about the last 10 pull requests for the repository {github_owner}/{github_repo}
2. Analyze and prioritize the pull requests based on their importance, urgency, and impact
3. Format a concise summary of high-priority items
4. Submit this summary to the Slack server in the channel {slack_channel}
Expand All @@ -40,7 +40,7 @@ async def github_to_slack(github_owner: str, github_repo: str, slack_channel: st

prompt = f"""Complete the following workflow:

1. Retrieve the latest pull requests from the GitHub repository {github_owner}/{github_repo}.
1. Retrieve the last 10 pull requests from the GitHub repository {github_owner}/{github_repo}.
Use the GitHub server to get this information.
Gather details such as PR title, author, creation date, status, and description.

Expand All @@ -60,14 +60,18 @@ async def github_to_slack(github_owner: str, github_repo: str, slack_channel: st
- Include links to the PRs
- End with any relevant action items or recommendations

4. Use the Slack server to post this summary to the channel {slack_channel}.
4. Use the Slack server to post this summary to the channel {slack_channel}. If you do not have Slack
tool access, just return the final summary.
"""

# Execute the workflow
print("Executing GitHub to Slack workflow...")
await llm.generate_str(prompt)
result = await llm.generate_str(prompt)

print("Workflow completed successfully!")
print(result)

return result

finally:
# Clean up the agent
Expand Down
24 changes: 13 additions & 11 deletions examples/usecases/mcp_github_to_slack_agent/mcp_agent.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,25 @@ logger:
mcp:
servers:
github:
command: "docker"
args: [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
]
transport: "streamable_http"
url: "https://api.githubcopilot.com/mcp/x/pull_requests/readonly"
headers:
Content-Type: "application/json"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do you specify the secrets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's populated in secret.yaml. see

http_timeout_seconds: 30
read_timeout_seconds: 60
description: "Access GitHub API operations"
allowed_tools:
- "list_pull_requests"
- "get_pull_request"
slack:
command: "npx"
args: ["-y",
"slack-mcp-server@latest",
"--transport",
"stdio"]
env:
SLACK_MCP_XOXP_TOKEN: "ADD_YOUR_TOKEN_HERE"
SLACK_TEAM_ID: "T0123213213"
SLACK_MCP_ADD_MESSAGE_TOOL: "true"
description: "Access Slack API operations"]
description: "Access Slack API operations"
allowed_tools:
- "conversations_add_message"
Comment on lines +34 to +36
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Slack tool naming/permissions and channel identifier; also fix EOF newline.

  • Confirm the tool name conversations_add_message matches the Slack MCP server’s schema and that your token has scopes (e.g., chat:write, channels:read or groups:read depending on channel type).
  • Ensure the CLI expects a channel ID (C…/G…) vs. a name to avoid posting failures.
  • Add missing newline at EOF to satisfy YAML linters.

Minimal EOF fix:

-        - "conversations_add_message"
+        - "conversations_add_message"
+

🌐 Web query:

What tool names and argument shapes does the official slack-mcp-server expose for posting messages, and which Slack OAuth scopes are required?

💡 Result:

Short answer — from the official slack-mcp-server package the message-posting tool is:

  • slack_post_message
    • Inputs (argument shape):
      • channel_id (string) — ID of the channel to post to (required)
      • text (string) — message text (required)
    • (There is also slack_reply_to_thread for thread replies: channel_id (string), thread_ts (string), text (string).) (npmjs.com)

Required Slack OAuth scopes (common/official bot-token scopes used by the server for full functionality — include at least chat:write plus channel/group/IM read/write and others listed below): channels:read, channels:manage (or channels:write in some forks), groups:read, groups:write, chat:write, files:write, im:read, mpim:read, reactions:read, reactions:write, team:read, users:read. (Some forks/variants may request additional/history scopes like channels:history, groups:history, im:history, or use user tokens with user scopes instead.) (github.com)

If you want, I can fetch the exact JSON tool schema (full parameter names/types) from the package manifest or repository you plan to use.

Citations:


Replace allowed_tools with slack_post_message, require channel_id & chat scopes, and add EOF newline.

  • File: examples/usecases/mcp_github_to_slack_agent/mcp_agent.config.yaml (lines 34–36)
  • Change allowed_tools entry from the non-existent conversations_add_message to slack_post_message — the slack-mcp-server tool expects: channel_id (string) and text (string). slack_reply_to_thread exists for thread replies.
  • Ensure the bot token includes at minimum chat:write and the appropriate channel read scope (channels:read for public channels or groups:read for private channels); additional common scopes: channels:manage/groups:write, im:read, mpim:read, files:write, reactions:read/write, users:read as needed.
  • Pass a channel ID (C.../G...), not a human-readable name.
  • Add missing newline at EOF.

Minimal EOF fix (unchanged):

-        - "conversations_add_message"
+        - "conversations_add_message"
+
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
description: "Access Slack API operations"
allowed_tools:
- "conversations_add_message"
description: "Access Slack API operations"
allowed_tools:
- "conversations_add_message"
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 36-36: no new line character at the end of file

(new-line-at-end-of-file)

🤖 Prompt for AI Agents
In examples/usecases/mcp_github_to_slack_agent/mcp_agent.config.yaml around
lines 34 to 36, replace the allowed_tools entry "conversations_add_message" with
"slack_post_message", ensure the tool usage includes required parameters
channel_id (must be a channel ID like C... or G..., not a human-readable name)
and text, verify the bot token configuration lists at minimum chat:write plus
the appropriate channel read scope (channels:read for public or groups:read for
private) and any additional needed scopes, and add a missing newline at EOF.

Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ $schema: ../../../schema/mcp-agent.config.schema.json
mcp:
servers:
# Slack configuration
# Create a Slack Bot Token and get your Team ID
# Create a Slack App Oauth Token and get your Team ID
# https://api.slack.com/apps
slack:
env:
SLACK_BOT_TOKEN: "xoxb-your-bot-token"
SLACK_TEAM_ID: "T01234567"
SLACK_MCP_XOXP_TOKEN: "xoxp-oauth-token"
Comment on lines +6 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There appears to be a terminology mismatch in the configuration comments. The comment refers to "Slack App Oauth Token" but the environment variable SLACK_MCP_XOXP_TOKEN specifically indicates a user token (xoxp prefix), not an app/bot token.

For clarity, either:

  1. Update the comment to specify this is a user-level OAuth token (xoxp), or
  2. If a bot token is actually intended, update the variable name to reflect the correct token type

This distinction is important as user tokens and bot tokens have different permission scopes and security implications.

Suggested change
# Create a Slack App Oauth Token and get your Team ID
# https://api.slack.com/apps
slack:
env:
SLACK_BOT_TOKEN: "xoxb-your-bot-token"
SLACK_TEAM_ID: "T01234567"
SLACK_MCP_XOXP_TOKEN: "xoxp-oauth-token"
# Create a Slack User OAuth Token (xoxp token) and get your Team ID
# https://api.slack.com/apps
slack:
env:
SLACK_MCP_XOXP_TOKEN: "xoxp-oauth-token"

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

# SLACK_MCP_XOXP_TOKEN: !developer_secret SLACK_MCP_XOXP_TOKEN
Comment on lines +6 to +11
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Slack token var/type mismatch; add Team ID and align with server expectations.

The example switches to a user token (xoxp) and variable SLACK_MCP_XOXP_TOKEN, while the Slack MCP server commonly expects a bot token (xoxb) and a well-known var (e.g., SLACK_BOT_TOKEN). Also, SLACK_TEAM_ID is required by your config but missing here. This will lead to 401s or tool init failures.

Apply one of the following (Option A recommended):

Option A — use bot token:

-    # Create a Slack App Oauth Token and get your Team ID
+    # Create a Slack Bot User OAuth Token (xoxb) and get your Team ID
       # https://api.slack.com/apps
       slack:
         env:
-        SLACK_MCP_XOXP_TOKEN: "xoxp-oauth-token"
-#        SLACK_MCP_XOXP_TOKEN: !developer_secret SLACK_MCP_XOXP_TOKEN
+        SLACK_BOT_TOKEN: "xoxb-your-bot-token"
+#        SLACK_BOT_TOKEN: !developer_secret SLACK_BOT_TOKEN
+        SLACK_TEAM_ID: "T0123456789"
+#        SLACK_TEAM_ID: !developer_secret SLACK_TEAM_ID

Option B — if your server truly requires a user token, also pass the same var in config’s Slack env and document required user scopes.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Create a Slack App Oauth Token and get your Team ID
# https://api.slack.com/apps
slack:
env:
SLACK_BOT_TOKEN: "xoxb-your-bot-token"
SLACK_TEAM_ID: "T01234567"
SLACK_MCP_XOXP_TOKEN: "xoxp-oauth-token"
# SLACK_MCP_XOXP_TOKEN: !developer_secret SLACK_MCP_XOXP_TOKEN
# Create a Slack Bot User OAuth Token (xoxb) and get your Team ID
# https://api.slack.com/apps
slack:
env:
SLACK_BOT_TOKEN: "xoxb-your-bot-token"
# SLACK_BOT_TOKEN: !developer_secret SLACK_BOT_TOKEN
SLACK_TEAM_ID: "T0123456789"
# SLACK_TEAM_ID: !developer_secret SLACK_TEAM_ID


# GitHub configuration
# Create a GitHub Personal Access Token with repo scope
# https://github.com/settings/tokens
github:
env:
GITHUB_PERSONAL_ACCESS_TOKEN: "github_pat_your-access-token"
headers:
Authorization: "Bearer ghp_xxxxxxxxxxx"
# Authorization: !developer_secret GITHUB_PERSONAL_ACCESS_TOKEN_WITH_BEARER_PREFIX
Comment on lines +17 to +19
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid inlining GitHub tokens; use developer_secret injection.

Even in an example, showing an inline Bearer token encourages unsafe patterns. Prefer secret injection.

-      headers:
-        Authorization: "Bearer ghp_xxxxxxxxxxx"
-#        Authorization: !developer_secret GITHUB_PERSONAL_ACCESS_TOKEN_WITH_BEARER_PREFIX
+      headers:
+#        Authorization: !developer_secret GITHUB_PERSONAL_ACCESS_TOKEN_WITH_BEARER_PREFIX
+        Authorization: "Bearer YOUR_TOKEN_HERE"  # example value; do not commit real tokens

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In examples/usecases/mcp_github_to_slack_agent/mcp_agent.secrets.yaml.example
around lines 17 to 19, the example inlines a GitHub PAT with a "Bearer
ghp_xxxxx" which encourages unsafe practices; replace the inline token with the
developer_secret placeholder (or remove the Bearer prefix and use the secret
injection syntax) so consumers are shown how to inject secrets at runtime (e.g.,
restore the commented developer_secret line or reference a properly named secret
variable) and update any accompanying README note to tell users to set the
secret in their environment rather than paste tokens into the example file.

Comment on lines +18 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There appears to be an inconsistency in the GitHub token format instructions:

Authorization: "Bearer ghp_xxxxxxxxxxx"
#Authorization: !developer_secret GITHUB_PERSONAL_ACCESS_TOKEN_WITH_BEARER_PREFIX

The first line shows an explicit Bearer prefix with the token, while the commented line suggests using a developer secret that already includes this prefix (as indicated by WITH_BEARER_PREFIX).

This could lead to authentication errors if users follow both patterns. Consider standardizing the approach by either:

  1. Removing the Bearer prefix from line 18 and updating the developer secret name to indicate the token should be provided without the prefix, or
  2. Clarifying in a comment that the developer secret should include the Bearer prefix exactly as shown in line 18

Consistent instructions will help prevent authentication failures during setup.

Suggested change
Authorization: "Bearer ghp_xxxxxxxxxxx"
# Authorization: !developer_secret GITHUB_PERSONAL_ACCESS_TOKEN_WITH_BEARER_PREFIX
Authorization: "Bearer ghp_xxxxxxxxxxx"
# Authorization: !developer_secret GITHUB_TOKEN
# Note: When using a developer secret, you need to include the "Bearer " prefix in the secret value

Spotted by Diamond

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.


anthropic:
api_key: your-anthropic-api-key
api_key: your-anthropic-api-key
# api_key: !developer_secret ANTHROPIC_API_KEY
Loading