You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(mcp): mask credentials by default, add file handoff (#1)
The MCP server returned raw xoxc-* tokens and d/d-s cookie values
directly in tool results, placing live Slack credentials into the
calling model's context window, transcript, and provider-side logs
(OWASP LLM Top 10 #2, sensitive information disclosure).
The four read tools now return only masked previews plus metadata.
A new write_credentials_file tool writes the real credentials to a
0600-mode file in a private per-run directory and returns only the
path — secrets travel via the filesystem, never the transcript. The
directory is removed on shutdown.
SLACKTOKENS_MCP_ALLOW_RAW=1 is a documented opt-in that restores raw
inlining for users who knowingly accept the exposure.
A standards-compliant [Model Context Protocol](https://modelcontextprotocol.io) server is shipped under `cmd/slacktokens-mcp/`. It exposes the library as four read-only tools to MCP-capable clients (Claude Code, Claude Desktop, Cursor, etc.) over stdio.
126
+
A standards-compliant [Model Context Protocol](https://modelcontextprotocol.io) server is shipped under `cmd/slacktokens-mcp/`. It exposes the library to MCP-capable clients (Claude Code, Claude Desktop, Cursor, etc.) over stdio.
127
127
128
128
```sh
129
129
go install github.com/hishamkaram/slacktokens/cmd/slacktokens-mcp@latest
130
130
```
131
131
132
+
### Secure by default — credentials never enter the AI's context
133
+
134
+
A Slack token or auth cookie is a live credential. Returning one in a tool result would drop it into the calling model's context window, its transcript, and any provider-side logs — a sensitive-information-disclosure risk. So the MCP server is **masked by default**:
135
+
136
+
- The four read tools return only a **masked preview** (e.g. `xoxc-2…3f9a`) — enough for a human to recognise their own credential, useless as a credential itself — plus workspace/cookie metadata.
137
+
- To hand over **real, usable credentials**, call `write_credentials_file`. It writes them to a freshly created local file readable only by your OS user (mode `0600`) and returns **only the path** — the credential values never enter the model context. The file is removed when the server stops.
138
+
139
+
The credentials file holds the same JSON as `slacktokens` with no flags — `{ "tokens": …, "cookie": …, "cookies": … }` — so you or a script can consume it directly:
| `get_tokens` | `xoxc-*` tokens for every workspace |
137
-
| `get_cookie` | the `d` auth cookie |
138
-
| `get_cookies` | both `d` and `d-s` when present |
139
-
| `get_tokens_and_cookie` | tokens + cookies in one call |
151
+
|`get_tokens`| per-workspace name + **masked**`xoxc-*` token preview |
152
+
|`get_cookie`| the `d` auth cookie, **masked**|
153
+
|`get_cookies`|`d` and `d-s` (when present), **masked**|
154
+
|`get_tokens_and_cookie`| masked tokens + cookies in one call |
155
+
|`write_credentials_file`| path to a `0600` JSON file holding the real credentials |
140
156
141
-
All tools advertise `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`. Each tool's title and description flag the result as **sensitive** so a compliant MCP client surfaces a confirmation prompt before invoking. The server also opts out of the `logging` capability so secrets cannot leak via `notifications/message`.
157
+
The four read tools advertise `readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`. `write_credentials_file` advertises `readOnlyHint: false`and `idempotentHint: false` (it creates a file) and is otherwise non-destructive and offline. The server opts out of the `logging` capability so secrets cannot leak via `notifications/message`.
142
158
143
159
Built against the official Go SDK (`github.com/modelcontextprotocol/go-sdk@v1.6.0`) and the **MCP 2025-11-25** specification.
144
160
161
+
> Note: file handoff keeps secrets out of the model context, transcript, and logs. An agent that *also* has shell/file-read tools can still be explicitly instructed to open the file — that is a deliberate user-directed act, not the silent exposure this design prevents.
162
+
163
+
### Opting in to raw output
164
+
165
+
If you understand the exposure and still want the read tools to inline raw `xoxc-*` tokens and cookie values (the previous behaviour), start the server with the `SLACKTOKENS_MCP_ALLOW_RAW=1` environment variable. Leaving it unset keeps every read tool masked.
166
+
145
167
### Claude Code / Claude Desktop config
146
168
147
169
```jsonc
@@ -154,6 +176,19 @@ Built against the official Go SDK (`github.com/modelcontextprotocol/go-sdk@v1.6.
154
176
}
155
177
```
156
178
179
+
To opt in to raw output, add the environment variable:
180
+
181
+
```jsonc
182
+
{
183
+
"mcpServers": {
184
+
"slacktokens": {
185
+
"command":"slacktokens-mcp",
186
+
"env": { "SLACKTOKENS_MCP_ALLOW_RAW":"1" }
187
+
}
188
+
}
189
+
}
190
+
```
191
+
157
192
(Or use the absolute path to the binary if it isn't on PATH.)
0 commit comments