Skip to content

feat(mcp): add $history variable and structured response format#17132

Merged
ayax79 merged 15 commits intonushell:mainfrom
andrewgazelka:feature/mcp-history-variable
Dec 10, 2025
Merged

feat(mcp): add $history variable and structured response format#17132
ayax79 merged 15 commits intonushell:mainfrom
andrewgazelka:feature/mcp-history-variable

Conversation

@andrewgazelka
Copy link
Contributor

@andrewgazelka andrewgazelka commented Dec 8, 2025

image
  • Add $history variable that stores all previous command outputs
  • Access by index: $history.0, $history.1, etc.
  • Wrap all responses in structured record with:
    • history_index: 0-based index of result in history
    • cwd: current working directory after command
    • output: command output (possibly truncated)
  • Truncate large outputs (>10k chars by default) and reference history
  • Configurable threshold via NU_MCP_OUTPUT_TRUNCATE env var
  • Remove moka caching (incompatible with history tracking)
  • Update instructions.md with history documentation

🤖 Generated with Claude Code

- Add `$history` variable that stores all previous command outputs
- Access by index: `$history.0`, `$history.1`, etc.
- Wrap all responses in structured record with:
  - `history_index`: 0-based index of result in history
  - `cwd`: current working directory after command
  - `output`: command output (possibly truncated)
- Truncate large outputs (>10k chars by default) and reference history
- Configurable threshold via `NU_MCP_OUTPUT_TRUNCATE` env var
- Remove moka caching (incompatible with history tracking)
- Update instructions.md with history documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Rename NU_MCP_OUTPUT_TRUNCATE to NU_MCP_OUTPUT_LIMIT
- Read from $env.NU_MCP_OUTPUT_LIMIT first (nushell native)
- Fall back to process env var if not set in nushell
- Add test for nushell env var configuration
@andrewgazelka andrewgazelka force-pushed the feature/mcp-history-variable branch from 7ffbdbb to d3bf1e3 Compare December 8, 2025 18:18
andrewgazelka and others added 2 commits December 8, 2025 10:21
…ions

- Remove process env var fallback for NU_MCP_OUTPUT_LIMIT
- Only use nushell's $env.NU_MCP_OUTPUT_LIMIT (typed int)
- Convert output_limit and register_history_variable to free-standing functions
- Use inline paths instead of grouped imports (per Rust conventions)
- Update instructions.md to clarify $history is list<any> and limit is bytes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
andrewgazelka and others added 2 commits December 8, 2025 10:25
Include unit (bytes) in the env var name for clarity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- NU_MCP_OUTPUT_LIMIT now accepts filesize (e.g., 10kb)
- No default fallback - truncation only happens when explicitly configured
- Returns Option<usize> instead of silently defaulting
@andrewgazelka andrewgazelka force-pushed the feature/mcp-history-variable branch from 966252f to fb1d8ce Compare December 8, 2025 18:30
Response format now has distinct fields:
- Normal: {cwd, history_index, output}
- Truncated: {cwd, history_index, note}
@andrewgazelka andrewgazelka marked this pull request as ready for review December 8, 2025 18:36
@fdncred
Copy link
Contributor

fdncred commented Dec 8, 2025

I'm not sure how I feel about this history functionality taking infinite memory. Yes, we can truncate each at 10k or whatever is set but a bazillion 10k's will still be too much memory. There should be a way to reclaim unused or old items.

Previously truncation only occurred when NU_MCP_OUTPUT_LIMIT was
explicitly set. Now defaults to 10kb, with 0 to disable truncation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@andrewgazelka
Copy link
Contributor Author

I'm not sure how I feel about this history functionality taking infinite memory. Yes, we can truncate each at 10k or whatever is set but a bazillion 10k's will still be too much memory. There should be a way to reclaim unused or old items.

it is just a variable so the model could technically modify it itself I think? have any specific ideas? we could alternateively also have $history only store the last x entries

@andrewgazelka
Copy link
Contributor Author

Claude Claude: Re: memory concerns - a few options to consider:

  1. Ring buffer: Store only the last N entries (e.g., 100). Simple and predictable.

  2. Max total size: Cap total history memory (e.g., 10MB), evicting oldest entries when exceeded.

  3. User-controlled: Let users clear history via $history = [] or add a $env.NU_MCP_HISTORY_LIMIT env var.

  4. LRU eviction: Evict least-recently-accessed entries (more complex to implement).

Given this is for MCP (AI tool use), conversations tend to be short-lived. A simple ring buffer of ~50-100 entries would likely cover most use cases while bounding memory. What do you think?

@fdncred
Copy link
Contributor

fdncred commented Dec 8, 2025

I'd vote for a ring buffer for X items of Y count/bytes/filesize but $history would probably also need a timedate stamp to know which item is the latest.

Addresses reviewer feedback about unbounded memory growth:
- History is now stored as a ring buffer (VecDeque) with configurable limit
- Default limit is 100 entries, configurable via NU_MCP_HISTORY_LIMIT env var
- Each history entry is now a record with `timestamp` and `value` fields
- Oldest entries are evicted when the limit is reached

Breaking change: History entries are now accessed via $history.N.value
instead of $history.N directly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Move timestamp from history entries to the response record
- History now stores just values directly ($history.0 instead of $history.0.value)
- Response includes: cwd, history_index, timestamp, output/note
- Ring buffer behavior unchanged (default 100 entries, configurable)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Replace inline paths with proper use statements at file top
- Extract history-related code into dedicated history.rs module
- History struct now encapsulates ring buffer and variable registration
- Cleaner separation of concerns between evaluation and history management

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@andrewgazelka
Copy link
Contributor Author

@fdncred All review threads addressed and resolved. Let me know if there's anything else needed for approval!

@ayax79
Copy link
Contributor

ayax79 commented Dec 10, 2025

@andrewgazelka I am doing a bit of testing. If all goes well, I'll merge tomorrow.

@ayax79
Copy link
Contributor

ayax79 commented Dec 10, 2025

working well so far, thanks!

@ayax79 ayax79 merged commit 11d71fe into nushell:main Dec 10, 2025
17 checks passed
@github-actions github-actions bot added this to the v0.110.0 milestone Dec 10, 2025
@fdncred fdncred added the A:MCP Model Context Protocol (nu-mcp) label Dec 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A:MCP Model Context Protocol (nu-mcp)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants