448 Commits

Author SHA1 Message Date
Paymahn Moghadasian 4eaf5247b3 docs: explain how the CLI works (in-process handler invocation, shared cache) 2026-06-26 11:12:32 -05:00
Paymahn Moghadasian 8963a2e139 chore(napkin): record real-workspace verification 2026-06-26 11:07:45 -05:00
Paymahn Moghadasian 6a972a1f05 feat: add slack-cli, a no-daemon CLI over the slack-mcp-server engine
Turn the forked slack-mcp-server into a CLI so running many agents no
longer means one resident MCP process each. Every command is a
short-lived process that reads the shared on-disk cache.

- rename module to github.com/paymog/slack-cli (go install/homebrew/ldflags)
- internal/toolcall: invoke the upstream tool handlers in-process; the only
  mcp-go coupling lives here, so pkg/handler and pkg/provider are reused
  byte-for-byte (clean upstream merges, fork-and-extend)
- internal/{cli,cmds,config,credstore,runtime,output}: cobra command tree,
  keyring-backed credential profiles, provider bootstrap, result printing
- 21 tools as subcommands (channels, conversations, users, usergroups,
  saved, reactions, attachments, cache); write tools keep their env gating
- goreleaser + homebrew release workflow; ships a skills/slack-cli skill
- unit tests for config/credstore/toolcall; MCP server still builds

The MCP server (cmd/slack-mcp-server) is kept intact.
2026-06-26 11:04:05 -05:00
Dmitrii Korotovskii b88c0de3f7 Remove maintainer note from configuration documentation 2026-05-15 00:51:29 +02:00
Dmitrii Korotovskii 31f3f69e62 Update 02-installation.md 2026-05-15 00:51:15 +02:00
Dmitrii Korotovskii 2aedf06896 Remove maintainer note from authentication setup 2026-05-15 00:50:58 +02:00
Dmitrii Korotovskii a079b3cd4d Golang version bump to 1.25 2026-05-15 00:46:32 +02:00
Dmitrii Korotovskii cf0ce0d8f5 Integration tests fix 2026-05-15 00:42:57 +02:00
Dmitrii Korotovskii b58192cd5e Update go in Dockerfile 2026-05-15 00:26:19 +02:00
Dmitrii Korotovskii c88ed62a61 fix: pass ctx to convertMessagesFromHistory calls in saved.go
PR #269 added a leading ctx parameter to convertMessagesFromHistory
but missed the three call sites in saved.go, breaking the build.
2026-05-14 23:09:33 +02:00
Dmitrii Korotovskii 01f0ad4525 Revert "Merge pull request #292 from korotovsky/dependabot/go_modules/go-dependencies-f46f41233a"
This reverts commit 400c900774, reversing
changes made to 19e8a0c7b1.
2026-05-14 23:07:52 +02:00
Dmitrii Korotovskii 342e3e3cd2 Merge pull request #269 from gkatz2/feature/targeted-user-cache-patch
Add targeted user cache patch on miss
2026-05-14 23:01:12 +02:00
Dmitrii Korotovskii 400c900774 Merge pull request #292 from korotovsky/dependabot/go_modules/go-dependencies-f46f41233a
deps(go): bump the go-dependencies group across 1 directory with 9 updates
2026-05-14 23:01:07 +02:00
Dmitrii Korotovskii 19e8a0c7b1 test: fix TestIntegrationChannelsListQueryFilter to assert on Name column
The integration test added in #252 was reading row[0], which is the channel
ID column in channels_list CSV output, not the channel name. The CI for
#252 never ran (status checks were empty at merge time), so this slipped
through. Now resolves to the Name column by header lookup, matching the
convention used elsewhere in this file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 22:32:53 +02:00
Dmitrii Korotovskii 2e2c4b5e92 Merge pull request #192 from derodero24/feat/extract-email-file-text
feat: extract email metadata from file-type messages
2026-05-14 22:28:05 +02:00
derodero24 c298e5cf9c feat: extract email metadata from file-type messages
When emails are forwarded to Slack channels, message content is stored in
files[] with filetype "email" rather than in text or blocks. This adds
FilesToText() to extract From, CC, and Subject metadata as a fallback
when msg.Text is empty, so these messages no longer appear as blank rows
in conversations_history output.

