Skip to content

Commit ac718aa

Browse files
committed
feat: add Zod validation and enhance MCP server functionality with new log retrieval and clearing tools
1 parent b4be2d5 commit ac718aa

11 files changed

Lines changed: 1040 additions & 28 deletions

File tree

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ No production impact. Providers enable this across frameworks by injecting a tin
3737
- Colorized terminal output
3838
- Optional file logging (Vite provider only)
3939
- Works great with AI assistants reading your terminal
40+
- **NEW:** MCP (Model Context Protocol) support for enhanced AI assistant integration
41+
42+
## MCP Support for AI Assistants
43+
44+
Browser Echo now includes built-in MCP server support, enabling AI assistants like Claude (via Cursor) to interact with your frontend logs using natural language commands:
45+
46+
- **"Check frontend logs"** - Retrieves recent console logs
47+
- **"Show only errors from the last 2 minutes"** - Filters by level and time
48+
- **"Find hydration mismatch warnings"** - Searches for specific content
49+
- **"Clear logs and start fresh"** - Clears the buffer for new captures
50+
- **"Focus on my current tab's logs"** - Filters by session
51+
52+
The MCP server exposes two main tools:
53+
- `get_logs` - Fetch logs with extensive filtering (level, session, time, content)
54+
- `clear_logs` - Clear logs with soft/hard modes and session-specific clearing
55+
56+
This integration makes debugging with AI assistants much more powerful - they can directly query and analyze your frontend logs without you having to copy/paste from the terminal.
4057

4158
## Options (shared shape)
4259

