cra
mr

Context Management and MCP

Context Management and MCP

Narrator: Welcome to another edition of trying to explain to people why MCP vs CLI is the dumbest fucking debate on the planet.

At Sentry we recently shipped a new CLI, and the common reaction from a lot of folks was immediately “thank you now I can stop using the MCP!”.

Sigh.

People still don’t seem to understand how context works with LLMs, despite them all proclaiming their expertise while they simultaneously ship all their personal information to the public via some lobster-themed agent. With this post I’m going to try, once again, to help you do what you should already have done: step back and understand the problem space, and then make an informed decision.

Sentry has an MCP server that one might argue is best-in-class. I might even argue it is the best server on the market. Given I built the server — and I did so because I saw the potential in the spec — I like to think I’m fairly well informed, and I hope you’ll give me the benefit of the doubt if you’re an avid hater. What we’re going to focus on, within the MCP server, is simply the value of steering the agent and why CLI vs MCP doesn’t make sense as a conversation point.

First off, MCP does a lot of things. It’s bloated, complicated, and brittle. I’m not going to defend the protocol. What I do want to focus on, though, is how most people use MCP: exposing tools, often behind standardized authentication (OAuth). This is where I think the value is — nothing more, nothing less. It doesn’t need to be used to expose your documentation, to replace tools like bash and grep (generally, at least), and it certainly doesn’t need to be just a proxy for your existing machine-focused API.

To understand what I mean by steering, let’s look at one of the tools exposed from Sentry’s server:

I do not claim these are the most optimized descriptions, they’re just to illustrate the point.

Unified entry point for fetching Sentry resources. Auto-detects resource type from URL or accepts explicit type and identifiers.

USE THIS TOOL WHEN:

- User provides a Sentry URL (any type: issue, event, trace, profile, replay, monitor, release)
- User wants to fetch a specific resource by type and ID

FULLY SUPPORTED:

- **issue**: Fetch issue details by ID
- **event**: Fetch specific event within an issue
- **trace**: Fetch trace details (supports span focus from URL)
- **profile**: Fetch and analyze CPU profiling data

URL RECOGNIZED (returns helpful guidance):

- **replay**: Session replay URLs
- **monitor**: Cron monitor URLs
- **release**: Release URLs

<examples>
### URL mode (auto-detect type)

```
get_sentry_resource(url='https://my-org.sentry.io/issues/PROJECT-123')
get_sentry_resource(url='https://my-org.sentry.io/explore/traces/trace/abc123...')
get_sentry_resource(url='https://my-org.sentry.io/replays/def456...')
```

### Explicit mode - Issue

```
get_sentry_resource(
resourceType='issue',
organizationSlug='my-org',
issueId='PROJECT-123'
)
```

### Explicit mode - Trace

```
get_sentry_resource(
resourceType='trace',
organizationSlug='my-org',
traceId='a4d1aae7216b47ff8117cf4e09ce9d0a'
)
```

</examples>

<hints>
- URL mode is simplest: just pass the Sentry URL and the tool auto-detects the resource type
- For explicit mode, required params depend on resourceType:
  - issue: organizationSlug, issueId
  - event: organizationSlug, issueId, eventId
  - trace: organizationSlug, traceId
  - profile: organizationSlug, projectSlug, transactionName
</hints>

This is for a tool called get_sentry_resource, which is kind of like a URL handler. I want you to focus on the intent — what we’re exposing as a description. Our goal is to steer the agent so that, when a Sentry URL is offered, it can fetch information about that resource. Under the hood this will take something like an issue URL, map it to another function call that makes a handful of API requests, and shape a response:

# Issue MCP-SERVER-ET3 in **sentry**

**Description**: No refresh token available in stored props
**Culprit**: https://mcp.sentry.dev/oauth/token
**First Seen**: 2025-10-02T01:16:40.915Z
**Last Seen**: 2026-02-02T20:40:22.000Z
**Occurrences**: 239413
**Users Impacted**: 1069
**Status**: unresolved
**Substatus**: ongoing
**Issue Type**: error
**Issue Category**: error
**Seer Actionability**: low
**Platform**: javascript
**Project**: mcp-server
**URL**: https://sentry.sentry.io/issues/MCP-SERVER-ET3

## Event Details

**Event ID**: 5b9953564f2d44299fa613bdd1132fe5
**Type**: default
**Occurred At**: 2026-02-02T20:40:22.122Z
**Message**:
No refresh token available in stored props

### Error

```
No refresh token available in stored props
```

### HTTP Request

**Method:** POST
**URL:** https://mcp.sentry.dev/oauth/token

### Tags

**environment**: cloudflare
**level**: error
**mcp.server_version**: 0.29.0
**release**: 32ee8c5e-e4d4-4cf4-8818-67308c6345e2
**runtime.name**: cloudflare
**url**: https://mcp.sentry.dev/oauth/token
**user**: id:379324

### Additional Context

This is additional context provided by the user when they're instrumenting their application.

**cloud_resource**
cloud.provider: "cloudflare"

**culture**
timezone: "America/Chicago"

**runtime**
name: "cloudflare"

**trace**
trace_id: "df281d6d033048b6bc7e26386e3a2c06"
span_id: "bee527a8c961304d"
status: "unknown"
client_sample_rate: 1
sampled: true

# Using this information

- You can reference the IssueID in commit messages (e.g. `Fixes MCP-SERVER-ET3`) to automatically close the issue when the commit is merged.
- The stacktrace includes both first-party application code as well as third-party code; it's important to triage to first-party code.
- To search for specific occurrences or filter events within this issue, use `search_issue_events(organizationSlug='sentry', issueId='MCP-SERVER-ET3', naturalLanguageQuery='your query')`

