@prmichaelsen/acp-mcp 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,191 @@
1
+ # Task 7: Implement Progress Streaming in Execute Command
2
+
3
+ **Milestone**: M4 - Progress Streaming - Server Implementation
4
+ **Estimated Time**: 4-5 hours
5
+ **Dependencies**: Task 6 (SSH stream execution)
6
+ **Status**: Not Started
7
+ **Priority**: High
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Update `acp_remote_execute_command` tool to support progress streaming when client provides a `progressToken`. Implement graceful fallback to timeout mode when no progress token is provided.
14
+
15
+ ## Context
16
+
17
+ **Design Reference**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
18
+
19
+ **Current State**: Tool uses `execWithTimeout()` and returns all output at once
20
+
21
+ **Desired State**: Tool detects `progressToken`, streams output with progress notifications, maintains backward compatibility
22
+
23
+ ---
24
+
25
+ ## Steps
26
+
27
+ ### 1. Update Handler Signature
28
+
29
+ **File**: `src/tools/acp-remote-execute-command.ts`
30
+
31
+ **Actions**:
32
+ - Add `extra?: { progressToken?: string | number }` parameter
33
+ - Import server instance for sending notifications
34
+ - Add type definitions for progress params
35
+
36
+ ### 2. Add Progress Detection Logic
37
+
38
+ **Actions**:
39
+ - Check if `extra?.progressToken` exists
40
+ - If yes: call `executeWithProgress()`
41
+ - If no: use existing `execWithTimeout()` (fallback)
42
+
43
+ ### 3. Implement executeWithProgress() Function
44
+
45
+ **Actions**:
46
+ - Call `sshConnection.execStream()`
47
+ - Set up stdout data handler
48
+ - Send progress notification for each chunk
49
+ - Collect full output for final result
50
+ - Handle stderr separately (no progress)
51
+ - Wait for exit code
52
+ - Return structured result
53
+
54
+ **Code Pattern**:
55
+ ```typescript
56
+ async function executeWithProgress(
57
+ command: string,
58
+ cwd: string | undefined,
59
+ sshConnection: SSHConnectionManager,
60
+ progressToken: string | number
61
+ ): Promise<{ content: Array<{ type: string; text: string }> }> {
62
+ const { stream, stderr: stderrStream, exitCode } = await sshConnection.execStream(command, cwd);
63
+
64
+ let stdout = '';
65
+ let stderr = '';
66
+ let bytesReceived = 0;
67
+
68
+ stream.on('data', (chunk: Buffer) => {
69
+ const text = chunk.toString();
70
+ stdout += text;
71
+ bytesReceived += chunk.length;
72
+
73
+ // Send progress notification
74
+ server.notification({
75
+ method: 'notifications/progress',
76
+ params: {
77
+ progressToken,
78
+ progress: bytesReceived,
79
+ total: undefined,
80
+ message: text,
81
+ },
82
+ });
83
+ });
84
+
85
+ stderrStream.on('data', (chunk: Buffer) => {
86
+ stderr += chunk.toString();
87
+ });
88
+
89
+ const finalExitCode = await exitCode;
90
+
91
+ return {
92
+ content: [{
93
+ type: 'text',
94
+ text: JSON.stringify({
95
+ stdout,
96
+ stderr,
97
+ exitCode: finalExitCode,
98
+ timedOut: false,
99
+ streamed: true,
100
+ }, null, 2),
101
+ }],
102
+ };
103
+ }
104
+ ```
105
+
106
+ ### 4. Add Rate Limiting
107
+
108
+ **Actions**:
109
+ - Limit progress notifications to max 10/second
110
+ - Batch small chunks
111
+ - Track last notification time
112
+ - Only send if enough time elapsed
113
+
114
+ **Code Pattern**:
115
+ ```typescript
116
+ let lastProgressTime = 0;
117
+ const MIN_PROGRESS_INTERVAL = 100; // 100ms
118
+
119
+ stream.on('data', (chunk: Buffer) => {
120
+ stdout += chunk.toString();
121
+ bytesReceived += chunk.length;
122
+
123
+ const now = Date.now();
124
+ if (now - lastProgressTime >= MIN_PROGRESS_INTERVAL) {
125
+ server.notification({ /* ... */ });
126
+ lastProgressTime = now;
127
+ }
128
+ });
129
+ ```
130
+
131
+ ### 5. Add Error Handling
132
+
133
+ **Actions**:
134
+ - Handle stream errors
135
+ - Handle connection loss
136
+ - Send error via progress notification
137
+ - Return error in final result
138
+
139
+ ### 6. Update Tool Schema
140
+
141
+ **Actions**:
142
+ - Update description to mention progress support
143
+ - Note that timeout is ignored when streaming
144
+ - Add examples of progress usage
145
+
146
+ ### 7. Test Implementation
147
+
148
+ **Actions**:
149
+ - Build project
150
+ - Test with progressToken (streaming mode)
151
+ - Test without progressToken (fallback mode)
152
+ - Test with long-running command
153
+ - Test with command that fails
154
+ - Test error scenarios
155
+
156
+ ---
157
+
158
+ ## Verification
159
+
160
+ - [ ] Handler accepts `extra` parameter
161
+ - [ ] Detects `progressToken` correctly
162
+ - [ ] Calls `executeWithProgress()` when token provided
163
+ - [ ] Falls back to `execWithTimeout()` when no token
164
+ - [ ] Sends progress notifications for stdout chunks
165
+ - [ ] Rate limiting prevents notification spam
166
+ - [ ] Collects full output for final result
167
+ - [ ] Handles errors gracefully
168
+ - [ ] TypeScript compiles without errors
169
+ - [ ] Build completes successfully
170
+ - [ ] Both modes tested and working
171
+
172
+ ---
173
+
174
+ ## Expected Output
175
+
176
+ ### Files Modified
177
+ - `src/tools/acp-remote-execute-command.ts` - Progress streaming implementation
178
+
179
+ ### New Function
180
+ ```typescript
181
+ async function executeWithProgress(
182
+ command: string,
183
+ cwd: string | undefined,
184
+ sshConnection: SSHConnectionManager,
185
+ progressToken: string | number
186
+ ): Promise<{ content: Array<{ type: string; text: string }> }>
187
+ ```
188
+
189
+ ---
190
+
191
+ **Next Task**: [Task 8: Update Server Request Handlers](task-8-update-server-handlers.md)
@@ -0,0 +1,109 @@
1
+ # Task 8: Update Server Request Handlers
2
+
3
+ **Milestone**: M4 - Progress Streaming - Server Implementation
4
+ **Estimated Time**: 1-2 hours
5
+ **Dependencies**: Task 7 (Progress streaming implementation)
6
+ **Status**: Not Started
7
+ **Priority**: Medium
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Update server request handlers in both `server.ts` and `server-factory.ts` to pass the `extra` parameter (containing `progressToken`) to tool handlers.
14
+
15
+ ## Context
16
+
17
+ **Design Reference**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
18
+
19
+ **Current State**: Handlers don't pass `extra` parameter to tools
20
+
21
+ **Desired State**: Handlers pass `extra` to `acp_remote_execute_command` handler
22
+
23
+ ---
24
+
25
+ ## Steps
26
+
27
+ ### 1. Update server.ts Handler
28
+
29
+ **File**: `src/server.ts`
30
+
31
+ **Actions**:
32
+ - Modify `CallToolRequestSchema` handler signature to accept `extra` parameter
33
+ - Pass `extra` to `handleAcpRemoteExecuteCommand()`
34
+ - Keep other tool handlers unchanged (they don't need progress)
35
+
36
+ **Code Pattern**:
37
+ ```typescript
38
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
39
+ const startTime = Date.now();
40
+ logger.toolInvoked(request.params.name, request.params.arguments);
41
+
42
+ try {
43
+ let result;
44
+
45
+ if (request.params.name === 'acp_remote_execute_command') {
46
+ result = await handleAcpRemoteExecuteCommand(
47
+ request.params.arguments,
48
+ sshConnection,
49
+ extra // Pass extra with progressToken
50
+ );
51
+ } else if (request.params.name === 'acp_remote_list_files') {
52
+ result = await handleAcpRemoteListFiles(request.params.arguments, sshConnection);
53
+ }
54
+ // ... other tools
55
+
56
+ return result;
57
+ } catch (error) {
58
+ logger.toolFailed(request.params.name, error as Error, request.params.arguments);
59
+ throw error;
60
+ }
61
+ });
62
+ ```
63
+
64
+ ### 2. Update server-factory.ts Handler
65
+
66
+ **File**: `src/server-factory.ts`
67
+
68
+ **Actions**:
69
+ - Same changes as server.ts
70
+ - Ensure consistency between both files
71
+
72
+ ### 3. Verify No Breaking Changes
73
+
74
+ **Actions**:
75
+ - Confirm other tools still work
76
+ - Verify `extra` parameter is optional
77
+ - Test that undefined `extra` doesn't break anything
78
+
79
+ ### 4. Test Both Server Modes
80
+
81
+ **Actions**:
82
+ - Build project
83
+ - Test standalone server (server.ts)
84
+ - Test factory server (server-factory.ts)
85
+ - Verify both pass `extra` correctly
86
+
87
+ ---
88
+
89
+ ## Verification
90
+
91
+ - [ ] server.ts handler updated
92
+ - [ ] server-factory.ts handler updated
93
+ - [ ] `extra` parameter passed to execute_command handler
94
+ - [ ] Other tools unaffected
95
+ - [ ] TypeScript compiles without errors
96
+ - [ ] Build completes successfully
97
+ - [ ] Both server modes tested
98
+
99
+ ---
100
+
101
+ ## Expected Output
102
+
103
+ ### Files Modified
104
+ - `src/server.ts` - Pass `extra` to handler
105
+ - `src/server-factory.ts` - Pass `extra` to handler
106
+
107
+ ---
108
+
109
+ **Next Task**: [Task 9: Testing and Documentation](task-9-testing-documentation.md)
@@ -0,0 +1,192 @@
1
+ # Task 9: Testing and Documentation
2
+
3
+ **Milestone**: M4 - Progress Streaming - Server Implementation
4
+ **Estimated Time**: 3-4 hours
5
+ **Dependencies**: Tasks 6, 7, 8 (All implementation complete)
6
+ **Status**: Not Started
7
+ **Priority**: High
8
+
9
+ ---
10
+
11
+ ## Objective
12
+
13
+ Add comprehensive tests for progress streaming functionality and update all documentation for v0.7.0 release.
14
+
15
+ ## Context
16
+
17
+ **Design Reference**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
18
+
19
+ **Current State**: Implementation complete, needs testing and documentation
20
+
21
+ **Desired State**: Full test coverage, updated documentation, ready for v0.7.0 release
22
+
23
+ ---
24
+
25
+ ## Steps
26
+
27
+ ### 1. Write Unit Tests
28
+
29
+ **File**: Create `src/utils/ssh-connection.test.ts` (if doesn't exist)
30
+
31
+ **Actions**:
32
+ - Test `execStream()` returns correct types
33
+ - Test stream emits data events
34
+ - Test exit code promise resolves
35
+ - Test error handling
36
+ - Mock SSH client for tests
37
+
38
+ ### 2. Write Integration Tests
39
+
40
+ **File**: Create `src/tools/acp-remote-execute-command.test.ts`
41
+
42
+ **Actions**:
43
+ - Test with `progressToken` (streaming mode)
44
+ - Test without `progressToken` (fallback mode)
45
+ - Test progress notifications are sent
46
+ - Test rate limiting works
47
+ - Test error scenarios
48
+ - Use real SSH connection (or mock)
49
+
50
+ ### 3. Manual Testing
51
+
52
+ **Actions**:
53
+ - Test with simple command: `echo "test"`
54
+ - Test with long command: `for i in 1 2 3 4 5; do echo "Line $i"; sleep 0.5; done`
55
+ - Test with failing command
56
+ - Test with very long output
57
+ - Test connection loss scenario
58
+
59
+ ### 4. Update README.md
60
+
61
+ **File**: `README.md`
62
+
63
+ **Actions**:
64
+ - Add section on progress streaming support
65
+ - Document that progress requires MCP SDK v1.26.0+
66
+ - Add examples of progress usage
67
+ - Note client requirements
68
+ - Update tool description for `acp_remote_execute_command`
69
+
70
+ **Example Addition**:
71
+ ```markdown
72
+ ### Progress Streaming (v0.7.0+)
73
+
74
+ `acp_remote_execute_command` supports real-time progress streaming for long-running commands. When a client provides a `progressToken`, the tool will send progress notifications with live output.
75
+
76
+ **Requirements**:
77
+ - MCP SDK v1.26.0+ (server and client)
78
+ - Client must provide `progressToken` in request
79
+ - Client must handle `onprogress` callback
80
+
81
+ **Example** (client-side):
82
+ \`\`\`typescript
83
+ const result = await client.request({
84
+ method: 'tools/call',
85
+ params: {
86
+ name: 'acp_remote_execute_command',
87
+ arguments: { command: 'npm run build' }
88
+ }
89
+ }, {
90
+ progressToken: 'build-123',
91
+ onprogress: (progress) => {
92
+ console.log(progress.message); // Live output
93
+ }
94
+ });
95
+ \`\`\`
96
+
97
+ **Fallback**: If no `progressToken` provided, uses timeout-based execution (backward compatible).
98
+ ```
99
+
100
+ ### 5. Update CHANGELOG.md
101
+
102
+ **File**: `CHANGELOG.md`
103
+
104
+ **Actions**:
105
+ - Add v0.7.0 section
106
+ - Document progress streaming feature
107
+ - Note backward compatibility
108
+ - List all changes
109
+
110
+ **Example Entry**:
111
+ ```markdown
112
+ ## [0.7.0] - 2026-02-24
113
+
114
+ ### Added
115
+ - **Progress Streaming** for `acp_remote_execute_command` tool
116
+ - Real-time output streaming for long-running commands
117
+ - Uses MCP SDK's native progress notification system
118
+ - Graceful fallback to timeout mode for clients without progress support
119
+ - Rate limiting prevents notification spam (max 10/second)
120
+ - Supports commands like `npm run build`, `npm run dev`, `npm test`
121
+
122
+ ### Changed
123
+ - `acp_remote_execute_command` now accepts optional `progressToken` parameter
124
+ - Added `execStream()` method to SSHConnectionManager
125
+ - Server handlers now pass `extra` parameter to tool handlers
126
+
127
+ ### Technical Details
128
+ - Requires MCP SDK v1.26.0+ for progress support
129
+ - Progress notifications sent via `notifications/progress` method
130
+ - Backward compatible - existing clients unaffected
131
+ - No breaking changes to API
132
+ ```
133
+
134
+ ### 6. Update package.json
135
+
136
+ **File**: `package.json`
137
+
138
+ **Actions**:
139
+ - Bump version to 0.7.0
140
+ - Verify dependencies are correct
141
+
142
+ ### 7. Build and Verify
143
+
144
+ **Actions**:
145
+ - Run `npm run build`
146
+ - Verify TypeScript compiles
147
+ - Run tests: `npm test`
148
+ - Verify all tests pass
149
+ - Check for any warnings
150
+
151
+ ---
152
+
153
+ ## Verification
154
+
155
+ - [ ] Unit tests written and passing
156
+ - [ ] Integration tests written and passing
157
+ - [ ] Manual testing completed successfully
158
+ - [ ] README.md updated with progress documentation
159
+ - [ ] CHANGELOG.md updated for v0.7.0
160
+ - [ ] package.json version bumped to 0.7.0
161
+ - [ ] TypeScript compiles without errors
162
+ - [ ] Build completes successfully
163
+ - [ ] All tests pass
164
+ - [ ] No warnings or errors
165
+
166
+ ---
167
+
168
+ ## Expected Output
169
+
170
+ ### Files Created
171
+ - `src/utils/ssh-connection.test.ts` - Unit tests (if doesn't exist)
172
+ - `src/tools/acp-remote-execute-command.test.ts` - Integration tests (if doesn't exist)
173
+
174
+ ### Files Modified
175
+ - `README.md` - Progress streaming documentation
176
+ - `CHANGELOG.md` - v0.7.0 entry
177
+ - `package.json` - Version bump to 0.7.0
178
+
179
+ ### Test Results
180
+ ```
181
+ ✓ SSH stream execution tests (5 passed)
182
+ ✓ Progress streaming tests (8 passed)
183
+ ✓ Fallback mode tests (3 passed)
184
+ ✓ Error handling tests (4 passed)
185
+
186
+ Total: 20 tests passed
187
+ ```
188
+
189
+ ---
190
+
191
+ **Next Milestone**: M5 - Progress Streaming - Wrapper Integration (mcp-auth)
192
+ **Related Design**: [`agent/design/local.progress-streaming.md`](../../design/local.progress-streaming.md)
@@ -0,0 +1,170 @@
1
+ # Task 5: Fix Incomplete Directory Listings (GitHub Issue #2)
2
+
3
+ **Milestone**: M3 - Bug Fixes and Enhancements
4
+ **Estimated Time**: 3-4 hours
5
+ **Dependencies**: None
6
+ **Status**: In Progress
7
+ **Priority**: 🚨 CRITICAL
8
+ **GitHub Issue**: [#2](https://github.com/prmichaelsen/acp-mcp/issues/2)
9
+
10
+ ---
11
+
12
+ ## Objective
13
+
14
+ Fix the critical bug where `acp_remote_list_files` returns incomplete directory listings, missing hidden files and directories. Implement comprehensive file listing with full metadata (permissions, timestamps, size, etc.) using a hybrid approach.
15
+
16
+ ## Context
17
+
18
+ **Problem**: SFTP `readdir()` filters out hidden files (starting with `.`) by default, causing incomplete listings.
19
+
20
+ **Root Cause**: SFTP protocol behavior, not a library bug. SFTP `readdir()` excludes hidden files per protocol specification.
21
+
22
+ **Solution**: Use shell `ls` command to get ALL filenames (including hidden), then SFTP `stat()` to get rich metadata for each file.
23
+
24
+ **Design Reference**: See [`agent/reports/github-issue-2-incomplete-directory-listings.md`](../reports/github-issue-2-incomplete-directory-listings.md)
25
+
26
+ ---
27
+
28
+ ## Steps
29
+
30
+ ### 1. Update FileEntry Interface
31
+
32
+ Create comprehensive interface for file metadata.
33
+
34
+ **File**: `src/types/file-entry.ts` (create new)
35
+
36
+ **Actions**:
37
+ - Define `FileEntry` interface with all metadata fields
38
+ - Include permissions, timestamps, size, ownership
39
+ - Export helper functions for permission conversion
40
+
41
+ ### 2. Update SSHConnectionManager.listFiles()
42
+
43
+ Implement hybrid approach: shell + SFTP.
44
+
45
+ **File**: `src/utils/ssh-connection.ts`
46
+
47
+ **Actions**:
48
+ - Add `includeHidden` parameter (default: `true`)
49
+ - Use shell `ls -A` to get all filenames
50
+ - Use SFTP `stat()` to get metadata for each file
51
+ - Return comprehensive `FileEntry[]` with all metadata
52
+ - Add fallback to SFTP `readdir()` if shell fails
53
+ - Add comprehensive logging
54
+
55
+ ### 3. Update Tool Schema
56
+
57
+ Add `includeHidden` parameter to tool.
58
+
59
+ **File**: `src/tools/acp-remote-list-files.ts`
60
+
61
+ **Actions**:
62
+ - Add `includeHidden` to input schema
63
+ - Update tool description
64
+ - Pass parameter to `listFiles()`
65
+ - Update recursive listing to use parameter
66
+
67
+ ### 4. Update Tool Output Format
68
+
69
+ Return structured JSON with metadata.
70
+
71
+ **File**: `src/tools/acp-remote-list-files.ts`
72
+
73
+ **Actions**:
74
+ - Change output from simple text to structured JSON
75
+ - Include all file metadata in response
76
+ - Format for easy parsing by agents
77
+
78
+ ### 5. Update Documentation
79
+
80
+ Document new functionality and parameters.
81
+
82
+ **Files**: `README.md`, `CHANGELOG.md`
83
+
84
+ **Actions**:
85
+ - Document `includeHidden` parameter
86
+ - Document new output format with metadata
87
+ - Add examples of usage
88
+ - Update CHANGELOG for v0.6.0
89
+
90
+ ### 6. Test Implementation
91
+
92
+ Verify fix works correctly.
93
+
94
+ **Actions**:
95
+ - Build project: `npm run build`
96
+ - Test with hidden files directory
97
+ - Verify all files returned
98
+ - Verify metadata is correct
99
+ - Test recursive listing
100
+ - Test with `includeHidden=false`
101
+
102
+ ---
103
+
104
+ ## Verification
105
+
106
+ - [ ] `FileEntry` interface created with all fields
107
+ - [ ] `SSHConnectionManager.listFiles()` updated with hybrid approach
108
+ - [ ] `includeHidden` parameter added to tool schema
109
+ - [ ] Tool returns structured JSON with metadata
110
+ - [ ] README.md updated with new parameter
111
+ - [ ] CHANGELOG.md updated for v0.6.0
112
+ - [ ] TypeScript compiles without errors
113
+ - [ ] Build completes successfully
114
+ - [ ] Manual testing shows all files including hidden
115
+ - [ ] Metadata fields populated correctly
116
+ - [ ] Recursive listing works with hidden files
117
+ - [ ] Fallback to SFTP works if shell fails
118
+
119
+ ---
120
+
121
+ ## Expected Output
122
+
123
+ ### Files Created
124
+ - `src/types/file-entry.ts` - FileEntry interface and helpers
125
+
126
+ ### Files Modified
127
+ - `src/utils/ssh-connection.ts` - Hybrid listing implementation
128
+ - `src/tools/acp-remote-list-files.ts` - Updated schema and output
129
+ - `README.md` - Documentation updates
130
+ - `CHANGELOG.md` - v0.6.0 entry
131
+ - `package.json` - Version bump to 0.6.0
132
+
133
+ ---
134
+
135
+ ## Implementation Details
136
+
137
+ ### FileEntry Interface
138
+ ```typescript
139
+ export interface FileEntry {
140
+ name: string;
141
+ path: string;
142
+ type: 'file' | 'directory' | 'symlink' | 'other';
143
+ size: number;
144
+ permissions: {
145
+ mode: number;
146
+ string: string;
147
+ owner: { read: boolean; write: boolean; execute: boolean };
148
+ group: { read: boolean; write: boolean; execute: boolean };
149
+ others: { read: boolean; write: boolean; execute: boolean };
150
+ };
151
+ owner: {
152
+ uid: number;
153
+ gid: number;
154
+ };
155
+ timestamps: {
156
+ accessed: string;
157
+ modified: string;
158
+ };
159
+ }
160
+ ```
161
+
162
+ ### Hybrid Approach
163
+ 1. Execute `ls -A -1` to get all filenames (including hidden)
164
+ 2. For each filename, call SFTP `stat()` to get metadata
165
+ 3. Construct `FileEntry` objects with complete information
166
+ 4. Return structured array
167
+
168
+ ---
169
+
170
+ **Next Task**: Task 6 - Deploy v0.6.0 to npm