docs.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
You’re right to push on this. **Typing `browser-echo://logs` shouldn’t be required** for beginners. Two things are true at once:
2+
3+
1. Most MCP hosts *can* call your resource automatically from plain English (they read your resource & tool **names/descriptions** and decide what to invoke).
4+
2. In practice, **discoverability improves a lot** if you give the model a small, NL‑friendly *tool alias* and a couple of “quick actions” (prompts).
5+
6+
Below is a practical plan so “check frontend logs” *just works* in Cursor and Claude—**no URIs required**—while still keeping your “fewer tools” philosophy.
7+
8+
---
9+
10+
## The fix: a *hybrid* interface (Resource + one NL tool + optional prompts)
11+
12+
### 1) Keep the resource
13+
14+
* It’s perfect for streaming/reading the whole buffer and for structured returns.
15+
* Keep `browser-echo://logs` and (optionally) `browser-echo://logs/{session}`.
16+
17+
### 2) Add **one** tool alias: `get_logs`
18+
19+
* Purpose: make intent resolution trivial. The LLM sees a tool literally named “get logs” with a description like “Fetch recent **frontend browser console logs** (errors/warnings/info) from the running dev app.”
20+
* Inputs (all optional):
21+
22+
```ts
23+
{
24+
level?: ('error'|'warn'|'info'|'log'|'debug')[]; // default: all
25+
session?: string; // 8-char id prefix
26+
includeStack?: boolean; // default: true
27+
limit?: number; // e.g., 200
28+
contains?: string; // substring filter
29+
sinceMs?: number; // e.g., Date.now()-300000
30+
}
31+
```
32+
* Output: **both** a text summary *and* a JSON list of entries (models love JSON for follow-up reasoning).
33+
34+
> Why one tool? It acts as the **NLP entry point**. The planner can easily decide: “User said ‘check error logs’ → call `get_logs` with `level:['error','warn']`.” You still have just **two tools total** (`get_logs`, `clear_logs`).
35+
36+
### 3) (Optional) Register **prompt templates** (“Quick actions”)
37+
38+
* “Check frontend logs (last 2 minutes)”
39+
* “Check only errors & warnings”
40+
* “Clear and capture new logs for 30s”
41+
* Many hosts surface these as clickable actions or as suggestions when users type.
42+
43+
*(If your SDK version exposes a `registerPrompt` API, use it. If not, you still get most of the win from the `get_logs` tool naming/description.)*
44+
45+
### 4) Tune **names & descriptions** (this matters a lot)
46+
47+
* Server name: **“Browser Echo (Frontend Logs)”**
48+
* Resource title: **“Frontend Browser Console Logs”**
49+
* Resource description: include keywords beginners use: *frontend logs, console errors, warnings, React/Next hydration, network failures*.
50+
* Tool description: repeat those keywords and examples (e.g., “show hydration errors, network failures, React warnings”).
51+
52+
### 5) Return **JSON alongside text**
53+
54+
* When resolving the resource and the tool, include **two contents**: a human‑readable plain text block (like your terminal format) **and** a JSON array of entries.
55+
* This lets the model filter/sort programmatically without fighting text parsing.
56+
57+
---
58+
59+
## What this changes in the user experience
60+
61+
* In **Cursor** or **Claude Code**, users can simply write:
62+
63+
***Check frontend logs**
64+
***Show only errors from the last 2 minutes**
65+
***Find hydration mismatch warnings**
66+
* The IDE’s planner will typically call **`get_logs`** with sensible args. If it doesn’t, the descriptive names make it very likely on the second try.
67+
* Power users can still say “fetch the logs resource” or click a quick action.
68+
69+
---
70+
71+
## Minimal code sketch (drop‑in to your server snippet)
72+
73+
Add the `get_logs` tool *next to* your existing `clear_logs` registration:
74+
75+
```ts
76+
server.registerTool(
77+
'get_logs',
78+
{
79+
title: 'Get Frontend Browser Logs',
80+
description:
81+
'Fetch recent frontend browser console logs (errors/warnings/info). ' +
82+
'Use this when the user asks to check frontend logs, errors, hydration issues, or network failures.',
83+
inputSchema: {
84+
type: 'object',
85+
properties: {
86+
level: {
87+
type: 'array',
88+
items: { enum: ['log','info','warn','error','debug'] },
89+
description: 'Filter by levels'
90+
},
91+
session: { type: 'string', description: '8-char session id prefix' },
92+
includeStack: { type: 'boolean', default: true },
93+
limit: { type: 'number', minimum: 1, maximum: 5000 },
94+
contains: { type: 'string', description: 'Substring filter' },
95+
sinceMs: { type: 'number', description: 'Only entries with time >= sinceMs' }
96+
},
97+
additionalProperties: false
98+
} as any
99+
},
100+
async ({ level, session, includeStack = true, limit = 1000, contains, sinceMs }) => {
101+
let items = STORE.snapshot();
102+
if (sinceMs) items = items.filter(e => !e.time || e.time >= sinceMs);
103+
if (session) items = items.filter(e => (e.sessionId||'').slice(0,8) === session.slice(0,8));
104+
if (level?.length) items = items.filter(e => level.includes(e.level));
105+
if (contains) items = items.filter(e => (e.text||'').includes(contains));
106+
if (!includeStack) items = items.map(e => ({ ...e, stack: '' }));
107+
if (limit && items.length > limit) items = items.slice(-limit);
108+
109+
// Text view (like terminal but no ANSI)
110+
const text = items.map(e => {
111+
const sid = (e.sessionId||'anon').slice(0,8);
112+
const lvl = (e.level||'log').toUpperCase();
113+
const tag = e.tag || '[browser]';
114+
let line = `${tag} [${sid}] ${lvl}: ${e.text}`;
115+
if (e.source) line += ` (${e.source})`;
116+
if (includeStack && e.stack?.trim()) {
117+
const indented = e.stack.split(/\r?\n/g).map(l => l ? ` ${l}` : l).join('\n');
118+
return `${line}\n${indented}`;
119+
}
120+
return line;
121+
}).join('\n');
122+
123+
return {
124+
content: [
125+
{ type: 'text', text },
126+
{ type: 'json', json: { entries: items } }
127+
]
128+
};
129+
}
130+
);
131+
```
132+
133+
> That’s it: one tool. Keep your existing resource; now beginners never need to type its URI.
134+
135+
*(If you want “quick actions”, add prompt registrations that internally call `get_logs` with common defaults. If your SDK version doesn’t expose prompts, you can simulate by adding small, well‑named tools like `get_error_logs` that just call `get_logs` internally with `level:['error','warn']`. Still a tiny tool count.)*
136+
137+
---
138+
139+
## Real‑world flows that become “NLP‑easy”
140+
141+
***Check frontend logs**” → calls `get_logs()` with defaults → shows text + JSON, model summarizes.
142+
***Only errors since I refreshed**” → `get_logs({ level:['error','warn'], sinceMs: <timestamp of refresh> })`
143+
***Hydration issues**” → `get_logs({ contains:'Hydration', level:['error','warn'] })`
144+
***Focus my current tab**” → model lists sessions then calls `get_logs({ session:'a1b2c3d4' })`
145+
***Start a clean capture, then I’ll repro**” → `clear_logs()` → wait → `get_logs({ level:['error','warn'] })`
146+
147+
---
148+
149+
## Do you *have* to keep the resource?
150+
151+
No, but I recommend it:
152+
153+
* Tools improve **intent mapping**.
154+
* Resources are great for **streaming and bulk reads** and are a natural fit for “log feed”.
155+
* Together, they maximize compatibility and robustness across hosts.
156+
157+
---
158+
159+
### Bottom line
160+
161+
You didn’t misunderstand—**URIs are optional** in day‑to‑day use. Make it NLP‑easy by adding **one** `get_logs` tool (plus good naming/descriptions, optional quick prompts). Keep the resource as the high‑throughput backbone. That strikes the balance between **beginner‑friendly UX** and **minimal surface area**, while staying aligned with “fewer tools” best practices.
162+
163+
164+
what about clear_logs. should we keep this or not?
165+
166+
**Keep `clear_logs`.**
167+
It’s one of the few side‑effect tools that’s *worth having* even under a “fewer tools” philosophy. It makes “fresh capture → reproduce → analyze” dead‑simple for the model and for beginners—no parameters, no URIs—just *“clear the logs, I’ll repro, then check errors.”*
168+
169+
Below is the why, when, and how—plus a safe refinement you can add (optional) without increasing tool count.
170+
171+
---
172+
173+
## Why keep it?
174+
175+
* **Deterministic captures:** Guarantees the next fetch contains *only* the logs from your repro, avoiding stale noise. This is hard to get right if you rely solely on “since time” filters—the planner may forget to pass them.
176+
* **Shorter, cleaner context:** Fewer irrelevant lines → cheaper + more accurate reasoning/summarization.
177+
* **Beginner‑friendly NLP:** Users can say *“start a clean capture”* and the assistant calls a single, obvious tool with no arguments.
178+
* **Side‑effect separation:** Getting data (resource / `get_logs`) vs. performing an action (`clear_logs`) are cleanly distinguished for the agent.
179+
180+
You’ll still have just **two** tools total:
181+
182+
1. `get_logs` (NLP entry point for fetching)
183+
2. `clear_logs` (fresh capture)
184+
185+
That’s minimal, and it maps perfectly to how people actually debug.
186+
187+
---
188+
189+
## When to use it (practical patterns)
190+
191+
* **Repro loop:**
192+
*“Run `clear_logs`. I’ll trigger the bug. In 30s, fetch logs and summarize only errors/warnings with the top stack + source.”*
193+
* **Fix verification:**
194+
*“Clear logs, reload, then confirm the previous hydration error is gone; if anything new appears, list it.”*
195+
* **Race conditions / intermittent failures:**
196+
*“Clear logs, I’ll click around for 60s. Then group errors by stack top and propose a guard.”*
197+
* **Per‑session focus:**
198+
*“Clear logs for my session `ab12cd34`, I’ll repro on that tab, then fetch only that session’s logs.”* (see refinement below)
199+
200+
---
201+
202+
## What if we removed it?
203+
204+
You *can* approximate with `get_logs({ sinceMs })`, but:
205+
206+
* The assistant might omit or mis‑set `sinceMs`.
207+
* Other background logs (extensions, other tabs) can still creep in.
208+
* New users don’t know to ask for a time‑window; “clear and check” is intuitive.
209+
210+
In practice, **`clear_logs` saves mistakes** and reduces friction.
211+
212+
---
213+
214+
## Recommended refinement (optional, still one tool)
215+
216+
Keep the same tool name, but give it **gentle scoping** so it’s safer and more flexible **without** adding tools:
217+
218+
**Inputs (optional):**
219+
220+
* `session?: string` — clear only one 8‑char session (good for multi‑tab/dev setups)
221+
* `scope?: 'soft' | 'hard'` — default `'soft'`
222+
223+
**Semantics:**
224+
225+
* **soft** (default): Don’t destroy history; just set a **baseline marker** so subsequent reads only return entries *after* the clear.
226+
227+
* Pros: O(1), reversible for auditing (file logging remains intact), less risky if multiple clients are connected.
228+
* **hard**: Drop in‑memory entries (today’s behavior).
229+
230+
* Pros: truly empties the ring buffer;
231+
* Cons: destructive for everyone until new logs arrive.
232+
233+
> You can implement *soft clear* by storing a per‑server (or per‑session) `baselineTimestamp`/generation and filtering on read; file logging stays untouched either way.
234+
235+
**Example prompt that takes advantage of it:**
236+
237+
> “Clear logs (soft) only for session `ab12cd34`. I’ll repro now. In 20 seconds, fetch logs for that session and summarize errors with source and top stack frame.”
238+
239+
---
240+
241+
## Defaults & UX guidance
242+
243+
* **Keep `clear_logs` in v1** exactly as you have it (global hard clear).
244+
Add the optional `session` + `scope` later; it’s backwards‑compatible.
245+
* Encourage assistants to use:
246+
247+
1. `clear_logs`
248+
2. user reproduces →
249+
3. `get_logs({ level:['error','warn'] })` or plain “check frontend logs”.
250+
* Make sure your **resource/tool descriptions** contain NL keywords (“frontend logs”, “console errors”, “hydration”, “network failures”), so planners map user intent correctly.
251+
* **Don’t** let `clear_logs` touch file logs—keep it in‑memory only. The file log (if enabled) is your ground truth trail.
252+
253+
---
254+
255+
### TL;DR
256+
257+
Yes—**keep `clear_logs`**. It’s the single, beginner‑friendly action that makes fresh, noise‑free captures trivial and reliable. Pair it with `get_logs` as the NLP fetch tool and you’ve got a minimal, powerful, and natural workflow. If you want extra polish, add optional `{ session, scope: 'soft' | 'hard' }`—still one tool, but safer and even more useful.

0 commit comments

Comments
 (0)