Closes #191
2026-05-14 22:27:26 +02:00
dependabot[bot] 781cc51f20 deps(go): bump the go-dependencies group across 1 directory with 9 updates
Bumps the go-dependencies group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/mark3labs/mcp-go](https://github.com/mark3labs/mcp-go) | `0.44.0` | `0.54.0` |
| [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) | `0.0.20` | `0.0.22` |
| [github.com/slack-go/slack](https://github.com/slack-go/slack) | `0.19.0` | `0.23.1` |
| [github.com/takara2314/slack-go-util](https://github.com/takara2314/slack-go-util) | `0.4.0` | `0.4.1` |
| [go.uber.org/zap](https://github.com/uber-go/zap) | `1.27.1` | `1.28.0` |
| [golang.ngrok.com/ngrok/v2](https://github.com/ngrok/ngrok-go) | `2.1.1` | `2.1.4` |
| [golang.org/x/net](https://github.com/golang/net) | `0.50.0` | `0.54.0` |
| [golang.org/x/time](https://github.com/golang/time) | `0.14.0` | `0.15.0` |



Updates `github.com/mark3labs/mcp-go` from 0.44.0 to 0.54.0
- [Release notes](https://github.com/mark3labs/mcp-go/releases)
- [Commits](https://github.com/mark3labs/mcp-go/compare/v0.44.0...v0.54.0)

Updates `github.com/mattn/go-isatty` from 0.0.20 to 0.0.22
- [Commits](https://github.com/mattn/go-isatty/compare/v0.0.20...v0.0.22)

Updates `github.com/slack-go/slack` from 0.19.0 to 0.23.1
- [Release notes](https://github.com/slack-go/slack/releases)
- [Changelog](https://github.com/slack-go/slack/blob/master/CHANGELOG.md)
- [Commits](https://github.com/slack-go/slack/compare/v0.19.0...v0.23.1)

Updates `github.com/takara2314/slack-go-util` from 0.4.0 to 0.4.1
- [Release notes](https://github.com/takara2314/slack-go-util/releases)
- [Commits](https://github.com/takara2314/slack-go-util/compare/v0.4.0...v0.4.1)

Updates `go.uber.org/zap` from 1.27.1 to 1.28.0
- [Release notes](https://github.com/uber-go/zap/releases)
- [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/zap/compare/v1.27.1...v1.28.0)

Updates `golang.ngrok.com/ngrok/v2` from 2.1.1 to 2.1.4
- [Release notes](https://github.com/ngrok/ngrok-go/releases)
- [Changelog](https://github.com/ngrok/ngrok-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ngrok/ngrok-go/compare/v2.1.1...v2.1.4)

Updates `golang.org/x/net` from 0.50.0 to 0.54.0
- [Commits](https://github.com/golang/net/compare/v0.50.0...v0.54.0)

Updates `golang.org/x/sync` from 0.19.0 to 0.20.0
- [Commits](https://github.com/golang/sync/compare/v0.19.0...v0.20.0)

Updates `golang.org/x/time` from 0.14.0 to 0.15.0
- [Commits](https://github.com/golang/time/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: github.com/mark3labs/mcp-go
  dependency-version: 0.50.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
- dependency-name: github.com/mattn/go-isatty
  dependency-version: 0.0.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-dependencies
- dependency-name: github.com/slack-go/slack
  dependency-version: 0.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
- dependency-name: github.com/takara2314/slack-go-util
  dependency-version: 0.4.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
- dependency-name: go.uber.org/zap
  dependency-version: 1.28.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
- dependency-name: golang.ngrok.com/ngrok/v2
  dependency-version: 2.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-dependencies
- dependency-name: golang.org/x/net
  dependency-version: 0.53.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
- dependency-name: golang.org/x/sync
  dependency-version: 0.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
- dependency-name: golang.org/x/time
  dependency-version: 0.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-14 20:25:25 +00:00
Dmitrii Korotovskii bee5d73883 deps: bump jsonparser v1.1.1→v1.1.2 and go-jose/v3 v3.0.4→v3.0.5
Resolves the two HIGH-severity findings from the Trivy filesystem scan:
- CVE-2026-32285 (github.com/buger/jsonparser, fixed in v1.1.2)
- CVE-2026-34986 (github.com/go-jose/go-jose/v3, fixed in v3.0.5)

Both are indirect deps, bumped via `go get` + `go mod tidy`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 22:23:24 +02:00
Dmitrii Korotovskii bfc6fb7e73 Merge pull request #220 from georgebashi/feat/channels-me
feat: add channels_me tool
2026-05-14 22:21:28 +02:00
George Bashi ae3c7b4f13 perf: remove sort param from channels_me, always use fast path
The sort=popularity option forced fetching every channel the user belongs
to before sorting client-side — hundreds of API calls on large workspaces.
The Slack API doesn't support server-side sorting, so this was inherently
expensive. Remove it and always stop fetching once we have enough results,
using the Slack API's native cursor for pagination.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-14 22:20:31 +02:00
George Bashi 6f0114928a perf: stop fetching all API pages in channels_me when not needed
When sort is not "popularity", stop paginating the Slack API as soon as
we have enough results for the requested limit, and pass through the
API's native cursor. On large workspaces this avoids hundreds of API
calls when only a small number of channels are requested.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-14 22:20:31 +02:00
George Bashi 55842fe2c8 feat: add channels_me tool
Add a new MCP tool to list channels the calling user is a member of,
using the users.conversations API. Follows the same pattern as
usergroups_me vs usergroups_list.

Unlike channels_list which returns all workspace channels, channels_me
returns only channels the user has joined — useful on large workspaces
where channels_list returns thousands of results.

Supports channel_types, sort (by popularity), limit, and cursor
parameters.
2026-05-14 22:20:31 +02:00
Dmitrii Korotovskii b32ab23eb9 test: update title_with_link expectation after bracket-substitution removal
The test was added by #272 (d3f7ca3) when AttachmentToText still applied
`(` → `[` and `)` → `]` substitutions, which produced `[text][url]` output.
#281 (5c095ac) removed those substitutions, so AttachmentToText now emits
proper markdown `[text](url)`. The test wasn't updated in #281's merge.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 22:19:20 +02:00
Dmitrii Korotovskii 5c095ac935 Merge pull request #281 from byrmsh/fix/preserve-message-content
fix(text): stop deleting punctuation, emoji, and quotes from messages
2026-05-14 22:12:01 +02:00
Dmitrii Korotovskii c653429517 Merge pull request #272 from tim-watcha/feat/attachment-fields
fix: bot and integration messages silently lose structured content
2026-05-14 22:11:48 +02:00
Dmitrii Korotovskii e49db6aa24 Merge pull request #252 from unsafe9/feature/channels-list-query-filter
feat: add query and query_targets parameters to channels_list tool
2026-05-14 22:11:40 +02:00
Dmitrii Korotovskii 69cd994d9d Merge pull request #240 from jonzarecki/feat/saved-items
feat: add saved_list, saved_update, and saved_clear_completed tools
2026-05-14 22:11:31 +02:00
Dmitrii Korotovskii 60566a196f Merge pull request #225 from flacoste/feat/stale-while-revalidate-cache
feat: stale-while-revalidate cache for large Slack workspaces
2026-05-14 22:10:59 +02:00
Dmitrii Korotovskii 21775f640d Merge pull request #237 from vbichkovsky/feat/native-image-content
feat: return image attachments as native MCP image content
2026-05-14 22:10:26 +02:00
Dmitrii Korotovskii a93cb3ea24 Merge pull request #280 from korotovsky/dependabot/github_actions/github-actions-0edc9ef621
deps(gha): bump the github-actions group across 1 directory with 5 updates
2026-05-14 22:10:15 +02:00
Francis J. Lacoste df22121447 fix: address code review findings from multi-agent analysis
- Fix infinite loop on cold start when API returns zero results: return
  error instead of nil when no existing cache is available, so the
  watcher calls Fatal rather than spinning IsReady() forever
- Secure temp file handling: use os.CreateTemp for unpredictable names
  (prevents symlink attacks) and clean up temp files on any failure
- Restrict cache file permissions from 0644 to 0600 and cache directory
  from 0755 to 0700 (cache contains user PII)
- Extract atomicWriteFile helper to deduplicate temp+rename pattern
- Fix stale docstring: getCacheTTL default is 24h not 1h

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-14 21:44:44 +02:00
Francis J. Lacoste 6e93a40174 fix: address PR #225 review feedback for SWR cache
- Restore IsReady() polling loop before ServeStdio() to fix cold-start
  regression where tool calls fail for 60-90s on first run (no cache)
- Add fetchUsersMu/fetchChannelsMu mutexes to serialize fetchAndStore*
  calls, preventing race between ForceRefresh and background refresh
- Use atomic file writes (temp + os.Rename) to prevent corrupt cache
  files on crash
- Guard against empty API results overwriting valid cache
- Guard against empty cache files being treated as valid data
- Fix typo: TestRefreshingFlagPreventsConucrrentRefreshes → Concurrent

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-14 21:44:44 +02:00
Francis J. Lacoste f16fb0fe2b feat: stale-while-revalidate cache for large Slack workspaces
On large workspaces (41K+ users), the server blocks for ~90 seconds
during startup while fetching all users/channels from the Slack API,
exceeding MCP client connection timeouts.

Changes:
- Load expired cache files immediately, mark server ready, then refresh
  in background via goroutine (stale-while-revalidate pattern)
- Convert usersReady/channelsReady to atomic.Bool for race-free reads
- Add refreshingUsers/refreshingChannels atomic.Bool to coalesce
  concurrent background refreshes via CompareAndSwap
- Remove stdio IsReady() polling loop (no longer needed)
- Increase default cache TTL from 1h to 24h
- Document SLACK_MCP_CACHE_TTL and SLACK_MCP_MIN_REFRESH_INTERVAL
  env vars in docs/03-configuration-and-usage.md

Fixes startup timeout on large workspaces. Server now starts in under
1 second regardless of workspace size when a cache file exists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-14 21:44:44 +02:00
tim-watcha d3f7ca3a4a fix: include attachment TitleLink in message text output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-14 21:34:18 +02:00
tim-watcha d9213df8f9 fix: include attachment Fields in message text output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-14 21:34:17 +02:00
Greg Katz 2d19f8c752 Add targeted user cache patch on miss
When a user ID is not in the in-memory cache, message rendering
degrades to raw IDs and paramFormatUser fails the tool call
entirely. This is common on Enterprise Grid workspaces where the
user cache (50K+ users) can be hours stale.

On cache miss, fetch the single user via users.info and patch the
snapshot atomically. This costs one API call instead of rebuilding
the entire user cache. Disk persistence is skipped; the next full
refresh cycle handles it.

Fixes #268

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-14 12:03:17 -07:00
Dmitrii Korotovskii 29a73b191a Merge pull request #294 from arnstarn/feat/blocks-and-dep-bump
feat: add blocks parameter and bump slack-go-util to v0.4.0
2026-05-14 21:03:14 +02:00
Dmitrii Korotovskii 5cb7c2c12c Merge pull request #190 from derodero24/feat/extract-block-kit-text
feat: extract text content from message blocks in conversations_history
2026-05-14 21:02:19 +02:00
Dmitrii Korotovskii 9e9f84cfba Merge pull request #219 from georgebashi/feat/conversations-join-leave
feat: add conversations_join and conversations_leave tools
2026-05-14 20:47:36 +02:00
Dmitrii Korotovskii 5e72c6bb91 Merge pull request #263 from Christian-Sidak/feat/users-search-by-id
feat: support direct user ID lookup in users_search
2026-05-14 20:47:31 +02:00
Dmitrii Korotovskii 262f0bc78e Merge pull request #279 from bkbaheti/fix/include-file-names-in-attachment-ids
Include file names in AttachmentIDs for message responses
2026-05-14 20:47:26 +02:00
Dmitrii Korotovskii 78005d34da Merge pull request #284 from clwluvw/slack-add-msg
fix: return plain confirmation from conversations_add_message
2026-05-14 20:47:21 +02:00
Dmitrii Korotovskii 5690a6a3ab Merge pull request #297 from aharon-br/master
fix: handle Slack refresh token format (xoxe)
2026-05-14 20:47:17 +02:00
Dmitrii Korotovskii 8c4614ccda Merge pull request #262 from flacoste/fix/search-rate-limit-retry
fix: add rate limiting and retry to SearchContext
2026-05-14 20:46:32 +02:00
Dmitrii Korotovskii d753982209 Merge pull request #265 from tmastny/tim/add-permalink-and-channel-id
Include channel ID and permalink in search results
2026-05-14 20:46:27 +02:00
Dmitrii Korotovskii a91a6183b0 Merge pull request #245 from coolwuu/docs/fix-reaction-attachment-tool-env-vars
docs: fix incorrect env var references for reactions and add missing tool env vars
2026-05-14 20:46:22 +02:00
Dmitrii Korotovskii 23871daa95 Merge pull request #277 from mustafa89/fix/non-blocking-stdio-startup
fix: non-blocking stdio startup and --no-cache flag
2026-05-14 20:46:16 +02:00
Harry Richman a851750aaa Update api.go
re https://github.com/korotovsky/slack-mcp-server/issues/115
2026-05-13 16:25:14 +01:00
Arnold Mendez 090ad2ebcf ci: retrigger integration tests (suspected flaky test)
The conversations_history integration test returned empty messages from
the test workspace. The slack-go API code path is unchanged between
v0.17.3 and v0.19.0 for this operation - likely a transient state.
2026-05-07 10:37:21 -04:00
Arnold Mendez 97b24505c9 feat: add blocks parameter and bump slack-go-util to v0.4.0
Add optional `blocks` parameter to conversations_add_message for raw
Slack Block Kit JSON support (rich_text lists, code blocks, etc.).

When blocks is provided it takes precedence over text/content_type for
message rendering. The text parameter serves as notification fallback.

The blocks argument accepts both a JSON string and a raw JSON array to
accommodate different MCP client serialization behaviors.

Also bumps takara2314/slack-go-util from v0.3.0 to v0.4.0 which adds
nested list support to the existing text/markdown conversion path.
2026-05-07 10:10:53 -04:00