Skip to main content
Glama
README.md
# slack-mcp

Slack MCP server built from the skeleton-mcp base.

This project exposes Slack Web API operations as MCP tools with:
- stdio and HTTP transport support
- HTTP bearer-token protection for /mcp
- optional admin authorization gates for mutating tools
- per-user Slack bot token routing (different MCP users can run with different Slack tokens)
- admin tools to set/list/get/delete user token assignments
- Vault/Postgres scaffolding preserved from the original skeleton

## What It Does

The server currently focuses on Slack operations:
- Validate Slack token context
- List conversations
- Read conversation history
- Read user profile info
- Post messages
- Call any Slack Web API method via a generic tool

## Slack MCP Tool Catalog

Read-only tools:
- slack_connection_info
- slack_scope_info
- slack_list_methods
- slack_query_suggestions
- slack_auth_test
- slack_conversations_list
- slack_conversation_history
- slack_user_info

Mutating tools:
- slack_post_message
- slack_api_call (only guarded when the method is mutating)

Admin token tools:
- slack_admin_token_set
- slack_admin_token_get
- slack_admin_token_list
- slack_admin_token_delete
- slack_admin_token_refresh
- slack_admin_emulation_set

### Placeholder token emulation mode

If a resolved Slack bot token (from SLACK_BOT_TOKEN, the token store fallback map, or Vault) is
literally the string `placeholder` (case-insensitive), every Slack Web API call is answered with a
locally generated emulated response instead of calling the real Slack API. Emulated responses are
marked with `emulated: true` and `slack_connection_info` reports `slack.emulationActive: true` and
`slack.emulationMode` (`auto`, `on`, or `off`).

This lets the MCP server start and be exercised end-to-end before a real Slack bot token exists.
Once a real token is seeded into Vault for a user, call `slack_admin_token_refresh` to re-read it
and disable emulation for the default client; per-user calls automatically stop being emulated as
soon as `resolveTokenForUser` resolves a non-placeholder token from Vault or the token store.

An admin can also force emulation on or off directly, independent of the configured token, with
`slack_admin_emulation_set` (`mode: "on" | "off" | "auto"`). `"on"` emulates every Slack call
regardless of the token in use; `"off"` always makes real Slack calls even with a placeholder
token; `"auto"` (the default) restores the placeholder-token detection described above.

Authorization behavior:
- If MCP_ADMIN_AUTH_KEY is set, mutating tools require authorizationKey.
- Guarded mutating method names for slack_api_call include chat.postMessage and common write operations like reactions.add, pins.add, conversations.archive, etc.
- Admin token tools always require authorizationKey when MCP_ADMIN_AUTH_KEY is set.

Per-user execution behavior:
- Operational tools accept optional tokenUserId.
- If tokenUserId is omitted, the server uses the request user context (HTTP token metadata userId/subject when available), then MCP_CONFIG_DEFAULT_USER_ID.
- The selected MCP user id is resolved to a Slack bot token via the configured token store.

## Detailed Tool Definitions

### Shared Behavior Across All Tools

