@ebowwa/large-output 1.1.0 → 1.2.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.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Shared utility for handling large MCP outputs with automatic file fallback and **actionable LLM prompts**.
4
4
 
5
+ **Available in TypeScript and Rust with full API parity.**
6
+
5
7
  ## Problem Solved
6
8
 
7
9
  When MCP tools return large outputs, they typically hit Claude's ~20,000 character tool output limit. Common solutions like pagination fragment the context and require multiple round-trips.
@@ -9,55 +11,26 @@ When MCP tools return large outputs, they typically hit Claude's ~20,000 charact
9
11
  **This library solves it by:**
10
12
  - Returning content inline if under the threshold
11
13
  - Automatically writing to a temp file if over the threshold
12
- - **Returning actionable text that prompts the LLM to read the file** (NEW in v1.1.0)
13
-
14
- ## What's New in v1.1.0
15
-
16
- **Actionable Response Format (Default):**
17
-
18
- Instead of returning JSON that LLMs often ignore:
19
- ```json
20
- {"type": "file", "path": "...", "size": 126507}
21
- ```
22
-
23
- Now returns actionable text:
24
- ```
25
- ⚠️ Large output (126.5 KB) saved to file.
26
-
27
- 📖 **ACTION REQUIRED**: Use the Read tool to read this file:
14
+ - **Returning actionable text that prompts the LLM to read the file**
28
15
 
29
- /tmp/mcp_output_2025-02-19T12-38-00_abc123.txt
16
+ ---
30
17
 
31
- --- PREVIEW (first 500 chars) ---
32
- [preview content...]
33
- --- END PREVIEW ---
34
-
35
- ✅ File contains the complete data. Read it to proceed.
36
- ```
18
+ ## TypeScript
37
19
 
38
- This format is designed to **prompt the LLM to take action** and read the file.
39
-
40
- ## Installation
20
+ ### Installation
41
21
 
42
22
  ```bash
43
- # From npm
44
23
  bun add @ebowwa/large-output
45
-
46
- # Or from within the monorepo
47
- bun add ../../packages/src/large-output
48
24
  ```
49
25
 
50
- ## Quick Start
26
+ ### Quick Start
51
27
 
52
28
  ```typescript
53
29
  import { handleMCPOutput } from "@ebowwa/large-output";
54
30
 
55
31
  // In your MCP tool handler:
56
32
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
57
- const { query } = request.params.arguments as { query: string };
58
-
59
- // Fetch your data
60
- const results = await fetchData(query);
33
+ const results = await fetchData();
61
34
  const content = JSON.stringify(results, null, 2);
62
35
 
63
36
  // Return with automatic file fallback (actionable format by default)
@@ -67,147 +40,128 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
67
40
  });
68
41
  ```
69
42
 
70
- ## API
43
+ ### API
71
44
 
72
- ### `handleMCPOutput(content, options?)`
45
+ | Function | Description |
46
+ |----------|-------------|
47
+ | `handleOutput(content, options?)` | Handle output, returns `OutputResponse` |
48
+ | `handleMCPOutput(content, options?)` | Convenience: handle + return MCP string |
49
+ | `toMCPResponse(response, format)` | Convert `OutputResponse` to string |
50
+ | `handleBatch(contents, options?)` | Batch handler for multiple outputs |
73
51
 
74
- Convenience function that handles output and returns MCP-formatted string.
52
+ ### Options
75
53
 
76
54
  | Option | Type | Default | Description |
77
55
  |--------|------|---------|-------------|
78
- | `threshold` | number | `15000` | Character threshold for file fallback |
79
- | `previewLength` | number | `500` | Preview chars when written to file |
80
- | `tempDir` | string | `os.tmpdir()` | Custom temp directory |
81
- | `filenamePrefix` | string | `"mcp_output"` | Filename prefix |
82
- | `includeSize` | boolean | `true` | Include size in file response |
83
- | `includePreview` | boolean | `true` | Include preview in file response |
84
- | `responseFormat` | `"actionable"` \| `"json"` | `"actionable"` | Response format for file outputs |
85
-
86
- ### Response Formats
56
+ | `threshold` | `number` | `15000` | Character threshold for file fallback |
57
+ | `previewLength` | `number` | `500` | Preview chars when written to file |
58
+ | `tempDir` | `string` | `os.tmpdir()` | Custom temp directory |
59
+ | `filenamePrefix` | `string` | `"mcp_output"` | Filename prefix |
60
+ | `includeSize` | `boolean` | `true` | Include size in file response |
61
+ | `includePreview` | `boolean` | `true` | Include preview in file response |
62
+ | `responseFormat` | `"actionable"` \| `"json"` | `"actionable"` | Response format |
87
63
 
88
- **Inline (under threshold):**
89
- ```
90
- <raw content returned directly>
91
- ```
64
+ ---
92
65
 
