@brutalist/mcp 0.6.11 → 0.6.13
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.
- package/README.md +122 -154
- package/dist/brutalist-server.d.ts.map +1 -1
- package/dist/brutalist-server.js +70 -52
- package/dist/brutalist-server.js.map +1 -1
- package/dist/cli-agents.d.ts.map +1 -1
- package/dist/cli-agents.js +32 -15
- package/dist/cli-agents.js.map +1 -1
- package/dist/tool-definitions.js +5 -5
- package/dist/tool-definitions.js.map +1 -1
- package/dist/types/tool-config.d.ts +1 -1
- package/dist/types/tool-config.js +1 -1
- package/dist/types/tool-config.js.map +1 -1
- package/dist/utils/pagination.d.ts +9 -3
- package/dist/utils/pagination.d.ts.map +1 -1
- package/dist/utils/pagination.js +39 -20
- package/dist/utils/pagination.js.map +1 -1
- package/dist/utils/response-cache.d.ts +13 -13
- package/dist/utils/response-cache.d.ts.map +1 -1
- package/dist/utils/response-cache.js +43 -43
- package/dist/utils/response-cache.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,59 +1,48 @@
|
|
|
1
|
-
# Brutalist MCP
|
|
1
|
+
# Brutalist MCP
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Multi-perspective code analysis using Claude Code, Codex, and Gemini CLI agents.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Get direct, honest technical feedback on your code, architecture, and ideas before they reach production.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## What It Does
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The Brutalist MCP connects your AI coding assistant to three different CLI agents (Claude, Codex, Gemini), each providing independent analysis. This gives you multiple perspectives on:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
- Code quality and security vulnerabilities
|
|
12
|
+
- Architecture decisions and scalability
|
|
13
|
+
- Product ideas and technical feasibility
|
|
14
|
+
- Research methodology and design flaws
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
Real file-system access. Straightforward analysis. No sugar-coating.
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## Quick Start
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
### Step 1: Install a CLI Agent
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Install at least one CLI agent:
|
|
22
|
-
- **Claude Code**: `npm install -g claude` (or via Claude desktop app)
|
|
23
|
-
- **Codex**: Install from [OpenAI Codex](https://github.com/openai/codex-cli)
|
|
24
|
-
- **Gemini**: `npm install -g @google/gemini-cli` or authenticate via `gemini auth`
|
|
25
|
-
|
|
26
|
-
### Installation
|
|
27
|
-
|
|
28
|
-
<details>
|
|
29
|
-
<summary><strong>Claude Code</strong> — One-liner</summary>
|
|
22
|
+
You need at least one of these installed:
|
|
30
23
|
|
|
31
24
|
```bash
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
</details>
|
|
25
|
+
# Option 1: Claude Code (recommended)
|
|
26
|
+
npm install -g claude
|
|
35
27
|
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
# Option 2: Codex
|
|
29
|
+
# Install from https://github.com/openai/codex-cli
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
# Option 3: Gemini
|
|
32
|
+
npm install -g @google/gemini-cli
|
|
41
33
|
```
|
|
42
|
-
</details>
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
<summary><strong>Gemini CLI</strong> — One-liner</summary>
|
|
35
|
+
### Step 2: Install the MCP Server
|
|
46
36
|
|
|
37
|
+
Choose your IDE:
|
|
38
|
+
|
|
39
|
+
**Claude Code:**
|
|
47
40
|
```bash
|
|
48
|
-
|
|
41
|
+
claude mcp add brutalist --scope user -- npx -y @brutalist/mcp
|
|
49
42
|
```
|
|
50
|
-
</details>
|
|
51
|
-
|
|
52
|
-
<details>
|
|
53
|
-
<summary><strong>Cursor</strong> — Manual config</summary>
|
|
54
|
-
|
|
55
|
-
Add to `~/.cursor/mcp.json` or use **Settings → MCP & Integrations**
|
|
56
43
|
|
|
44
|
+
**Cursor:**
|
|
45
|
+
Add to `~/.cursor/mcp.json`:
|
|
57
46
|
```json
|
|
58
47
|
{
|
|
59
48
|
"brutalist": {
|
|
@@ -62,13 +51,14 @@ Add to `~/.cursor/mcp.json` or use **Settings → MCP & Integrations**
|
|
|
62
51
|
}
|
|
63
52
|
}
|
|
64
53
|
```
|
|
65
|
-
</details>
|
|
66
|
-
|
|
67
|
-
<details>
|
|
68
|
-
<summary><strong>Windsurf</strong> — Manual config</summary>
|
|
69
54
|
|
|
70
|
-
|
|
55
|
+
**VS Code / Cline:**
|
|
56
|
+
```bash
|
|
57
|
+
code --add-mcp '{"name":"brutalist","command":"npx","args":["-y","@brutalist/mcp"]}'
|
|
58
|
+
```
|
|
71
59
|
|
|
60
|
+
**Windsurf:**
|
|
61
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
72
62
|
```json
|
|
73
63
|
{
|
|
74
64
|
"brutalist": {
|
|
@@ -77,187 +67,165 @@ Add to `~/.codeium/windsurf/mcp_config.json` or use **Plugin Store**
|
|
|
77
67
|
}
|
|
78
68
|
}
|
|
79
69
|
```
|
|
80
|
-
</details>
|
|
81
70
|
|
|
82
|
-
|
|
71
|
+
### Step 3: Verify Installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Check which CLI agents are available
|
|
75
|
+
cli_agent_roster()
|
|
76
|
+
```
|
|
83
77
|
|
|
84
|
-
|
|
78
|
+
## Usage Examples
|
|
85
79
|
|
|
86
|
-
|
|
80
|
+
### Analyze Your Codebase
|
|
87
81
|
|
|
88
82
|
```bash
|
|
89
|
-
#
|
|
83
|
+
# Analyze entire project
|
|
90
84
|
roast_codebase "/path/to/your/project"
|
|
91
85
|
|
|
92
|
-
#
|
|
93
|
-
roast_codebase "/src/auth"
|
|
94
|
-
roast_codebase "/src/api/handlers"
|
|
95
|
-
roast_codebase "/components" # React component chaos
|
|
86
|
+
# Analyze specific modules
|
|
87
|
+
roast_codebase "/src/auth"
|
|
88
|
+
roast_codebase "/src/api/handlers"
|
|
96
89
|
```
|
|
97
90
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
### 💡 **Idea Obliteration**
|
|
101
|
-
|
|
102
|
-
> Reality-check your startup dreams, product concepts, and technical decisions.
|
|
91
|
+
### Validate Ideas
|
|
103
92
|
|
|
104
93
|
```bash
|
|
105
|
-
#
|
|
94
|
+
# Evaluate a product concept
|
|
106
95
|
roast_idea "A social network for developers to share code snippets"
|
|
107
96
|
|
|
108
|
-
#
|
|
97
|
+
# Review technical decisions
|
|
109
98
|
roast_idea "Migrating our monolith to microservices with Kubernetes"
|
|
110
|
-
|
|
111
|
-
# Product feature validation
|
|
112
|
-
roast_idea "Adding AI-powered code suggestions to our IDE"
|
|
113
99
|
```
|
|
114
100
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
### 🏗️ **Architecture Annihilation**
|
|
118
|
-
|
|
119
|
-
> Find every scaling bottleneck, cost explosion, and operational nightmare in your system design.
|
|
101
|
+
### Review Architecture
|
|
120
102
|
|
|
121
103
|
```bash
|
|
122
|
-
# System architecture
|
|
104
|
+
# System architecture analysis
|
|
123
105
|
roast_architecture "Microservices with event sourcing and CQRS"
|
|
124
106
|
|
|
125
|
-
# Infrastructure design
|
|
107
|
+
# Infrastructure design review
|
|
126
108
|
roast_architecture """
|
|
127
109
|
API Gateway → Load Balancer → 3 Node.js services → PostgreSQL
|
|
128
110
|
Redis for caching, Docker containers on AWS ECS
|
|
129
111
|
"""
|
|
130
112
|
```
|
|
131
113
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
### 🔒 **Security Demolition**
|
|
135
|
-
|
|
136
|
-
> Expose authentication bypasses, injection vulnerabilities, and data leak opportunities.
|
|
114
|
+
### Security Analysis
|
|
137
115
|
|
|
138
116
|
```bash
|
|
139
|
-
# Authentication
|
|
117
|
+
# Authentication review
|
|
140
118
|
roast_security "JWT tokens with user roles in localStorage"
|
|
141
119
|
|
|
142
|
-
# API security
|
|
120
|
+
# API security check
|
|
143
121
|
roast_security "GraphQL API with dynamic queries and no rate limiting"
|
|
144
122
|
```
|
|
145
123
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
### 🤺 **Multi-Agent Warfare**
|
|
149
|
-
|
|
150
|
-
> Deploy multiple CLI agents in adversarial combat for maximum destruction.
|
|
124
|
+
### Compare Perspectives
|
|
151
125
|
|
|
152
126
|
```bash
|
|
153
|
-
#
|
|
127
|
+
# Get multiple viewpoints on technical decisions
|
|
154
128
|
roast_cli_debate "Should we use TypeScript or Go for this API?"
|
|
155
129
|
|
|
156
|
-
#
|
|
130
|
+
# Compare architecture approaches
|
|
157
131
|
roast_cli_debate "Microservices vs Monolith for our e-commerce platform"
|
|
158
132
|
```
|
|
159
133
|
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
### 🛠️ **Meta Commands**
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
# Check which CLI agents are available
|
|
166
|
-
cli_agent_roster()
|
|
167
|
-
```
|
|
168
|
-
|
|
169
134
|
## How It Works
|
|
170
135
|
|
|
171
|
-
This MCP server
|
|
172
|
-
- **Claude Code CLI** -
|
|
173
|
-
- **Codex CLI** -
|
|
174
|
-
- **Gemini CLI** -
|
|
136
|
+
This MCP server coordinates analysis from locally installed CLI agents:
|
|
137
|
+
- **Claude Code CLI** - Code review and architectural analysis
|
|
138
|
+
- **Codex CLI** - Security and technical implementation review
|
|
139
|
+
- **Gemini CLI** - System design and scalability analysis
|
|
175
140
|
|
|
176
|
-
Each agent runs locally
|
|
141
|
+
Each agent runs locally with direct file-system access, providing independent perspectives on your code and design decisions.
|
|
177
142
|
|
|
178
|
-
|
|
143
|
+
**Analysis time:** Up to 25 minutes for complex projects. Thorough analysis requires time to examine code patterns, dependencies, and architectural decisions.
|
|
179
144
|
|
|
180
|
-
##
|
|
145
|
+
## Pagination for Large Results
|
|
181
146
|
|
|
182
|
-
|
|
147
|
+
For analyses that exceed your IDE's token limit:
|
|
183
148
|
|
|
184
149
|
```bash
|
|
185
|
-
#
|
|
150
|
+
# Set chunk size for large codebases
|
|
186
151
|
roast_codebase({targetPath: "/monorepo", limit: 20000})
|
|
187
152
|
|
|
188
|
-
# Continue
|
|
153
|
+
# Continue from where you left off
|
|
189
154
|
roast_codebase({targetPath: "/monorepo", offset: 20000, limit: 20000})
|
|
190
155
|
|
|
191
|
-
#
|
|
156
|
+
# Use cursor-based navigation
|
|
192
157
|
roast_codebase({targetPath: "/complex-system", cursor: "offset:25000"})
|
|
193
158
|
```
|
|
194
159
|
|
|
195
|
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
-
|
|
160
|
+
Features:
|
|
161
|
+
- Smart boundary detection (preserves paragraphs and sentences)
|
|
162
|
+
- Token estimation (~4 chars = 1 token)
|
|
163
|
+
- Progress indicators
|
|
164
|
+
- Configurable chunk size (1K to 100K characters)
|
|
200
165
|
|
|
201
166
|
## Tools
|
|
202
167
|
|
|
203
|
-
### Code & Architecture
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
|
216
|
-
|
|
217
|
-
| `
|
|
218
|
-
| `
|
|
219
|
-
| `
|
|
220
|
-
| `
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
168
|
+
### Code & Architecture
|
|
169
|
+
|
|
170
|
+
| Tool | Analyzes |
|
|
171
|
+
|------|----------|
|
|
172
|
+
| `roast_codebase` | Security vulnerabilities, performance issues, code quality |
|
|
173
|
+
| `roast_file_structure` | Directory organization, naming conventions, structure |
|
|
174
|
+
| `roast_dependencies` | Version conflicts, security vulnerabilities, compatibility |
|
|
175
|
+
| `roast_git_history` | Commit quality, branching strategy, collaboration patterns |
|
|
176
|
+
| `roast_test_coverage` | Test coverage, quality gaps, testing strategy |
|
|
177
|
+
|
|
178
|
+
### Design & Planning
|
|
179
|
+
|
|
180
|
+
| Tool | Analyzes |
|
|
181
|
+
|------|----------|
|
|
182
|
+
| `roast_idea` | Feasibility, market fit, implementation challenges |
|
|
183
|
+
| `roast_architecture` | Scalability, cost, operational complexity |
|
|
184
|
+
| `roast_research` | Methodology, reproducibility, statistical validity |
|
|
185
|
+
| `roast_security` | Attack vectors, authentication, authorization |
|
|
186
|
+
| `roast_product` | UX, adoption barriers, user needs |
|
|
187
|
+
| `roast_infrastructure` | Reliability, scaling, operational overhead |
|
|
188
|
+
|
|
189
|
+
### Utilities
|
|
190
|
+
|
|
191
|
+
| Tool | Purpose |
|
|
192
|
+
|------|---------|
|
|
193
|
+
| `roast_cli_debate` | Multi-agent discussion from different perspectives |
|
|
194
|
+
| `cli_agent_roster` | Show available CLI agents on your system |
|
|
195
|
+
|
|
196
|
+
## Advanced Usage
|
|
197
|
+
|
|
198
|
+
### Choose Specific CLI Agents
|
|
231
199
|
|
|
232
200
|
```bash
|
|
233
|
-
# Use specific
|
|
201
|
+
# Use a specific agent
|
|
234
202
|
roast_codebase(targetPath="/src", preferredCLI="claude")
|
|
235
203
|
|
|
236
|
-
#
|
|
237
|
-
roast_security "/auth/module" #
|
|
204
|
+
# System automatically selects best agent for task
|
|
205
|
+
roast_security "/auth/module" # Typically uses Codex
|
|
238
206
|
|
|
239
|
-
#
|
|
240
|
-
roast_idea "..." # All available agents
|
|
207
|
+
# Multi-agent analysis (default)
|
|
208
|
+
roast_idea "..." # All available agents provide perspectives
|
|
241
209
|
```
|
|
242
210
|
|
|
243
|
-
###
|
|
244
|
-
|
|
245
|
-
Different CLI agents excel at different analysis types:
|
|
246
|
-
- **Code review**: Claude > Codex > Gemini
|
|
247
|
-
- **Architecture**: Gemini > Claude > Codex
|
|
248
|
-
- **Security**: Codex > Claude > Gemini
|
|
249
|
-
- **Research**: Claude > Gemini > Codex
|
|
211
|
+
### Agent Strengths
|
|
250
212
|
|
|
251
|
-
|
|
213
|
+
Different agents have different strengths:
|
|
214
|
+
- **Code review**: Claude, Codex, Gemini
|
|
215
|
+
- **Architecture**: Gemini, Claude, Codex
|
|
216
|
+
- **Security**: Codex, Claude, Gemini
|
|
217
|
+
- **Research**: Claude, Gemini, Codex
|
|
252
218
|
|
|
253
|
-
|
|
254
|
-
**Solution:** Deploy multiple local CLI agents with adversarial perspectives.
|
|
255
|
-
**Result:** Brutal honesty through systematic destruction before expensive failures.
|
|
219
|
+
## Why Multiple Perspectives
|
|
256
220
|
|
|
257
|
-
|
|
221
|
+
Each CLI agent brings a different approach to analysis:
|
|
222
|
+
- Different training data and focus areas
|
|
223
|
+
- Independent evaluation of the same code
|
|
224
|
+
- Varied perspectives on technical tradeoffs
|
|
258
225
|
|
|
259
|
-
|
|
226
|
+
Getting multiple viewpoints helps identify issues that a single perspective might miss.
|
|
260
227
|
|
|
261
228
|
---
|
|
262
229
|
|
|
263
|
-
|
|
230
|
+
**License:** MIT
|
|
231
|
+
**Issues:** https://github.com/ejmockler/brutalist-mcp/issues
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brutalist-server.d.ts","sourceRoot":"","sources":["../src/brutalist-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,OAAO,EACL,qBAAqB,EAKtB,MAAM,sBAAsB,CAAC;AAc9B,qBAAa,eAAe;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,qBAAqB,CAAC;IACrC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAC,CAAgC;IACtD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAC,CAAa;IAErC,OAAO,CAAC,cAAc,CAIjB;gBAEO,MAAM,GAAE,qBAA0B;IA0C9C,OAAO,CAAC,oBAAoB,CAkE1B;IAEF,OAAO,CAAC,oBAAoB,CAsC1B;IAEI,KAAK;YAeG,gBAAgB;YAMhB,eAAe;IAmItB,aAAa,IAAI,MAAM,GAAG,SAAS;IAKnC,OAAO,IAAI,IAAI;IAOtB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,oBAAoB;IAoG5B;;OAEG;YACW,eAAe;YAuLf,gBAAgB;IAkK9B,OAAO,CAAC,gBAAgB;YA0FV,wBAAwB;IA0FtC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,kBAAkB;
|
|
1
|
+
{"version":3,"file":"brutalist-server.d.ts","sourceRoot":"","sources":["../src/brutalist-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,OAAO,EACL,qBAAqB,EAKtB,MAAM,sBAAsB,CAAC;AAc9B,qBAAa,eAAe;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,MAAM,EAAE,qBAAqB,CAAC;IACrC,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAC,CAAgC;IACtD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAC,CAAa;IAErC,OAAO,CAAC,cAAc,CAIjB;gBAEO,MAAM,GAAE,qBAA0B;IA0C9C,OAAO,CAAC,oBAAoB,CAkE1B;IAEF,OAAO,CAAC,oBAAoB,CAsC1B;IAEI,KAAK;YAeG,gBAAgB;YAMhB,eAAe;IAmItB,aAAa,IAAI,MAAM,GAAG,SAAS;IAKnC,OAAO,IAAI,IAAI;IAOtB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,oBAAoB;IAoG5B;;OAEG;YACW,eAAe;YAuLf,gBAAgB;IAkK9B,OAAO,CAAC,gBAAgB;YA0FV,wBAAwB;IA0FtC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,kBAAkB;IA6F1B,OAAO,CAAC,uBAAuB;IAuH/B,OAAO,CAAC,mBAAmB;YA8Bb,mBAAmB;CAUlC"}
|
package/dist/brutalist-server.js
CHANGED
|
@@ -12,7 +12,7 @@ import { TOOL_CONFIGS } from './tool-definitions.js';
|
|
|
12
12
|
import { extractPaginationParams, parseCursor, PAGINATION_DEFAULTS, ResponseChunker, createPaginationMetadata, formatPaginationStatus, estimateTokenCount } from './utils/pagination.js';
|
|
13
13
|
import { ResponseCache } from './utils/response-cache.js';
|
|
14
14
|
// Use environment variable or fallback to manual version
|
|
15
|
-
const PACKAGE_VERSION = process.env.npm_package_version || "0.
|
|
15
|
+
const PACKAGE_VERSION = process.env.npm_package_version || "0.6.12";
|
|
16
16
|
export class BrutalistServer {
|
|
17
17
|
server;
|
|
18
18
|
config;
|
|
@@ -26,7 +26,7 @@ export class BrutalistServer {
|
|
|
26
26
|
constructor(config = {}) {
|
|
27
27
|
this.config = {
|
|
28
28
|
workingDirectory: process.cwd(),
|
|
29
|
-
defaultTimeout:
|
|
29
|
+
defaultTimeout: 120000, // 2 minutes for testing (configurable via BRUTALIST_TIMEOUT env)
|
|
30
30
|
transport: 'stdio', // Default to stdio for backward compatibility
|
|
31
31
|
httpPort: 3000,
|
|
32
32
|
...config
|
|
@@ -373,9 +373,9 @@ export class BrutalistServer {
|
|
|
373
373
|
roster += "## Pagination Support (NEW in v0.5.2)\n";
|
|
374
374
|
roster += "**All tools now support intelligent pagination:**\n";
|
|
375
375
|
roster += "- Analysis results are cached with 2-hour TTL\n";
|
|
376
|
-
roster += "- Use `
|
|
376
|
+
roster += "- Use `context_id` from response to resume conversation\n";
|
|
377
377
|
roster += "- Smart text chunking preserves readability\n";
|
|
378
|
-
roster += "- Example: `roast_codebase(
|
|
378
|
+
roster += "- Example: `roast_codebase(context_id: 'a3f5c2d8', offset: 25000)`\n\n";
|
|
379
379
|
roster += "## Brutalist Philosophy\n";
|
|
380
380
|
roster += "*All tools use CLI agents with brutal system prompts for maximum reality-based criticism.*\n";
|
|
381
381
|
return {
|
|
@@ -445,13 +445,13 @@ export class BrutalistServer {
|
|
|
445
445
|
const explicitPaginationRequested = args.offset !== undefined ||
|
|
446
446
|
args.limit !== undefined ||
|
|
447
447
|
args.cursor !== undefined ||
|
|
448
|
-
args.
|
|
449
|
-
logger.info(`🔧 DEBUG: explicitPaginationRequested=${explicitPaginationRequested}, offset=${args.offset}, limit=${args.limit}, cursor=${args.cursor},
|
|
450
|
-
// Check cache if
|
|
451
|
-
if (args.
|
|
452
|
-
const cachedContent = await this.responseCache.get(args.
|
|
448
|
+
args.context_id !== undefined;
|
|
449
|
+
logger.info(`🔧 DEBUG: explicitPaginationRequested=${explicitPaginationRequested}, offset=${args.offset}, limit=${args.limit}, cursor=${args.cursor}, context_id=${args.context_id}`);
|
|
450
|
+
// Check cache if context_id provided
|
|
451
|
+
if (args.context_id && !args.force_refresh) {
|
|
452
|
+
const cachedContent = await this.responseCache.get(args.context_id, sessionId);
|
|
453
453
|
if (cachedContent) {
|
|
454
|
-
logger.info(`🎯 Cache HIT for
|
|
454
|
+
logger.info(`🎯 Cache HIT for context_id: ${args.context_id}`);
|
|
455
455
|
const cachedResult = {
|
|
456
456
|
success: true,
|
|
457
457
|
responses: [{
|
|
@@ -461,14 +461,14 @@ export class BrutalistServer {
|
|
|
461
461
|
executionTime: 0
|
|
462
462
|
}]
|
|
463
463
|
};
|
|
464
|
-
return this.formatToolResponse(cachedResult, args.verbose, paginationParams, args.
|
|
464
|
+
return this.formatToolResponse(cachedResult, args.verbose, paginationParams, args.context_id, explicitPaginationRequested);
|
|
465
465
|
}
|
|
466
466
|
else {
|
|
467
|
-
logger.warn(`❌ Cache MISS for
|
|
468
|
-
// Don't silently re-run -
|
|
469
|
-
throw new Error(`
|
|
467
|
+
logger.warn(`❌ Cache MISS for context_id: ${args.context_id}, session: ${sessionId}`);
|
|
468
|
+
// Don't silently re-run - context_id should always hit cache or error
|
|
469
|
+
throw new Error(`Context ID "${args.context_id}" not found in cache. ` +
|
|
470
470
|
`It may have expired (2 hour TTL) or belong to a different session. ` +
|
|
471
|
-
`Remove
|
|
471
|
+
`Remove context_id parameter to run a new analysis.`);
|
|
472
472
|
}
|
|
473
473
|
}
|
|
474
474
|
// Generate cache key for this request
|
|
@@ -482,12 +482,12 @@ export class BrutalistServer {
|
|
|
482
482
|
if (!args.force_refresh) {
|
|
483
483
|
const cachedContent = await this.responseCache.get(cacheKey, sessionId);
|
|
484
484
|
if (cachedContent) {
|
|
485
|
-
// Get existing
|
|
486
|
-
const
|
|
487
|
-
const
|
|
488
|
-
? this.responseCache.createAlias(
|
|
489
|
-
: this.responseCache.
|
|
490
|
-
logger.info(`🎯 Cache hit for new request, using
|
|
485
|
+
// Get existing context_id or create new alias
|
|
486
|
+
const existingContextId = this.responseCache.findContextIdForKey(cacheKey);
|
|
487
|
+
const contextId = existingContextId
|
|
488
|
+
? this.responseCache.createAlias(existingContextId, cacheKey)
|
|
489
|
+
: this.responseCache.generateContextId(cacheKey);
|
|
490
|
+
logger.info(`🎯 Cache hit for new request, using context_id: ${contextId}`);
|
|
491
491
|
const cachedResult = {
|
|
492
492
|
success: true,
|
|
493
493
|
responses: [{
|
|
@@ -497,7 +497,7 @@ export class BrutalistServer {
|
|
|
497
497
|
executionTime: 0
|
|
498
498
|
}]
|
|
499
499
|
};
|
|
500
|
-
return this.formatToolResponse(cachedResult, args.verbose, paginationParams,
|
|
500
|
+
return this.formatToolResponse(cachedResult, args.verbose, paginationParams, contextId, explicitPaginationRequested);
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
503
|
// Build context with custom builder if available
|
|
@@ -509,7 +509,7 @@ export class BrutalistServer {
|
|
|
509
509
|
// Run the analysis
|
|
510
510
|
const result = await this.executeBrutalistAnalysis(config.analysisType, primaryArg, config.systemPrompt, context, args.workingDirectory, args.preferredCLI, args.verbose, args.models, progressToken, sessionId, requestId);
|
|
511
511
|
// Cache the result if successful
|
|
512
|
-
let
|
|
512
|
+
let contextId;
|
|
513
513
|
if (result.success && result.responses.length > 0) {
|
|
514
514
|
const fullContent = this.extractFullContent(result);
|
|
515
515
|
if (fullContent) {
|
|
@@ -519,14 +519,14 @@ export class BrutalistServer {
|
|
|
519
519
|
acc[field] = args[field];
|
|
520
520
|
return acc;
|
|
521
521
|
}, {});
|
|
522
|
-
const {
|
|
523
|
-
requestId //
|
|
522
|
+
const { contextId: newId } = await this.responseCache.set(cacheData, fullContent, cacheKey, sessionId, // Bind to session
|
|
523
|
+
requestId // Track request
|
|
524
524
|
);
|
|
525
|
-
|
|
526
|
-
logger.info(`✅ Cached analysis result with ID: ${
|
|
525
|
+
contextId = newId;
|
|
526
|
+
logger.info(`✅ Cached analysis result with context ID: ${contextId} for session: ${sessionId?.substring(0, 8)}`);
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
|
-
return this.formatToolResponse(result, args.verbose, paginationParams,
|
|
529
|
+
return this.formatToolResponse(result, args.verbose, paginationParams, contextId, explicitPaginationRequested);
|
|
530
530
|
}
|
|
531
531
|
catch (error) {
|
|
532
532
|
return this.formatErrorResponse(error);
|
|
@@ -814,7 +814,7 @@ Remember: You are ${currentAgent.toUpperCase()}, passionate advocate for ${assig
|
|
|
814
814
|
}
|
|
815
815
|
return null;
|
|
816
816
|
}
|
|
817
|
-
formatToolResponse(result, verbose = false, paginationParams,
|
|
817
|
+
formatToolResponse(result, verbose = false, paginationParams, contextId, explicitPaginationRequested = false) {
|
|
818
818
|
logger.info(`🔧 DEBUG: formatToolResponse called with synthesis length: ${result.synthesis?.length || 0}`);
|
|
819
819
|
logger.info(`🔧 DEBUG: result.success=${result.success}, responses.length=${result.responses?.length || 0}`);
|
|
820
820
|
logger.info(`🔧 DEBUG: pagination params:`, paginationParams);
|
|
@@ -836,25 +836,41 @@ Remember: You are ${currentAgent.toUpperCase()}, passionate advocate for ${assig
|
|
|
836
836
|
const estimatedTokens = estimateTokenCount(primaryContent);
|
|
837
837
|
const maxTokensWithoutPagination = 25000;
|
|
838
838
|
const needsAutoPagination = estimatedTokens > maxTokensWithoutPagination;
|
|
839
|
-
//
|
|
840
|
-
//
|
|
841
|
-
|
|
842
|
-
if ((explicitPaginationRequested || needsAutoPagination) && paginationParams && primaryContent) {
|
|
839
|
+
// CRITICAL: Always apply pagination if content is too large, even if not explicitly requested
|
|
840
|
+
// This prevents MCP protocol errors when response exceeds client token limits
|
|
841
|
+
if (needsAutoPagination || explicitPaginationRequested) {
|
|
843
842
|
if (needsAutoPagination && !explicitPaginationRequested) {
|
|
844
|
-
logger.info(`🔧
|
|
843
|
+
logger.info(`🔧 AUTO-PAGINATING: ${estimatedTokens} tokens exceeds ${maxTokensWithoutPagination} limit - forcing first page`);
|
|
844
|
+
// Force pagination params to show first chunk (use token-based limit)
|
|
845
|
+
const forcedParams = {
|
|
846
|
+
offset: 0,
|
|
847
|
+
limit: PAGINATION_DEFAULTS.DEFAULT_LIMIT_TOKENS // Use token-based limit
|
|
848
|
+
};
|
|
849
|
+
return this.formatPaginatedResponse(primaryContent, forcedParams, result, verbose, contextId);
|
|
845
850
|
}
|
|
846
|
-
else {
|
|
851
|
+
else if (paginationParams) {
|
|
847
852
|
logger.info(`🔧 DEBUG: Applying pagination (explicitly requested)`);
|
|
853
|
+
return this.formatPaginatedResponse(primaryContent, paginationParams, result, verbose, contextId);
|
|
848
854
|
}
|
|
849
|
-
return this.formatPaginatedResponse(primaryContent, paginationParams, result, verbose, analysisId);
|
|
850
855
|
}
|
|
851
856
|
// Non-paginated response (only for content that fits within token limit)
|
|
852
857
|
if (primaryContent) {
|
|
853
858
|
logger.info(`🔧 DEBUG: Returning full response (${estimatedTokens} tokens < ${maxTokensWithoutPagination} limit)`);
|
|
859
|
+
// Include context_id even for non-paginated responses (for future pagination/caching)
|
|
860
|
+
let responseText = '';
|
|
861
|
+
if (contextId) {
|
|
862
|
+
responseText += `# Brutalist Analysis Results\n\n`;
|
|
863
|
+
responseText += `**🔑 Context ID:** ${contextId}\n\n`;
|
|
864
|
+
responseText += `---\n\n`;
|
|
865
|
+
responseText += primaryContent;
|
|
866
|
+
}
|
|
867
|
+
else {
|
|
868
|
+
responseText = primaryContent;
|
|
869
|
+
}
|
|
854
870
|
return {
|
|
855
871
|
content: [{
|
|
856
872
|
type: "text",
|
|
857
|
-
text:
|
|
873
|
+
text: responseText
|
|
858
874
|
}]
|
|
859
875
|
};
|
|
860
876
|
}
|
|
@@ -880,13 +896,15 @@ Remember: You are ${currentAgent.toUpperCase()}, passionate advocate for ${assig
|
|
|
880
896
|
}]
|
|
881
897
|
};
|
|
882
898
|
}
|
|
883
|
-
formatPaginatedResponse(content, paginationParams, result, verbose,
|
|
899
|
+
formatPaginatedResponse(content, paginationParams, result, verbose, contextId) {
|
|
884
900
|
// Using imported pagination utilities
|
|
885
901
|
const offset = paginationParams.offset || 0;
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
902
|
+
// Convert character-based limit to token-based limit (1 token ≈ 4 chars)
|
|
903
|
+
const limitChars = paginationParams.limit || PAGINATION_DEFAULTS.DEFAULT_LIMIT;
|
|
904
|
+
const limitTokens = Math.ceil(limitChars / 4); // Convert chars to tokens
|
|
905
|
+
logger.info(`🔧 DEBUG: Paginating content - offset: ${offset}, limitChars: ${limitChars}, limitTokens: ${limitTokens}, total: ${content.length} chars`);
|
|
906
|
+
// Use ResponseChunker for intelligent boundary detection (TOKEN-BASED)
|
|
907
|
+
const chunker = new ResponseChunker(limitTokens, PAGINATION_DEFAULTS.CHUNK_OVERLAP_TOKENS);
|
|
890
908
|
const chunks = chunker.chunkText(content);
|
|
891
909
|
// Find the appropriate chunk based on offset
|
|
892
910
|
let targetChunk = chunks[0]; // Default to first chunk
|
|
@@ -905,7 +923,7 @@ Remember: You are ${currentAgent.toUpperCase()}, passionate advocate for ${assig
|
|
|
905
923
|
const actualOffset = targetChunk.startOffset;
|
|
906
924
|
const endOffset = targetChunk.endOffset;
|
|
907
925
|
// Create pagination metadata using actual chunk boundaries
|
|
908
|
-
const pagination = createPaginationMetadata(content.length, paginationParams,
|
|
926
|
+
const pagination = createPaginationMetadata(content.length, paginationParams, limitTokens, chunks, targetChunkIndex);
|
|
909
927
|
const statusLine = formatPaginationStatus(pagination);
|
|
910
928
|
// Estimate token usage for user awareness
|
|
911
929
|
const chunkTokens = estimateTokenCount(chunkContent);
|
|
@@ -917,20 +935,20 @@ Remember: You are ${currentAgent.toUpperCase()}, passionate advocate for ${assig
|
|
|
917
935
|
// Show pagination metadata
|
|
918
936
|
const needsPagination = pagination.totalChunks > 1 || pagination.hasMore;
|
|
919
937
|
const isFirstRequest = offset === 0;
|
|
920
|
-
// Always show
|
|
921
|
-
if (isFirstRequest &&
|
|
922
|
-
paginatedText += `**🔑
|
|
938
|
+
// Always show context_id on first request for future pagination
|
|
939
|
+
if (isFirstRequest && contextId) {
|
|
940
|
+
paginatedText += `**🔑 Context ID:** ${contextId}\n`;
|
|
923
941
|
paginatedText += `**🔢 Token Estimate:** ~${totalTokens.toLocaleString()} tokens (total)\n\n`;
|
|
924
942
|
}
|
|
925
943
|
if (needsPagination) {
|
|
926
944
|
paginatedText += `**📊 Pagination Status:** ${statusLine}\n`;
|
|
927
|
-
if (!isFirstRequest &&
|
|
928
|
-
paginatedText += `**🔑
|
|
945
|
+
if (!isFirstRequest && contextId) {
|
|
946
|
+
paginatedText += `**🔑 Context ID:** ${contextId}\n`;
|
|
929
947
|
}
|
|
930
948
|
paginatedText += `**🔢 Token Estimate:** ~${chunkTokens.toLocaleString()} tokens (chunk) / ~${totalTokens.toLocaleString()} tokens (total)\n\n`;
|
|
931
949
|
if (pagination.hasMore) {
|
|
932
|
-
if (
|
|
933
|
-
paginatedText += `**⏭️ Continue Reading:** Use \`
|
|
950
|
+
if (contextId) {
|
|
951
|
+
paginatedText += `**⏭️ Continue Reading:** Use \`context_id: "${contextId}", offset: ${endOffset}\`\n\n`;
|
|
934
952
|
}
|
|
935
953
|
else {
|
|
936
954
|
paginatedText += `**⏭️ Continue Reading:** Use \`offset: ${endOffset}\` for next chunk\n\n`;
|
|
@@ -945,8 +963,8 @@ Remember: You are ${currentAgent.toUpperCase()}, passionate advocate for ${assig
|
|
|
945
963
|
paginatedText += `\n\n---\n\n`;
|
|
946
964
|
if (pagination.hasMore) {
|
|
947
965
|
paginatedText += `📖 **End of chunk ${pagination.chunkIndex}/${pagination.totalChunks}**\n`;
|
|
948
|
-
if (
|
|
949
|
-
paginatedText += `🔄 To continue: Include \`
|
|
966
|
+
if (contextId) {
|
|
967
|
+
paginatedText += `🔄 To continue: Include \`context_id: "${contextId}"\` with \`offset: ${endOffset}\` in next request`;
|
|
950
968
|
}
|
|
951
969
|
else {
|
|
952
970
|
paginatedText += `🔄 To continue: Use same tool with \`offset: ${endOffset}\``;
|