Result: By the end of this tutorial you will have a locally hosted Model Context Protocol (MCP) server that receives Slack slash commands, authenticates the request, forwards the intent to Claude via MCP, and writes the result into a Google Sheet - all without ever exposing your API keys to the public internet.
What you'll get: a reproducible Docker-based stack, a Slack app that triggers the workflow, and a secure webhook that ties the three pieces together.
What is MCP? Model Context Protocol (MCP) is an open-source standard that lets LLMs call external services (APIs, databases, files) as if they were native functions. Think of it as a USB-C port for AI: any model that understands MCP can plug into your custom workflow without custom code for each integration.
What is a Slack slash command? A slash command is a special message that starts with "/" in Slack. When a user types it, Slack sends an HTTP POST to a URL you configure, allowing you to run arbitrary logic on the back-end.
What is the Google Sheets API? A RESTful interface that lets you read, write, and format spreadsheets programmatically.
What you need
| Tool | Plan / Price | Role |
|---|---|---|
| Docker | Free (self-hosted) | Container runtime for n8n and the MCP server |
| n8n | Community (free) or Cloud $20 / month | Visual workflow engine that hosts the webhook and MCP nodes |
| Node.js (v20) | Free | Runtime for any custom MCP adapters you may write |
| Slack App | Free | Provides the slash command endpoint |
| Google Cloud project | Free tier (check Google's current pricing) | Enables the Google Sheets API and OAuth2 credentials |
| Anthropic Claude API | Pay-as-you-go (≈ $0.25 per 1 M input tokens) | LLM that executes MCP calls |
| VS Code | Free | Code editor for editing JSON and scripts |
| Git | Free | Version control for your configuration files |
Time to build: 4 - 6 hours, assuming you have a basic familiarity with Docker and OAuth2.
How to build mcp server for slack
Below is a concrete, numbered walk-through. Every step names the exact UI field, JSON key, or CLI flag you need to set.
1. Install the local toolchain
Open a terminal and run the following commands.
If Docker reports "permission denied", add your user to the docker group (sudo usermod -aG docker $USER).
Key insight: Using Docker isolates n8n and the MCP server from your host OS, making it easy to spin up the exact versions the docs reference.
2. Create a Slack app and enable a slash command
1. Go to <https://api.slack.com/apps> and click Create New App → From scratch.
2. Name the app "MCP-Sheets Bridge" and pick the workspace where you'll test.
3. In the left sidebar, select Slash Commands → Create New Command.
- Command: /sheetadd
- Request URL: https://YOUR_PUBLIC_HOST/webhook/slack (you'll replace YOUR_PUBLIC_HOST later).
- Short description: "Add a row to the finance sheet".
- Usage hint: key=value ...
4. Save the command. Slack will generate a Signing Secret under Basic Information - copy it; you'll need it for request verification.
3. Set up a Google Cloud project and OAuth2 credentials
1. Open <https://console.cloud.google.com/> and create a new project called "MCP-Sheets".
2. In the navigation menu, go to APIs & Services → Library and enable Google Sheets API.
3. Still under APIs & Services, click OAuth consent screen → External → Create. Fill in the required fields (app name, support email).
4. Under Credentials, click Create Credentials → OAuth client ID → Web application.
- Authorized redirect URIs: https://YOUR_PUBLIC_HOST/oauth2callback (replace later).
- Authorized JavaScript origins: https://YOUR_PUBLIC_HOST.
5. Click Create and download the JSON file. Rename it to google-credentials.json and keep it in a secure folder (e.g., ./secrets).
Why this matters: The OAuth client lets n8n obtain a short-lived access token that the Google Sheets node will use.
4. Deploy n8n with Docker
Create a docker-compose.yml in a new folder mcp-slack.
Generate a self-signed certificate (or use Let's Encrypt via a reverse proxy).
Start the stack:
Visit https://localhost:5678 (accept the self-signed warning) and log in with the credentials you set (admin / changeme123).
5. Add a Webhook node to receive Slack commands
- In the n8n UI, click New Workflow → Add Node → search "Webhook".
- Set HTTP Method to
POST. - Set Path to
webhook/slack. This matches the URL you gave Slack in step 2. - Enable Response Mode →
On Received. This will let us acknowledge Slack quickly (within 3000 ms).
6. Verify Slack signatures (security)
Add a Function node after the webhook to validate the request.
Add the environment variable SLACK_SIGNING_SECRET in the n8n Docker compose file under environment: (or via the UI's Credentials tab).
7. Parse the slash command arguments
Slack sends the command payload as a URL-encoded string (text=key1=value1+key2=value2). Add another Function node to turn it into a JSON object.
Now $json.payload holds { "name": "Bob", "amount": "42" }.
8. Call Claude via MCP to format the row
Claude does not need to know the Google Sheets details; it only needs to request an MCP operation. Use an HTTP Request node configured for the Anthropic API.
- Method:
POST - URL:
https://api.anthropic.com/v1/complete - Authentication: Bearer token (set
ANTHROPIC_API_KEYin n8n credentials). - Headers:
Content-Type: application/json,anthropic-version: 2023-06-01 - Body (JSON):
The response will contain an MCP-compatible JSON block that looks like:
9. Execute the MCP call with the MCP node
n8n does not ship a native MCP node, but you can use a Function node to forward the JSON to a tiny MCP server you'll run locally. First, spin up the MCP server (see step 10). Then add an HTTP Request node:
- Method:
POST - URL:
http://host.docker.internal:8000/mcp(Docker bridge to host). - Body:
{{ $json.mcp }}(the MCP payload from Claude).
The MCP server will translate the request into a Google Sheets API call and return success/failure.
10. Run a minimal MCP server (Node.js)
Create a folder mcp-server and add package.json:
Install dependencies:
Create server.js:
Run the server:
What this does: It exposes a single /mcp endpoint that accepts the MCP JSON from Claude, validates the action, and calls the Google Sheets API to append the row.
11. Wire everything together in n8n
Connect the nodes in this order:
- Webhook → 2. Function (verify Slack) → 3. Function (parse args) → 4. HTTP Request (Claude) → 5. Function (extract MCP payload) → 6. HTTP Request (MCP server) → 7. Set (optional: format a success message) → 8. Respond to Slack.
In the final Respond to Slack node, set Response Body to:
Save the workflow and activate it (toggle the switch in the top-right).
12. Expose the webhook publicly (development only)
For local testing you can use ngrok:
Copy the generated HTTPS URL (e.g., https://abcd1234.ngrok.io) and replace YOUR_PUBLIC_HOST in the Slack app's Request URL and the Google OAuth redirect URI.
⚠️ Important: Never leave a development tunnel open in production. Deploy the same Docker compose stack behind a proper reverse proxy (Traefik, Caddy) with a real TLS certificate.
13. Test the end-to-end flow
In Slack, type:
You should see the confirmation message, and the row appear in the target Google Sheet. Check the n8n execution log for any errors.
Where this breaks
| Failure mode | Symptom | Fix |
|---|---|---|
| Slack signature mismatch | 400 error from n8n, "Invalid Slack signature" | Ensure the SLACK_SIGNING_SECRET env var matches the secret shown in Slack's Basic Information page. |
| Google OAuth token expired | MCP server logs "Request failed with status code 401" | Run the OAuth refresh flow: open https://accounts.google.com/o/oauth2/v2/auth?... with the client ID, grant access, and save the returned refresh_token to google-token.json. |
| Rate limit on Google Sheets API | 429 response, "User rate limit exceeded" | Batch multiple rows into a single append call, or request a higher quota in the Google Cloud console. |
| Anthropic rate limit | 429 from api.anthropic.com | Back-off 1 second and retry; consider purchasing a higher-tier plan if you exceed the free quota. |
| MCP server not reachable | n8n HTTP Request returns "ECONNREFUSED" | Verify Docker networking (host.docker.internal works on your OS) or expose the MCP server on the same Docker network. |
| Cost blow-up | Unexpected charge on Anthropic billing | Set a hard limit in the Anthropic dashboard, and add a n8n IF node that aborts if token usage exceeds a threshold. |
| HTTPS misconfiguration | Slack rejects the webhook with "Invalid URL" | Use a valid TLS certificate; Slack requires HTTPS with a trusted CA. |
> Never expose raw API keys in the webhook URL or in Slack's command text. All secrets must live in environment variables or Docker secrets.
For a deeper technical reference, see n8n's documentation.