Skip to content

Commit 3bb630c

Browse files
authored
Merge pull request #624 from rusq/mcp-2
mcp: add load_source tool and make archive argument optional
2 parents 0567587 + 1707ef1 commit 3bb630c

File tree

16 files changed

+1028
-195
lines changed

16 files changed

+1028
-195
lines changed

.github/copilot-instructions.md

Lines changed: 164 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,60 @@
55
**Slackdump** is a Go-based tool for archiving Slack workspaces without admin privileges. It can export messages, users, channels, files, and emojis, generating Slack Export archives in Standard or Mattermost formats.
66

77
**Repository**: https://github.com/rusq/slackdump
8-
**Language**: Go 1.24.2
9-
**Main Package**: `github.com/rusq/slackdump/v3`
8+
**Language**: Go 1.25.0
9+
**Main Package**: `github.com/rusq/slackdump/v4`
1010

1111
## Project Structure
1212

1313
```
1414
/
1515
├── cmd/slackdump/ # Main CLI application entry point
16+
│ └── internal/
17+
│ ├── bootstrap/ # Session/client initialisation shared by commands
18+
│ ├── cfg/ # Global CLI flags and config struct
19+
│ ├── archive/ # archive subcommand
20+
│ ├── convertcmd/ # convert subcommand
21+
│ ├── diag/ # diagnostics subcommand
22+
│ ├── dump/ # dump subcommand
23+
│ ├── emoji/ # emoji subcommand
24+
│ ├── export/ # export subcommand
25+
│ ├── format/ # output format helpers (CLI layer)
26+
│ ├── golang/ # custom CLI framework (based on Go's own cmd/)
27+
│ ├── list/ # list subcommand
28+
│ ├── man/ # built-in help/man pages
29+
│ ├── mcp/ # mcp subcommand (CLI glue only)
30+
│ ├── resume/ # resume subcommand
31+
│ ├── ui/ # TUI components (Bubble Tea)
32+
│ ├── view/ # view subcommand
33+
│ ├── wizard/ # interactive wizard
34+
│ └── workspace/ # workspace management subcommand
1635
├── auth/ # Authentication providers and methods
1736
├── internal/ # Internal packages (not for public API)
18-
│ ├── cache/ # User and channel caching
19-
│ ├── chunk/ # Data chunking and streaming
20-
│ ├── client/ # Slack API client wrapper
21-
│ ├── convert/ # Format conversion (archive, export, dump)
22-
│ ├── edge/ # Edge API client
23-
│ ├── network/ # Network layer with retry logic
24-
│ ├── structures/ # Slack data type parsing
25-
│ └── viewer/ # Built-in export viewer
26-
├── source/ # Data source abstractions
37+
│ ├── cache/ # Credential and workspace caching
38+
│ ├── chunk/ # Data chunking and streaming
39+
│ ├── client/ # Slack API client wrapper
40+
│ ├── convert/ # Format conversion (archive, export, dump)
41+
│ ├── edge/ # Edge API client
42+
│ ├── fasttime/ # Fast time parsing utilities
43+
│ ├── fixtures/ # Test fixture helpers
44+
│ ├── format/ # Internal formatting utilities
45+
│ ├── mcp/ # MCP server business logic (no CLI deps)
46+
│ ├── mocks/ # Shared mocks (auth, cache, io, os)
47+
│ ├── nametmpl/ # Filename template engine
48+
│ ├── network/ # Network layer with retry logic
49+
│ ├── osext/ # OS-level utilities
50+
│ ├── primitive/ # Generic primitives
51+
│ ├── redownload/ # Re-download logic for missing files
52+
│ ├── structures/ # Slack data type parsing and helpers
53+
│ ├── testutil/ # Shared test utilities
54+
│ └── viewer/ # Built-in export viewer (HTTP, chi router)
55+
├── source/ # Data source abstractions (Sourcer, Resumer, etc.)
2756
├── stream/ # Streaming API for large datasets
2857
├── types/ # Public API types
2958
├── export/ # Export format handling
30-
├── downloader/ # File download functionality
31-
└── processor/ # Message processors
59+
├── downloader/ # File download functionality
60+
├── mocks/ # Top-level shared mocks (processor, downloader)
61+
└── processor/ # Message processors
3262
```
3363

3464
## Build and Test
@@ -73,18 +103,18 @@ go generate ./...
73103

74104
### Naming Conventions
75105
- **Packages**: Short, lowercase, no underscores (e.g., `network`, `chunk`, `auth`)
76-
- **Interfaces**: Often suffixed with `er` (e.g., `SlackClienter`, `sourcer`)
106+
- **Interfaces**: Often suffixed with `er` (e.g., `SlackClienter`, `Sourcer`)
77107
- **Files**: Group related functionality (e.g., `channels.go`, `users.go`, `messages.go`)
78108