93
- **File - Actionable format (default):**
94
- ```
95
- ⚠️ Large output (126.5 KB) saved to file.
66
+ ## Rust
96
67
 
97
- 📖 **ACTION REQUIRED**: Use the Read tool to read this file:
68
+ Located in `./rust/` directory.
98
69
 
99
- /tmp/mcp_output_2025-02-19T12-38-00_abc123.txt
70
+ ### Installation
100
71
 
101
- --- PREVIEW (first 500 chars) ---
102
- {...preview...}
103
- --- END PREVIEW ---
104
-
105
- ✅ File contains the complete data. Read it to proceed.
106
- ```
72
+ Add to your `Cargo.toml`:
107
73
 
108
- **File - JSON format (for programmatic consumers):**
109
- ```json
110
- {
111
- "type": "file",
112
- "path": "/tmp/mcp_output_2025-02-19T12-38-00_abc123.txt",
113
- "size": 126507,
114
- "sizeFormatted": "126.5 KB",
115
- "preview": "..."
116
- }
74
+ ```toml
75
+ [dependencies]
76
+ large-output = "1.2.0"
117
77
  ```
118
78
 
119
- ## Advanced Usage
79
+ ### Quick Start
120
80
 
121
- ### Using JSON format
81
+ ```rust
82
+ use large_output::{handle_output, handle_mcp_output, OutputResponse};
122
83
 
123
- If you need JSON for programmatic consumers:
84
+ let content = "very large content...".repeat(1000);
85
+ let response = handle_output(&content, None);
124
86
 
125
- ```typescript
126
- import { handleMCPOutput } from "@ebowwa/large-output";
87
+ match response {
88
+ OutputResponse::Inline { content, .. } => println!("{}", content),
89
+ OutputResponse::File { path, size, .. } => {
90
+ println!("Written {} bytes to {:?}", size, path);
91
+ }
92
+ }
127
93
 
128
- return handleMCPOutput(JSON.stringify(results), {
129
- responseFormat: "json",
130
- });
94
+ // MCP convenience function
95
+ let mcp_text = handle_mcp_output(&content, None);
96
+ println!("{}", mcp_text);
131
97
  ```
132
98
 
133
- ### Direct response handling
99
+ ### API
134
100
 
135
- ```typescript
136
- import { handleOutput, toMCPResponse } from "@ebowwa/large-output";
101
+ | Function | Description |
102
+ |----------|-------------|
103
+ | `handle_output(content, options)` | Handle output, returns `OutputResponse` |
104
+ | `handle_mcp_output(content, options)` | Convenience: handle + return MCP string |
105
+ | `to_mcp_response(response, format)` | Convert `OutputResponse` to string |
106
+ | `handle_batch(contents, options)` | Batch handler for multiple outputs |
107
+ | `OptionsBuilder::new()...build()` | Builder for `LargeOutputOptions` |
137
108
 
138
- const response = handleOutput(largeContent, {
139
- threshold: 20000,
140
- filenamePrefix: "github_search",
141
- });
109
+ ### Options
142
110
 
143
- if (response.type === "file") {
144
- console.log(`Written ${response.sizeFormatted} to ${response.path}`);
145
- }
146
-
147
- // Convert to MCP return format (actionable by default)
148
- return toMCPResponse(response);
111
+ ```rust
112
+ use large_output::{OptionsBuilder, ResponseFormat};
149
113
 
150
- // Or explicitly use JSON format
151
- return toMCPResponse(response, "json");
114
+ let options = OptionsBuilder::new()
115
+ .threshold(20000)
116
+ .preview_length(1000)
117
+ .filename_prefix("github_search")
118
+ .response_format(ResponseFormat::Json)
119
+ .build();
152
120
  ```
153
121
 
154
- ### Batch handling
122
+ ### Feature Flags
155
123
 
156
- ```typescript
157
- import { handleBatch } from "@ebowwa/large-output";
124
+ - `default` - Synchronous file operations
125
+ - `async` - Async file operations with tokio
158
126
 
159
- const outputs = handleBatch([data1, data2, data3]);
160
- // Each output handled independently
161
- ```
127
+ ---
162
128
 
163
- ## Examples by MCP Server
129
+ ## Response Formats
164
130
 
165
- ### github-search
166
- ```typescript
167
- import { handleMCPOutput } from "@ebowwa/large-output";
131
+ ### Inline (under threshold)
168
132
 
169
- const results = await githubApi.search(query, { per_page: 100 });
170
- // Fetch all pages, accumulate results
171
- return handleMCPOutput(JSON.stringify(results, null, 2));
172
- ```
133
+ Content returned directly.
173
134
 
174
- ### claude-code-history
175
- ```typescript
176
- import { handleMCPOutput } from "@ebowwa/large-output";
135
+ ### File - Actionable format (default)
177
136
 
178
- const conversations = await getConversations({ limit: 1000 });
179
- return handleMCPOutput(JSON.stringify(conversations, null, 2));
180
137
  ```
138
+ Large output (126.5 KB) saved to file.
181
139
 
182
- ### git
183
- ```typescript
184
- import { handleMCPOutput } from "@ebowwa/large-output";
140
+ ACTION REQUIRED: Use the Read tool to read this file:
185
141
 