That’s a lot, but you’ll notice some of the same things in both of these examples: they’re returning LLM-catered responses. While they might be good for a human, it’s not remotely what our API would output (it’s also multiple API calls), and it’s also likely not what we’d output from a CLI. Both the API and the CLI often cater more toward machine-driven tasks, whereas the MCP we are focused on is steering the agent.

  1. We’re using Markdown, and in some cases XML-like syntax to contain sections.
  2. We create hints for the agent to suggest additional behaviors (such as how to retrieve more context if this wasn’t enough).
  3. (Generally) We aim to minimize mistakes in how an LLM can call the tool (fewer params).

The ability to steer the LLM is the entire value prop of MCP tools, in my opinion. It is what allows you to set up the Sentry MCP and one-shot fix a bug, pretty reliably.

OK, back to the CLI debate: “But you could do the same thing with a CLI!” you’re screaming in your head right now. You could do some of this with a CLI. For example, in Dex I explicitly return steering information for various calls (which is also helpful for humans):

  ~/s/warden (fix/auto-resolution-and-approval) ✔ dex complete v1o7yoi0
Error: --result (-r) is required
Usage: dex complete <task-id> --result "completion notes"
  /t/test dex show ypjxlsft
[ ] alicbtao: Example
└── [ ] ypjxlsft: Example 2 viewing

Description:


Created:   2026-02-02T20:52:43.988Z
Updated:   2026-02-02T20:52:43.988Z

More Information:
 View parent task: dex show alicbtao

So yes, you can still provide steering context, but it’s missing a key behavior of the MCP: a lot of that steering context is always on in the agent. “But that uses a lot of tokens for no reason!” you continue to argue. Sure, and progressive tool disclosure is certainly not the solution. “You can just ship a SKILL with your CLI” is the approach a lot have taken (What are Skills?). That can be OK in some cases, and it’s what I do with Dex, but it means I also have to inject that skill context. That’s usually done with something like the following in your AGENTS.md:

Use /dex for managing tasks.

There are two problems with this:

  1. Skill support is variable, as are the implementations. Behavior is unreliable at best.
  2. You’re now asking everyone to set up the Skill (still a pain in the ass) AND you’re updating every single project’s AGENTS.md to try to steer the LLM to use the Skill.

These don’t even touch on the challenge of auth, which often ends up as a custom or one-off thing; those alone are a big deal.

My general concern is that people are completely ignoring the fundamental limitations of the technology. We cannot prevent context rot, so you need to embrace consuming context in the most effective way possible. Your token strategy needs to be focused on results, which often means spending more tokens in the short term to save in the long term. It doesn’t help to spend your time trying to coerce the LLM to call the right command-line interface, only to ultimately fill the context window with noise and consume more net tokens than you would have otherwise.

With all this said, I fully agree that loading up your context window with a bunch of always-on MCP tools is not the answer, and many of the MCP implementations out there either don’t need to exist (e.g., Context7) or are of such low quality that they might as well not exist (e.g., GitHub).

That leads us to the last elephant in the room: progressive disclosure, or tool search, or any of the other attempts to stop pre-consuming tokens. It’s a really fucking bad idea.

If you haven’t already understood the value of the steering context, just give up and go back to arguing on the internet about MCP being evil and CLIs being some god-mode hack that’s anything more than a placebo. The rest assumes you understand context windows and agree with the premise that steering = valuable.

Progressive disclosure in any form hides context from the agent, which means things like description-based steering disappear. It means you’ve dumbed down tool calls to being no different than a shitty wrapper on your API. MCP using progressive disclosure is worse than a CLI. Its two steps backwards.

Importantly it also doesn’t solve the issue of recall, which we easily see with Skills as well. The agent very quickly will ignore what skills are in its system prompt and go its merry way. I see this with a “create-pr” skill we use. I explicitly tell it to “use the create-pr skill” (in various forms), and 70% of the time it does nothing and goes on its merry way. The usage of skills could be in post-training, in the core harness’s prompt, and they are still often ignored. What do you think it’s going to do with your CLI instructions that are buried 20k tokens deep?

Context rot is unavoidable and you cannot work around it (with today’s models).

I don’t know what the right answer is. Obviously it’d be great if pre/post-training led to the models never fucking up a tool call, and if they could do really cheap and completely reliable discovery of tools. I don’t see that happening in the near term, so my best advice is simple: leverage subagents.

The subagent approach gives a ton of flexibility in how you approach problems:

  • You can create isolation between models (using different models for different tasks)
  • You can restrict tools to only ones you want (read-only is a great example!)
  • You can opt-in to tools that otherwise weren’t exposed (imagine, IMAGINE, if MCP tools could be only disclosed to a specific subagent)
  • You minimize context rot, as you’re explicit about the entire context being run in a subagent
  • There is a lot of flexibility in how context is passed/discovered (forking, summarization, distillation, memory).

I’m not going to go into the approaches in this post, but they feel like the right logical next step. I want Skills, but with fewer consequences. I want this:

---
name: "sentry"
description: "Get help from Sentry about a problem, like debugging an error, querying information from sentry.io, and other cool shit"
mcpServers:
  - "sentry"
addedTools:
  - "sentry:*"
---
An entire, functional, contained system prompt that would let us ship a subagent to your local interpreter. One where the MCP server was _only_ active in context in this subagent, and where it could still manage OAuth itself.

Its not a perfect solution, but for a lot of use cases I think it’d do a lot better than everyones cheap duct-tape. Most importantly it embraces the limitations of the models.

If you don’t understand most of what I said above around context management, maybe this post from Anthropic is more useful.

More Reading

2026

MCP, Skills, and Agents

2025

Rethinking Tools in MCP

Subagents with MCP

Instrumenting Your MCP Server

MCP is not good, yet.