79109
### Code Style
80-
- **Comments**: Top-level package files start with `// In this file: <description>`
81-
- **Function comments**: Follow Go doc conventions - start with function name
110+
- **Comments**: Top-level package files often start with `// In this file: <description>`
111+
- **Function comments**: Follow Go doc conventions start with function name
82112
- **Unexported helpers**: Prefer short, descriptive names
83113
- **Line length**: No strict limit, but keep reasonable (~100-120 chars)
84114

85115
### Testing
86116
- **Test files**: Use `_test.go` suffix, same package or `_test` package
87-
- **Mocks**: Generated with `go:generate mockgen`, stored alongside or in `mocks_test.go`
117+
- **Mocks**: Generated with `go:generate mockgen` (`go.uber.org/mock/mockgen`), stored in `mock_<pkg>/` subdirectories alongside the source
88118
- **Table-driven tests**: Common pattern for multiple test cases
89119
- **Coverage**: Aim for good coverage on public API and critical paths
90120

@@ -93,15 +123,18 @@ go generate ./...
93123
### Key Libraries
94124
- **Slack API**: `github.com/rusq/slack` (fork of slack-go/slack)
95125
- **Authentication**: `github.com/rusq/slackauth`
126+
- **Browser automation**: `github.com/go-rod/rod` (primary); `github.com/playwright-community/playwright-go` (deprecated, kept for compatibility)
96127
- **CLI/TUI**: `github.com/charmbracelet/bubbletea`, `huh`, `lipgloss`, `bubbles`
128+
- **HTTP routing**: `github.com/go-chi/chi/v5` (used in the built-in viewer)
129+
- **Filesystem adapter**: `github.com/rusq/fsadapter`
97130
- **Database**: `modernc.org/sqlite` (for archive format)
98131
- **Network**: `golang.org/x/time/rate` for rate limiting
132+
- **MCP**: `github.com/mark3labs/mcp-go`
99133
- **Testing**: `github.com/stretchr/testify`, `go.uber.org/mock`
100134

101135
### Module Versioning
102-
- Current version: v3.x
103-
- Import path: `github.com/rusq/slackdump/v3`
104-
- v3.1.2 is retracted (broken build)
136+
- Current version: v4.x
137+
- Import path: `github.com/rusq/slackdump/v4`
105138

106139
## API Design
107140

@@ -112,7 +145,7 @@ go generate ./...
112145
- **Streaming**: Prefer streaming APIs for large datasets (e.g., `StreamChannels`)
113146

114147
### Internal packages
115-
- NOT part of public API - can change without notice
148+
- NOT part of public API can change without notice
116149
- Use for implementation details, utilities, and CLI-specific code
117150
- Keep internal packages focused and single-purpose
118151

@@ -132,17 +165,17 @@ go generate ./...
132165

133166
### Best Practices
134167
- Always use the network package's retry-aware functions
135-
- Don't implement your own retry logic - use `network.WithRetry()`
168+
- Don't implement your own retry logic use `network.WithRetry()`
136169
- Respect Slack's rate limits via `Limits` configuration
137170

138171
## File Organization
139172

140173
### One concept per file
141-
- `channels.go` - channel/conversation operations
142-
- `users.go` - user-related operations
143-
- `messages.go` - message retrieval
144-
- `thread.go` - thread handling
145-
- `config.go` - configuration types
174+
- `channels.go` channel/conversation operations
175+
- `users.go` user-related operations
176+
- `messages.go` message retrieval
177+
- `thread.go` thread handling
178+
- `config.go` configuration types
146179