186
- const commits = await gitLog({ maxCount: 500 });
187
- return handleMCPOutput(JSON.stringify(commits, null, 2));
188
- ```
142
+ /tmp/mcp_output_2025-02-19T12-38-00_abc123.txt
189
143
 
190
- ### npm-publish
191
- ```typescript
192
- import { handleMCPOutput } from "@ebowwa/large-output";
144
+ --- PREVIEW (first 500 chars) ---
145
+ {...preview...}
146
+ --- END PREVIEW ---
193
147
 
194
- const packages = await searchPackages({ limit: 500 });
195
- return handleMCPOutput(JSON.stringify(packages, null, 2));
148
+ File contains the complete data. Read it to proceed.
196
149
  ```
197
150
 
198
- ## Migration from v1.0.x
151
+ ### File - JSON format
199
152
 
200
- No code changes needed! The default behavior now uses actionable format.
201
-
202
- If you relied on JSON format:
203
- ```typescript
204
- // Old (v1.0.x) - JSON was default
205
- handleMCPOutput(content);
206
-
207
- // New (v1.1.0) - Explicitly request JSON
208
- handleMCPOutput(content, { responseFormat: "json" });
153
+ ```json
154
+ {
155
+ "type": "file",
156
+ "path": "/tmp/mcp_output_2025-02-19T12-38-00_abc123.txt",
157
+ "size": 126507,
158
+ "sizeFormatted": "126.5 KB",
159
+ "preview": "..."
160
+ }
209
161
  ```
210
162
 
163
+ ---
164
+
211
165
  ## License
212
166
 
213
167
  MIT
package/dist/index.d.ts CHANGED
@@ -92,7 +92,7 @@ export type OutputResponse = InlineOutputResponse | FileOutputResponse;
92
92
  */
93
93
  export declare function handleOutput(content: string, options?: LargeOutputOptions): OutputResponse;
94
94
  /**
95
- * Convert an OutputResponse to a JSON string for MCP tool return
95
+ * Convert an OutputResponse to a string for MCP tool return
96
96
  *
97
97
  * @param response - The response from handleOutput()
98
98
  * @param format - Response format: "actionable" (default) or "json"
@@ -101,7 +101,7 @@ export declare function handleOutput(content: string, options?: LargeOutputOptio
101
101
  * @example
102
102
  * ```ts
103
103
  * const response = handleOutput(largeContent);
104
- * return JSON.stringify(toMCPResponse(response));
104
+ * return toMCPResponse(response);
105
105
  * ```
106
106
  */
107
107
  export declare function toMCPResponse(response: OutputResponse, format?: "actionable" | "json"): string;
package/dist/index.js CHANGED
@@ -100,7 +100,7 @@ export function handleOutput(content, options = {}) {
100
100
  return response;
101
101
  }
102
102
  /**
103
- * Convert an OutputResponse to a JSON string for MCP tool return
103
+ * Convert an OutputResponse to a string for MCP tool return
104
104
  *
105
105
  * @param response - The response from handleOutput()
106
106
  * @param format - Response format: "actionable" (default) or "json"
@@ -109,7 +109,7 @@ export function handleOutput(content, options = {}) {
109
109
  * @example
110
110
  * ```ts
111
111
  * const response = handleOutput(largeContent);
112
- * return JSON.stringify(toMCPResponse(response));
112
+ * return toMCPResponse(response);
113
113
  * ```
114
114
  */
115
115
  export function toMCPResponse(response, format = "actionable") {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ebowwa/large-output",
3
- "version": "1.1.0",
4
- "description": "Shared utility for handling large MCP outputs with automatic file fallback and actionable LLM prompts",
3
+ "version": "1.2.0",
4
+ "description": "Shared utility for handling large MCP outputs with automatic file fallback and actionable LLM prompts. Includes TypeScript and Rust implementations.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -12,10 +12,13 @@
12
12
  }
13
13
  },
14
14
  "files": [
15
- "dist"
15
+ "dist",
16
+ "rust"
16
17
  ],
17
18
  "scripts": {
18
19
  "build": "tsc",
20
+ "build:rust": "cd rust && cargo build --release",
21
+ "test": "tsc --noEmit && cd rust && cargo test",
19
22
  "prepublishOnly": "bun run build"
20
23
  },
21
24
  "keywords": [
@@ -23,12 +26,26 @@
23
26
  "output",
24
27
  "pagination",
25
28
  "file-fallback",
26
- "llm-actionable"
29
+ "llm-actionable",
30
+ "rust",
31
+ "typescript"
27
32
  ],
28
33
  "author": "ebowwa",
29
34
  "license": "MIT",
30
35
  "devDependencies": {
31
36
  "@types/node": "^22.10.2",
32
37
  "typescript": "^5.7.2"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/ebowwa/codespaces",
42
+ "directory": "packages/src/ai/large-output"
43
+ },
44
+ "ownership": {
45
+ "domain": "tooling",
46
+ "responsibilities": [
47
+ "output-handling",
48
+ "large-response-management"
49
+ ]
33
50
  }
34
51
  }