- Transport/auth prerequisites:
- stdio mode has no HTTP bearer-token gate.
- HTTP mode requires Authorization: Bearer <token> for /mcp requests.
- If MCP_ADMIN_AUTH_KEY is set, mutating/admin tools require authorizationKey.
- Environment-selection behavior:
- Tools with tokenUserId run as that MCP user.
- If tokenUserId is omitted, user resolution order is: request context userId/subject -> MCP_CONFIG_DEFAULT_USER_ID.
- The selected user is resolved to a Slack bot token from slackTokenStore or fallback SLACK_BOT_TOKEN.
- Common response shape:

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\n  \"ok\": true,\n  \"status\": 200,\n  \"data\": { ... },\n  \"context\": { ... }\n}"
    }
  ]
}
```

- Error shape (encoded in content[0].text) includes:
- ok: false
- status: HTTP-like status code (for example 400, 401, 500)
- error: message

### slack_query_suggestions

- Classification: read-only, low risk.
- Use when:
- You want schema discovery and workflow recommendations for every other MCP tool.
- Do not use when:
- You only need known endpoint names (use slack_list_methods).
- Permissions/prerequisites:
- No authorizationKey required.
- Parameters and constraints:
- toolName: optional non-empty string; exact tool name filter.
- query: optional non-empty string; simple text match against tool metadata.
- includeExamples: optional boolean (default true).
- includeAdmin: optional boolean (default true).
- Expected data payload:
- summary: filter metadata and counts.
- recommendations: common usage sequences.
- tools: per-tool guidance, parameter schema, and optional examples.
- Recommended tools:
- Follow-up: invoke any recommended tool sequence directly from response.
- Example:

```json
{
  "name": "slack_query_suggestions",
  "arguments": {
    "query": "history",
    "includeExamples": true
  }
}
```

### slack_connection_info

- Classification: read-only, low risk.
- Use when:
- You need to verify server metadata, auth-gate configuration, effective request user, Slack client connection config, or token store wiring.
- Do not use when:
- You need to validate a specific Slack token's runtime permissions (use slack_auth_test).
- Permissions/prerequisites:
- No authorizationKey required.
- Requires server startup with valid env parsing.
- Parameters:
- none.
- Expected data payload:
- server: name, version, adminAuthConfigured, scopeModel, requestUserId.
- slack: service connection info.
- tokenStore: token-store connection info or null.
- Common failures:
- Rare; usually process misconfiguration causing server startup failure before tool execution.
- Recommended tools:
- Prerequisite/companion: slack_scope_info.
- Follow-up: slack_auth_test.
- Example:

```json
{
  "name": "slack_connection_info",
  "arguments": {}
}
```

### slack_scope_info

- Classification: read-only, low risk.
- Use when:
- You need deterministic app/user scoping paths for Vault token index and Postgres config keys.
- Do not use when:
- You need actual token values or token metadata (use admin token tools).
- Permissions/prerequisites:
- No authorizationKey required.
- Parameters:
- userId: optional non-empty string.
- If omitted, defaults to MCP_CONFIG_DEFAULT_USER_ID.
- Expected data payload:
- appName, userId, userIdPathSegment.
- postgres model and vault tokenIndexPath.
- Common failures:
- Invalid empty userId.
- Recommended tools:
- Prerequisite: slack_connection_info.
- Follow-up: slack_admin_token_set.
- Example:

```json
{
  "name": "slack_scope_info",
  "arguments": {
    "userId": "alice"
  }
}
```

### slack_list_methods

- Classification: read-only, low risk.
- Use when:
- You want a discoverable list of Slack wrapper endpoints available from this MCP service.
- Do not use when:
- You already know the target method and need execution (use specific tool or slack_api_call).
- Permissions/prerequisites:
- No authorizationKey required.
- Parameters:
- none.
- Expected data payload:
- endpoints: list of known wrapper method descriptors.
- Common failures:
- None typical beyond runtime service-client initialization issues.
- Recommended tools:
- Follow-up: slack_api_call or dedicated wrapper tools.
- Example:

```json
{
  "name": "slack_list_methods",
  "arguments": {}
}
```

### slack_auth_test

- Classification: read-only, low risk.
- Use when:
- You need to validate token identity/workspace and confirm user-token routing is working.
- Do not use when:
- You need channel/message data.
- Permissions/prerequisites:
- No authorizationKey required.
- Token must exist for resolved user (token store or fallback env token).
- Parameters:
- tokenUserId: optional non-empty string.
- Expected data payload:
- data: Slack auth.test response.
- context: tokenUserId and tokenSource used for this invocation.
- Common failures:
- 400 no Slack token configured for resolved user.
- 500 missing SLACK_BOT_TOKEN when token store is absent.
- Slack API errors (invalid_auth, account_inactive, etc.).
- Recommended tools:
- Prerequisite: slack_connection_info.
- Follow-up: slack_conversations_list.
- Example:

```json
{
  "name": "slack_auth_test",
  "arguments": {
    "tokenUserId": "alice"
  }
}
```

### slack_conversations_list

- Classification: read-only, moderate risk (can expose workspace metadata).
- Use when:
- You need channels/DM containers and pagination cursors.
- Do not use when:
- You need message bodies (use slack_conversation_history).
- Permissions/prerequisites:
- No authorizationKey required.
- Token needs conversation-list scopes (for example channels:read/groups:read/im:read/mpim:read).
- Parameters and constraints:
- types: optional non-empty string (Slack conversations.list types format).
- excludeArchived: optional boolean.
- limit: optional positive int <= 999.
- cursor: optional non-empty string.
- teamId: optional non-empty string.
- tokenUserId: optional non-empty string.
- Expected data payload:
- Raw Slack conversations.list response in data.
- context includes tokenUserId/tokenSource.
- Common failures:
- 400 invalid parameter shapes.
- Slack missing_scope/not_in_channel-like access failures.
- Recommended tools:
- Prerequisite: slack_auth_test.
- Follow-up: slack_conversation_history.
- Example:

```json
{
  "name": "slack_conversations_list",
  "arguments": {
    "types": "public_channel,private_channel",
    "excludeArchived": true,
    "limit": 100,
    "tokenUserId": "alice"
  }
}
```

### slack_conversation_history

- Classification: read-only, moderate risk (message-content access).
- Use when:
- You need messages from one conversation with cursor/time-window filtering.
- Do not use when:
- You only need channel discovery (use slack_conversations_list).
- Permissions/prerequisites:
- No authorizationKey required.
- Token needs history scopes for the target conversation type.
- Parameters and constraints:
- channel: required non-empty string.
- cursor: optional non-empty string.
- limit: optional positive int <= 999.
- oldest/latest: optional non-empty string (Slack timestamp string).
- inclusive/includeAllMetadata: optional booleans.
- tokenUserId: optional non-empty string.
- Expected data payload:
- Raw Slack conversations.history response in data.
- context includes tokenUserId/tokenSource.
- Common failures:
- 400 missing channel.
- Slack channel_not_found, not_in_channel, missing_scope.
- Recommended tools:
- Prerequisite: slack_conversations_list.
- Follow-up: slack_user_info (to resolve user ids in messages).
- Example:

```json
{
  "name": "slack_conversation_history",
  "arguments": {
    "channel": "C0123456789",
    "limit": 50,
    "oldest": "1710000000.000000",
    "tokenUserId": "alice"
  }
}
```

### slack_user_info

- Classification: read-only, moderate risk (PII exposure depending on scopes).
- Use when:
- You need profile details for a Slack user id.
- Do not use when:
- You need to list users in bulk (use slack_api_call with users.list if needed).
- Permissions/prerequisites:
- No authorizationKey required.
- users:read scope required; users:read.email for email fields.
- Parameters and constraints:
- user: required non-empty string.
- includeLocale: optional boolean.
- tokenUserId: optional non-empty string.
- Expected data payload:
- Raw Slack users.info response in data.
- context includes tokenUserId/tokenSource.
- Common failures:
- 400 missing user.
- Slack user_not_found or missing_scope.
- Recommended tools:
- Prerequisite: slack_auth_test.
- Follow-up: slack_post_message (for user-related workflows).
- Example:

```json
{
  "name": "slack_user_info",
  "arguments": {
    "user": "U0123456789",
    "includeLocale": true,
    "tokenUserId": "alice"
  }
}
```

### slack_post_message

- Classification: mutating, high risk.
- Use when:
- You need to send a message to a channel/DM/thread.
- Do not use when:
- You need read-only checks (use auth/list/history tools).
- Permissions/prerequisites:
- chat:write scope required.
- If MCP_ADMIN_AUTH_KEY is set, authorizationKey is required and must match.
- Parameters and constraints:
- channel: required non-empty string.
- text: optional string, 1..40000 chars when provided.
- blocks: optional array<object>.
- threadTs: optional non-empty string.
- replyBroadcast/unfurlLinks/unfurlMedia: optional booleans.
- tokenUserId: optional non-empty string.
- authorizationKey: required when admin auth is enabled.
- Expected data payload:
- Raw Slack chat.postMessage response in data.
- context includes tokenUserId/tokenSource.
- Common failures:
- 401 invalid/missing authorizationKey when required.
- Slack channel_not_found, not_in_channel, missing_scope, invalid_blocks.
- Safety warnings:
- This operation sends real Slack messages.
- Validate channel and content before execution, especially in production workspaces.
- Recommended tools:
- Prerequisite: slack_auth_test and optional slack_conversations_list.
- Follow-up: slack_conversation_history (confirm posted message).
- Example:

```json
{
  "name": "slack_post_message",
  "arguments": {
    "channel": "C0123456789",
    "text": "Deployment completed successfully.",
    "tokenUserId": "alice",
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

### slack_api_call

- Classification: mixed.
- read-only when calling read methods.
- mutating/high risk when methodName is in guarded mutating set.
- Use when:
- You need a Slack Web API method not wrapped by a dedicated tool.
- Do not use when:
- A dedicated wrapper exists and provides stronger parameter contracts.
- Permissions/prerequisites:
- Requires a valid token for resolved user.
- If methodName is guarded mutating (for example chat.postMessage, reactions.add, pins.add, conversations.archive), authorizationKey is required when MCP_ADMIN_AUTH_KEY is set.
- Parameters and constraints:
- methodName: required non-empty string; normalized to lower-case before dispatch.
- params: optional JSON object.
- tokenUserId: optional non-empty string.
- authorizationKey: required for guarded mutating calls when admin auth is enabled.
- Expected data payload:
- Raw Slack method response in data.
- context includes tokenUserId/tokenSource.
- Common failures:
- 401 for guarded mutating calls without valid authorizationKey.
- Slack unknown_method, invalid_arguments, missing_scope.
- Safety warnings:
- Generic access can invoke broad Slack behaviors.
- Prefer least-privilege scopes and dedicated wrappers when possible.
- Recommended tools:
- Prerequisite: slack_list_methods and slack_auth_test.
- Follow-up: method-specific read calls to verify side effects.
- Example (read):

```json
{
  "name": "slack_api_call",
  "arguments": {
    "methodName": "users.list",
    "params": {
      "limit": 100
    },
    "tokenUserId": "alice"
  }
}
```

- Example (guarded mutating):

```json
{
  "name": "slack_api_call",
  "arguments": {
    "methodName": "reactions.add",
    "params": {
      "channel": "C0123456789",
      "name": "white_check_mark",
      "timestamp": "1710000000.000000"
    },
    "tokenUserId": "alice",
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

### slack_admin_token_set

- Classification: mutating, high risk (credential write path).
- Use when:
- You need to create/update a per-user Slack bot token mapping.
- Do not use when:
- You only need to inspect mappings (use slack_admin_token_get/list).
- Permissions/prerequisites:
- If MCP_ADMIN_AUTH_KEY is set, authorizationKey is required and must match.
- slackTokenStore must be configured.
- Parameters and constraints:
- userId: required non-empty string.
- botToken: required non-empty string.
- note: optional string max 500.
- authorizationKey: required when admin auth is enabled.
- Expected data payload:
- Token-store write result metadata (user id, configured state, timestamps/source depending on store).
- Common failures:
- 401 invalid/missing authorizationKey when required.
- 500 slackTokenStore is not configured.
- store backend failures (Vault unavailable, permission denied).
- Safety warnings:
- Stores active credentials for future tool execution.
- Restrict access and audit usage.
- Recommended tools:
- Prerequisite: slack_scope_info.
- Follow-up: slack_admin_token_get and slack_auth_test.
- Example:

```json
{
  "name": "slack_admin_token_set",
  "arguments": {
    "userId": "alice",
    "botToken": "xoxb-...",
    "note": "Primary workspace bot token",
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

### slack_admin_token_refresh

- Classification: admin, high risk (credential control-flow).
- Use when:
- SLACK_BOT_TOKEN=placeholder was used to start the server and a real bot token has since been
  seeded into Vault; use this to disable emulation mode for the default Slack client.
- Do not use when:
- No slackTokenStore is configured, or the Vault secret still holds the placeholder value.
- Permissions/prerequisites:
- If MCP_ADMIN_AUTH_KEY is set, authorizationKey is required and must match.
- slackTokenStore must be configured.
- Parameters and constraints:
- userId: optional string, defaults to the request/default MCP user id.
- authorizationKey: required when admin auth is enabled.
- Expected data payload:
- `{ userId, refreshed, emulationActive, tokenSource }`; `refreshed: false` and
  `emulationActive: true` when Vault still only has the placeholder token.
- Common failures:
- 400 no token found in Vault for the user.
- 401 invalid/missing authorizationKey when required.
- 500 slackTokenStore is not configured.
- Safety warnings:
- Only disables emulation once a genuine token is present in Vault; does not create tokens.
- Recommended tools:
- Prerequisite: seed a real token into Vault out-of-band.
- Follow-up: slack_auth_test, slack_connection_info.
- Example:

```json
{
  "name": "slack_admin_token_refresh",
  "arguments": {
    "userId": "default",
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

### slack_admin_emulation_set

- Classification: admin, high risk (changes whether real Slack calls are made at all).
- Use when:
- You want to deliberately enter emulation mode for testing/demos, or force real Slack calls even
  though the resolved token is the placeholder value.
- Do not use when:
- You only want the default automatic behavior (placeholder token -> emulated, real token -> real
  calls); use `mode: "auto"` to restore that, or simply do nothing.
- Permissions/prerequisites:
- If MCP_ADMIN_AUTH_KEY is set, authorizationKey is required and must match.
- Parameters and constraints:
- mode: required, one of `on`, `off`, `auto`.
- authorizationKey: required when admin auth is enabled.
- Expected data payload:
- `{ emulationMode, emulationActive }`.
- Common failures:
- 401 invalid/missing authorizationKey when required.
- Safety warnings:
- `mode: "off"` sends real requests to Slack even with a placeholder token, which Slack will reject
  as invalid_auth; `mode: "on"` silently emulates all calls, including mutating ones like
  slack_post_message, so no real message is sent.
- Recommended tools:
- Follow-up: slack_connection_info to confirm the active mode.
- Example:

```json
{
  "name": "slack_admin_emulation_set",
  "arguments": {
    "mode": "on",
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

### slack_admin_token_get

- Classification: read-only, high risk when includeToken=true (credential exposure).
- Use when:
- You need token metadata or token value (explicitly) for a user mapping.
- Do not use when:
- You only need a roster of configured users (use slack_admin_token_list).
- Permissions/prerequisites:
- If MCP_ADMIN_AUTH_KEY is set, authorizationKey is required and must match.
- slackTokenStore must be configured.
- Parameters and constraints:
- userId: required non-empty string.
- includeToken: optional boolean (default false recommended).
- authorizationKey: required when admin auth is enabled.
- Expected data payload:
- Metadata summary.
- If includeToken=true and configured, includes token field.
- Common failures:
- 401 invalid/missing authorizationKey when required.
- 500 slackTokenStore is not configured.
- Safety warnings:
- includeToken=true reveals secret material in tool output.
- Prefer includeToken=false unless strictly required.
- Recommended tools:
- Follow-up: slack_auth_test.
- Example:

```json
{
  "name": "slack_admin_token_get",
  "arguments": {
    "userId": "alice",
    "includeToken": false,
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

### slack_admin_token_list

- Classification: read-only, moderate risk (reveals configured user identifiers).
- Use when:
- You need to enumerate MCP users with configured Slack token records.
- Do not use when:
- You need details for one user (use slack_admin_token_get).
- Permissions/prerequisites:
- If MCP_ADMIN_AUTH_KEY is set, authorizationKey is required and must match.
- slackTokenStore must be configured.
- Parameters:
- authorizationKey: required when admin auth is enabled.
- Expected data payload:
- users: array of configured user summaries.
- Common failures:
- 401 invalid/missing authorizationKey when required.
- 500 slackTokenStore is not configured.
- Recommended tools:
- Follow-up: slack_admin_token_get or slack_admin_token_delete.
- Example:

```json
{
  "name": "slack_admin_token_list",
  "arguments": {
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

### slack_admin_token_delete

- Classification: mutating, high risk (credential deletion).
- Use when:
- You need to revoke/remove stored Slack token mappings for a user.
- Do not use when:
- You only need to disable usage temporarily (consider rotating token externally first).
- Permissions/prerequisites:
- If MCP_ADMIN_AUTH_KEY is set, authorizationKey is required and must match.
- slackTokenStore must be configured.
- Parameters and constraints:
- userId: required non-empty string.
- authorizationKey: required when admin auth is enabled.
- Expected data payload:
- userId and deleted boolean.
- Common failures:
- 401 invalid/missing authorizationKey when required.
- 500 slackTokenStore is not configured.
- store backend failures.
- Safety warnings:
- Destructive operation for local token mapping.
- Confirm target userId before deletion.
- Recommended tools:
- Prerequisite: slack_admin_token_get.
- Follow-up: slack_admin_token_list and slack_auth_test (for validation of revocation impact).
- Example:

```json
{
  "name": "slack_admin_token_delete",
  "arguments": {
    "userId": "alice",
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

## Slack API Notes

Configured Slack client:
- Base URL defaults to https://slack.com/api
- Bot token is required via SLACK_BOT_TOKEN

Implemented method wrappers:
- auth.test
- conversations.list
- conversations.history
- users.info
- chat.postMessage

Generic method execution:
- slack_api_call sends POST to /<methodName> with params JSON payload
- Example methodName: conversations.info, users.list, chat.postMessage

## Required Slack Scopes

Typical scopes you should grant your Slack app for these tools:
- chat:write for slack_post_message
- channels:read, groups:read, im:read, mpim:read for conversations.list
- channels:history, groups:history, im:history, mpim:history for conversations.history
- users:read for users.info
- users:read.email if you need email in users.info responses

Exact required scopes can vary by workspace and conversation type.

## Environment Variables

Slack-specific:
- SLACK_BOT_TOKEN (optional default/fallback token)
- SLACK_API_BASE_URL (default: https://slack.com/api)
- SLACK_TIMEOUT_MS (default: 15000)
- MCP_SLACK_TOKEN_STORE (vault|memory; default auto-detects from Vault config)
- MCP_SLACK_DEFAULT_TOKEN_IN_VAULT (default: true)
- MCP_SLACK_USER_TOKENS_JSON (optional JSON fallback map, e.g. {"alice":"xoxb-..."})

Core app:
- APP_NAME
- MCP_SERVER_NAME (default: slack-mcp)
- MCP_SERVER_VERSION
- MCP_ADMIN_AUTH_KEY
- MCP_TRANSPORT_MODE (stdio, http, both)

HTTP transport:
- MCP_HTTP_HOST
- MCP_HTTP_PORT
- MCP_HTTP_PATH
- MCP_HTTP_HEALTH_PATH
- MCP_HTTP_AUTH_MODE
- MCP_HTTP_AUTH_TOKENS
- MCP_HTTP_TRUST_PROXY
- MCP_HTTP_ALLOWED_ORIGINS
- MCP_HTTP_ALLOWED_IPS
- MCP_HTTP_MAX_BODY_BYTES
- MCP_HTTP_RATE_LIMIT_WINDOW_MS
- MCP_HTTP_RATE_LIMIT_MAX_REQUESTS
- MCP_HTTP_TOKEN_SOURCE (vault|static; when vault, enables Vault token verifier metadata)
- MCP_HTTP_VAULT_TOKEN_INDEX_PATH
- MCP_HTTP_VAULT_TOKEN_DEFAULT_USER_ID
- MCP_HTTP_VAULT_TOKEN_REQUIRED_SCOPES
- MCP_HTTP_VAULT_TOKEN_REQUIRED_AUDIENCE
- MCP_HTTP_VAULT_TOKEN_CACHE_TTL_MS

For full defaults and examples, see .env.example.

## Quick Start

1. Install dependencies:

```bash
npm install
```

2. Copy env file and set Slack token:

```bash
cp .env.example .env
```

Set at minimum:
- SLACK_BOT_TOKEN=xoxb-...

3. Start MCP server:

```bash
npm run start:stdio
```

Or HTTP mode:

```bash
npm run start:http
```

4. Run tests:

```bash
npm test
```

## Registering in MCP Clients

### VS Code (stdio)

Example .vscode/mcp.json entry:

```json
{
  "command": "npm",
  "args": ["run", "start:stdio"],
  "cwd": "/path/to/slack-mcp"
}
```

### HTTP-capable clients

Run:

```bash
npm run start:http
```

Default endpoint:
- MCP: http://127.0.0.1:3000/mcp
- Health: http://127.0.0.1:3000/healthz

## HTTP Security Model

- Every /mcp request requires Authorization: Bearer <token>
- Token validation currently uses configured MCP_HTTP_AUTH_TOKENS unless other auth sources are wired
- Rate limit and body-size protections are enforced by src/http/server.js

With MCP_HTTP_TOKEN_SOURCE=vault and a Vault token index configured:
- incoming bearer tokens are verified via Vault token metadata
- user metadata (for example userId/subject) is propagated to MCP request context
- Slack tool execution defaults to that user context unless tokenUserId is explicitly provided

## Multi-User Token Administration

Use admin tools to manage user-to-Slack-token mappings:

1. Set token for a user:

```json
{
  "name": "slack_admin_token_set",
  "arguments": {
    "userId": "alice",
    "botToken": "xoxb-...",
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

2. Verify a user token mapping:

```json
{
  "name": "slack_admin_token_get",
  "arguments": {
    "userId": "alice",
    "includeToken": false,
    "authorizationKey": "<MCP_ADMIN_AUTH_KEY>"
  }
}
```

3. Run a Slack call as that user:

```json
{
  "name": "slack_auth_test",
  "arguments": {
    "tokenUserId": "alice"
  }
}
```

Token records are stored per user under Vault path:
- <appName>/users/<normalizedUserId>/http/auth/token-index

If Vault token storage is disabled, mappings are kept in-memory for that process.

Note:
- TLS termination is intended at reverse proxy/load balancer level in this process mode.

## External Services Mode

The repository still supports an app-only startup profile via docker-compose.external.yml when using external Vault and Postgres services.

Required variables in that mode include:
- POSTGRES_HOST
- POSTGRES_PORT
- POSTGRES_DB
- POSTGRES_USER
- POSTGRES_PASSWORD
- VAULT_ADDR
- VAULT_TOKEN

Start with:

```bash
docker compose -f docker-compose.external.yml up -d
```

## Project Structure

Primary runtime files:
- src/index.js: stdio startup
- src/http/index.js: HTTP startup
- src/http/server.js: HTTP transport/auth/rate limiting
- src/mcp/server.js: MCP tool registration and auth checks
- src/services/targetService.js: SlackServiceClient adapter
- src/config/env.js: env parsing/validation

Skeleton infrastructure (preserved):
- src/services/vault.js
- src/services/configStore.js
- docker-compose.yml
- docker-compose.external.yml
- vault-production/

## Testing

Current tests include:
- Slack MCP tool behavior and mutating auth requirements
- HTTP transport auth/initialize/health behavior
- Existing skeleton Vault/config infrastructure tests

Run all:

```bash
npm test
```

## Known Follow-up Work

The server behavior is Slack-specific, but some legacy skeleton assets remain intentionally preserved (Vault/Postgres flows and migration docs). If desired, those docs and compose defaults can be slimmed to a Slack-only deployment profile in a follow-up pass.