147180
### Test organization
148181
- Tests in same directory as code
@@ -190,9 +223,10 @@ func (s *Session) StreamChannels(ctx context.Context, chanTypes ...string) (<-ch
190223
## CLI Structure (`cmd/slackdump`)
191224

192225
### Command Organization
193-
- Uses **cobra-like** command structure (custom implementation)
226+
- Uses a **custom command framework** modelled after Go's own `cmd/go` (not Cobra) — see `cmd/slackdump/internal/golang/base/`
227+
- Each subcommand is a `*base.Command` with `Run`, `Wizard`, `UsageLine`, `Short`, `Long`, and a `flag.FlagSet`
194228
- Commands in `cmd/slackdump/internal/`
195-
- Subpackages: `workspace`, `export`, `dump`, `list`, `archive`, `emoji`, `diag`
229+
- Subpackages: `workspace`, `export`, `dump`, `list`, `archive`, `emoji`, `diag`, `mcp`, `view`, `resume`, `convertcmd`
196230

197231
### UI Components
198232
- **TUI**: Bubble Tea based interactive UI (`internal/ui/bubbles/`)
@@ -202,10 +236,11 @@ func (s *Session) StreamChannels(ctx context.Context, chanTypes ...string) (<-ch
202236
## Authentication (`auth/`)
203237

204238
### Supported Methods
205-
1. **EZ-Login 3000**: Automated browser-based login (Playwright/Rod)
206-
2. **Manual token/cookie**: Direct token and cookie input
207-
3. **Environment variables**: `SLACK_TOKEN`, `SLACK_COOKIE`
208-
4. **Value auth**: Programmatic token/cookie provider
239+
1. **Rod browser automation** (`NewRODAuth`) — primary automated login via `go-rod`
240+
2. **Playwright browser automation** (`NewPlaywrightAuth`) — **deprecated**, use Rod instead
241+
3. **Token + cookie file** (`NewCookieFileAuth`) — direct token with a Netscape cookie file
242+
4. **Value auth** (`NewValueAuth`, `NewValueCookiesAuth`) — programmatic token/cookie provider
243+
5. **Environment variables**`SLACK_TOKEN` and `SLACK_COOKIE`
209244

210245
### Provider Interface
211246
```go
@@ -219,10 +254,10 @@ type Provider interface {
219254

220255
## Data Formats
221256

222-
### Archive Format (v3)
257+
### Archive Format (v4)
223258
- SQLite-based storage
224259
- Minimal memory footprint
225-
- Universal structure - can convert to other formats
260+
- Universal structure can convert to other formats
226261
- Default format for all operations
227262

228263
### Export Format
@@ -239,21 +274,107 @@ type Provider interface {
239274

240275
### Token Handling
241276
- Never log tokens or cookies
242-
- Use `structures.RedactTokens()` for sanitization
243-
- Patterns in `internal/structures/structures.go`
277+
- `internal/structures` contains Slack data type helpers — check there for any sanitisation utilities
244278

245279
### Enterprise Workspaces
246280
- May trigger security alerts
247281
- Use `WithForceEnterprise(true)` when needed
248282
- Document in user-facing features
249283

284+
## MCP Server (`internal/mcp`)
285+
286+
The MCP server exposes Slackdump archive data to AI agents via the Model Context Protocol.
287+
288+
### Two-layer architecture
289+
290+
| Layer | Path | Responsibility |
291+
|---|---|---|
292+
| Business logic | `internal/mcp/` | `Server` struct, tools, handlers — no CLI deps |
293+
| CLI glue | `cmd/slackdump/internal/mcp/` | Wires auth/config, calls `internal/mcp.New()` |
294+
295+
### Key types
296+
297+
| Symbol | Location | Notes |
298+
|---|---|---|
299+
| `Server` | `internal/mcp/server.go` | Core server struct |
300+
| `Option` | `internal/mcp/server.go` | `func(*Server)` functional option type |
301+
| `SourceLoader` | `internal/mcp/server.go` | `func(ctx, path) (SourceResumeCloser, error)` |
302+
| `source.SourceResumeCloser` | `source/source.go` | Composite interface: `Sourcer + Resumer + io.Closer` |
303+
| `MockSourceResumeCloser` | `source/mock_source/mock_source.go` | Mock for tests |
304+
305+
### MCP library
306+
307+
Uses `github.com/mark3labs/mcp-go` — imported as `mcplib` (types/tool definitions) and `mcpsrv` (server) in the MCP packages.
308+
309+
### `New()` — functional options pattern
310+
311+
```go
312+
// All options are optional; src may be nil at startup.
313+
srv := mcp.New(
314+
mcp.WithSource(src), // open a source immediately
315+
mcp.WithLogger(lg), // custom slog.Logger
316+
mcp.WithSourceLoader(fn), // override how load_source opens archives
317+
)
318+
```
319+
320+
If `WithSource` is not provided, the server starts with `src == nil`. Every data tool returns a helpful error directing the agent to call `load_source` first.
321+
322+
### Thread safety
323+
324+
`Server.src` is guarded by `sync.RWMutex`:
325+
- **Read lock** — all tool handlers call `s.source()` (the read-locked getter).
326+
- **Write lock**`s.loadSource()` closes the old source then swaps in the new one.
327+
328+
`loadSource()` always swaps even if `Close()` on the old source returns an error (the error is logged as WARN).
329+
330+
### `load_source` tool
331+
332+
Registered as the first tool in `tools()`. Takes a single `path` string argument (filesystem path to a Slackdump archive). On success it logs the archive type and returns a human-readable summary.
333+
334+
### Adding a new MCP tool
335+
336+
1. Add a `toolXxx() mcplib.Tool` method and `handleXxx()` handler method to `tools.go`.
337+
2. Call `s.source()` at the top of the handler; return `resultErr(errNoSource)` if nil.
338+
3. Register the tool by appending `s.toolXxx()` in the `tools()` slice in `server.go`.
339+
4. Add tests in `tools_test.go` — use `newTestServer()` which returns `(*Server, *mock_source.MockSourceResumeCloser)`.
340+
341+
### Mock generation
342+
343+
`source/source.go` has:
344+
```go
345+
//go:generate mockgen -destination=mock_source/mock_source.go . Sourcer,Resumer,Storage,SourceResumeCloser
346+
```
347+
348+
After changing interfaces in `source/source.go`, regenerate with:
349+
```bash
350+
go generate ./source/...
351+
```
352+
353+
The LSP index may lag behind after regeneration — use `go build ./...` to verify there are no real compile errors.
354+
250355
## Documentation
251356

252357
### User Documentation
253358
- RST format in `doc/` directory
254359
- Built-in help via `slackdump help <topic>`
255360
- Man page: `slackdump.1`
256361

362+
### Command help pages
363+
Each CLI subcommand has a Markdown help page embedded at compile time via
364+
`//go:embed`. The convention is:
365+
366+
```
367+
cmd/slackdump/internal/<command>/assets/<command>.md
368+
```
369+
370+
For example: `cmd/slackdump/internal/mcp/assets/mcp.md`
371+
372+
The Markdown file is assigned to the `Long` field of the `*base.Command`
373+
struct, which is what `slackdump help <command>` prints. When adding or
374+
modifying a subcommand, keep its `.md` file in sync with the actual flags,
375+
arguments, and behaviour. The `## Flags` section at the bottom of each help
376+
page should list every flag registered on `cmd.Flag`.
377+
257378
### Code Documentation
258379
- GoDoc comments on all exported types/functions
259380
- Package docs at top of main file
@@ -285,18 +406,18 @@ type Provider interface {
285406

286407
### Adding a new CLI command
287408
1. Create package in `cmd/slackdump/internal/`
288-
2. Implement command logic
409+
2. Implement `*base.Command` with `Run`, `UsageLine`, `Short`, `Long`
289410
3. Wire up in main command router
290411
4. Add help text and documentation
291412

292413
### Modifying internal packages
293-
- Safe to change - not part of public API
414+
- Safe to change not part of public API
294415
- Ensure no unintended dependencies from public API
295416
- Update tests
296417

297418
### Working with tests
298419
- Use `testify/assert` and `testify/require` for assertions
299-
- Mock external dependencies with `mockgen`
420+
- Mock external dependencies with `go.uber.org/mock/mockgen`
300421
- Use `testutil` helpers when available
301422

302423
## Additional Notes
@@ -310,7 +431,7 @@ type Provider interface {
310431
## Troubleshooting
311432

312433
### Common Issues
313-
- **invalid_auth error**: Re-authenticate with `slackdump workspace new`
434+
- **invalid_auth error**: Re-authenticate via `slackdump workspace new`
314435
- **Rate limits**: Adjust limits via `WithLimits()` option
315436
- **Free workspace limitations**: Cannot access data older than 90 days (Slack API limitation)
316437

@@ -321,5 +442,5 @@ type Provider interface {
321442

322443
---
323444

324-
**Last Updated**: 2026-01-29
325-
**For**: Slackdump v3.x
445+
**Last Updated**: 2026-02-25
446+
**For**: Slackdump v4.x

.github/workflows/go.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ jobs:
1111
build:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- uses: actions/checkout@v4
14+
- uses: actions/checkout@v6
1515

1616
- name: Set up Go
17-
uses: actions/setup-go@v5
17+
uses: actions/setup-go@v6
1818
with:
1919
go-version: "1.25"
2020

@@ -31,10 +31,10 @@ jobs:
3131
build-windows:
3232
runs-on: windows-latest
3333
steps:
34-
- uses: actions/checkout@v4
34+
- uses: actions/checkout@v6
3535

3636
- name: Set up Go
37-
uses: actions/setup-go@v5
37+
uses: actions/setup-go@v6
3838
with:
3939
go-version: "1.25"
4040

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ jobs:
1212
goreleaser:
1313
runs-on: ubuntu-latest
1414
steps:
15-
- uses: actions/checkout@v4
15+
- uses: actions/checkout@v6
1616
with:
1717
fetch-depth: 0
1818
- run: git fetch --force --tags
19-
- uses: actions/setup-go@v5
19+
- uses: actions/setup-go@v6
2020
with:
2121
go-version: '>=1.25.0'
2222
cache: true

.github/workflows/shellcheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818

1919
steps:
2020
- name: Checkout
21-
uses: actions/checkout@v4
21+
uses: actions/checkout@v6
2222
- name: Codespell
2323
uses: codespell-project/actions-codespell@v2
2424
- name: Install dependencies

0 commit comments

Comments
 (0)