直接放代码 吾爱大佬出品
// ==UserScript==
// [url=home.php?mod=space&uid=170990]@name[/url] DeepSeek Fiddler 增强版
// [url=home.php?mod=space&uid=467642]@namespace[/url] http://tampermonkey.net/
// [url=home.php?mod=space&uid=1248337]@version[/url] 0.2
// @description DeepSeek + Fiddler 抓包分析集成
// [url=home.php?mod=space&uid=686208]@AuThor[/url] Your Name
// [url=home.php?mod=space&uid=195849]@match[/url] https://chat.deepseek.com/*
// [url=home.php?mod=space&uid=609072]@grant[/url] GM_xmlhttpRequest
// [url=home.php?mod=space&uid=67665]@connect[/url] localhost
// ==/UserScript==
window.shouldSendAfterStream = false;
window.commandResults = '';
window.MCP_SEND_PLACEHOLDER = '发送命令xxxoooxxx';
(function() {
'use strict';
// ==================== 配置 ====================
constMCP_SERVER = 'http://localhost:8024/mcp';
constFIDDLER_SERVER = 'http://localhost:9876';
// ==================== UI 组件 ====================
let overlay = null;
let overlayText = null;
let controlPanel = null;
let fiddlerStatus = { total: 0, pending: 0 };
functioncreateOverlay() {
if (overlay) return;
overlay = document.createElement('div');
overlay.id = 'mcp-overlay';
overlay.style.cssText = `position: fixed; transform: translateY( 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); display: none; justify-content: center; align-item)s: center; z-index: 9999; font-family: Arial, sans-serif; color: white; font-size: 18px; text-align: center;`;
overlayText = document.createElement('div');
overlayText.id = 'mcp-overlay-text';
overlayText.innerHTML = '🔄 处理中...';
overlayText.style.cssText = `background-color: rgba(0, 0, 0, 0.8); padding: 20px; border-radius: 10px; position: relative;`;
const closeBtn = document.createElement('button');
closeBtn.textContent = '×';
closeBtn.style.cssText = `position: absolute; transform: translateY( 8px; right: 12px; background: transparent; border: none; color: #fff; font-size: 20px; cursor: pointer;`;
closeBtn.addEventListener('click', hideOverlay);
overlayText.appendChild(closeBtn);
overlay.appendChild(overlayText);
document.body.appendChild(overlay);
}
functionshowOverlay(text = '🔄 处理中...') {
if (!overlay) createOverlay();
overlayText.innerHTML = text + '<button style="position: absolute; top: 8px; right: 12px; background: transparent; border: none; color: #fff; font-size: 20px; cursor: pointer;">×</button>';
overlay.style.display = 'flex';
}
functionhideOverlay() { if (overlay) overlay.style.display = 'none'; }
// ==================== 控制面板 ====================
functioncreateControlPanel() {
if (controlPanel) return;
controlPanel = document.createElem)ent('div');
controlPanel.id = 'fiddler-control-panel';
controlPanel.style.cssText = `
position: fixed; transform: translateY( 20px; right: 20px; z-index: 10000;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px; padding: 15px; min-width: 200px;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
font-family: Arial, sans-serif; color: white;
`;
controlPanel.innerHTML = `
<div style="font-size: 16px; font-weight: bold; margin-bottom: 12px; display: flex; align-item)s: center;">
<span style="margin-right: 8px;">🔧</span> MCP 控制台
</div>
<div id="fiddler-status" style="font-size: 12px; margin-bottom: 12px; padding: 8px; background: rgba(255,255,255,0.1); border-radius: 6px;">
<div>📊 请求: <span id="status-total">0</span> | 待分析: <span id="status-pending">0</span></div>
</div>
<div style="display: flex; flex-direction: column; gap: 8px;">
<button id="btn-init" style="padding: 10px; border: none; border-radius: 6px; background: #4CAF50; color: white; cursor: pointer; font-weight: bold; transition: all 0.3s;">
🚀 初始化 MCP
</button>
<button id="btn-analyze" style="padding: 10px; border: none; border-radius: 6px; background: #2196F3; color: white; cursor: pointer; font-weight: bold; transition: all 0.3s;">
📦 分析 Fiddler 请求
</button>
<button id="btn-refresh" style="padding: 10px; border: none; border-radius: 6px; background: #FF9800; color: white; cursor: pointer; font-weight: bold; transition: all 0.3s;">
🔄 刷新状态
</button>
<button id="btn-clear" style="padding: 10px; border: none; border-radius: 6px; background: #f44336; color: white; cursor: pointer; font-weight: bold; transition: all 0.3s;">
🗑️ 清空数据
</button>
</div>
<div style="margin-top: 12px; font-size: 10px; opacity: 0.7; text-align: center;">
按 Ctrl+Shift+F 切换面板显示
</div>
`;
document.body.appendChild(controlPanel);
// 绑定事件
document.getElementById('btn-init').addEventListener('click', initializeMCP);
document.getElementById('btn-analyze').addEventListener('click', analyzeFiddlerRequests);
document.getElementById('btn-refresh').addEventListener('click', refreshFiddlerStatus);
document.getElementById('btn-clear').addEventListener('click', clearFiddlerData);
// 按钮悬停效果
controlPanel.querySelectorAll('button').forEach(btn => {
btn.addEventListener('mouseenter', () => btn.style.transform = 'scale(1.02)');
btn.addEventListener('mouseleave', () => btn.style.transform = 'scale(1)');
});
// 初始刷新状态
refreshFiddlerStatus();
// 定时刷新
setInterval(refreshFiddlerStatus, 5000);
}
// ==================== Fiddler 相关功能 ====================
asyncfunctionrefreshFiddlerStatus() {
try {
const response = awaitfetch(FIDDLER_SERVER + '/status');
if (response.ok) {
const data = await response.json();
fiddlerStatus = data;
document.getElementById('status-total').textContent = data.total || 0;
document.getElementById('status-pending').textContent = data.pending || 0;
// 更新按钮状态
const analyzeBtn = document.getElementById('btn-analyze');
if (data.pending > 0) {
analyzeBtn.style.background = '#4CAF50';
analyzeBtn.textContent = `📦 分析 ${data.pending} 个请求`;
} else {
analyzeBtn.style.background = '#2196F3';
analyzeBtn.textContent = '📦 分析 Fiddler 请求';
}
}
} catch (e) {
document.getElementById('status-total').textContent = '-';
document.getElementById('status-pending').textContent = '-';
}
}
asyncfunctionanalyzeFiddlerRequests() {
if (fiddlerStatus.pending === 0) {
alert('没有待分析的请求。请先在 Fiddler 中发送请求到 MCP。');
return;
}
// 调用 fiddler_get_next 工具获取待分析请求
showOverlay('📦 正在获取 Fiddler 请求...');
try {
const result = awaitcallMCPTool('fiddler_get_next', { count: 5 });
if (result.success) {
const text = result.result?.content?.[0]?.text || JSON.stringify(result.result);
window.commandResults = `
📦 Fiddler 请求分析任务:
---
${text}
---
`;
hideOverlay();
simulateTypeAndSend(window.MCP_SEND_PLACEHOLDER);
} else {
hideOverlay();
alert('获取请求失败: ' + result.error);
}
} catch (e) {
hideOverlay();
alert('获取请求出错: ' + e.message);
}
}
asyncfunctionclearFiddlerData() {
if (!confirm('确定要清空所有 Fiddler 数据吗?')) return;
try {
const response = awaitfetch(FIDDLER_SERVER + '/clear', { method: 'POST', body: '{}' });
if (response.ok) {
refreshFiddlerStatus();
alert('已清空所有数据');
}
} catch (e) {
alert('清空失败: ' + e.message);
}
}
// ==================== MCP 客户端 ====================
functioncallMCPTool(toolName, params) {
returnnewPromise((resolve) => {
GM_xmlhttpRequest({
method: 'POST',
url: MCP_SERVER,
headers: { 'Content-Type': 'application/json; charset=utf-8' },
data: JSON.stringify({
jsonrpc: '2.0',
method: 'tools/call',
params: { name: toolName, arguments: params },
id: Date.now()
}),
onload: (res) => {
try {
const response = JSON.parse(res.responseText);
resolve(response.error ?
{ success: false, error: response.error.message } :
{ success: true, result: response.result });
} catch (e) {
resolve({ success: false, error: '响应解析失败: ' + e.message });
}
},
onerror: (err) =>resolve({ success: false, error: err.statusText || '网络失败' }),
ontimeout: () =>resolve({ success: false, error: '请求超时' })
});
});
}
// ==================== 模拟输入 ====================
functionsimulateTypeAndSend(message) {
if (window.isAutoSending) return;
window.isAutoSending = true;
const textarea = document.querySelector('textarea._27c9245') || document.querySelector('textarea') || document.querySelector('[contenteditable="true"]');
if (!textarea) { window.isAutoSending = false; return; }
textarea.focus();
const isPlaceholder = message === window.MCP_SEND_PLACEHOLDER;
const fullMsg = isPlaceholder ? message : (window.commandResults ? (window.commandResults + "\n" + message) : message);
if (!isPlaceholder) {
window.commandResults = '';
}
if (textarea.isContentEditable) {
textarea.innerHTML = '';
document.execCommand('insertText', false, fullMsg);
} else {
const nativeSetter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(textarea), 'value')?.set;
if (nativeSetter) nativeSetter.call(textarea, fullMsg);
textarea.dispatchEvent(newEvent('input', { bubbles: true }));
}
setTimeout(() => {
const sendButtons = Array.from(document.querySelectorAll('div[role="button"]'))
.filter(btn => btn.querySelector('svg path')?.getAttribute('d')?.includes('V15.0431'));
if (sendButtons.length > 0) {
sendButtons[0].click();
} else {
textarea.dispatchEvent(newKeyboardEvent('keydown', { key: 'Enter', ctrlKey: true, bubbles: true }));
}
setTimeout(() => { window.isAutoSending = false; }, 300);
}, 300);
}
// ==================== MCP 初始化 ====================
functioninitializeMCP() {
window.commandResults = '\n📊 MCP初始化成功\n---\n正在获取角色卡...\n---\n';
simulateTypeAndSend(window.MCP_SEND_PLACEHOLDER);
callMCPTool('get_role_card', {}).then(result => {
if (result.success) {
const text = result.result?.content?.[0]?.text || result.result?.content || JSON.stringify(result.result);
window.commandResults = `
📊 MCP初始化成功
---
${text}
---
`;
}
});
const btn = document.getElementById('btn-init');
if (btn) {
btn.textContent = '✅ 已初始化';
btn.style.background = '#888';
setTimeout(() => {
btn.textContent = '🚀 初始化 MCP';
btn.style.background = '#4CAF50';
}, 3000);
}
}
// ==================== SSE 监控 & 工具调用检测 ====================
let activeToolCalls = [];
constREPLACE_RULES = [
{
original: /发送命令xxxoooxxx/g,
replacement: function() { returnwindow.commandResults || ''; }
},
];
functiondeepExtract(obj) {
if (typeof obj === 'string') return obj;
if (Array.isArray(obj)) return obj.map(deepExtract).join('');
if (typeof obj === 'object' && obj !== null) {
const keys = ['v', 'content', 'text', 'fragments'];
for (const k of keys) {
if (obj[k]) returndeepExtract(obj[k]);
}
returnObject.values(obj).map(deepExtract).join('');
}
return'';
}
functionsafeJSONParse(jsonStr) {
try {
let cleanStr = jsonStr.trim();
if (cleanStr.length >= 2) {
const first = cleanStr[0];
const last = cleanStr[cleanStr.length - 1];
const wrappers = ['"', '\'', '`'];
if (wrappers.includes(first) && first === last) {
const inner = cleanStr.slice(1, -1).trim();
if ((inner.startsWith('{') && inner.endsWith('}')) || (inner.startsWith('[') && inner.endsWith(']'))) {
cleanStr = inner;
}
}
}
returnJSON.parse(cleanStr);
} catch (e) {
returnnull;
}
}
functionprocessBuffer(state) {
const lines = state.sseBuffer.split('\n');
state.sseBuffer = lines.pop() || '';
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || !trimmed.startsWith('data: ')) continue;
const jsonStr = trimmed.substring(6);
if (jsonStr === '[DONE]') continue;
try {
const json = JSON.parse(jsonStr);
let text = '';
if (json.p === 'response/fragments/-1/content' && json.o === 'APPEND' && typeof json.v === 'string') {
text = json.v;
} elseif (json.p === 'response' && json.o === 'BATCH' && Array.isArray(json.v)) {
for (const op of json.v) {
if (op.p === 'fragments' && op.o === 'APPEND' && Array.isArray(op.v)) {
for (const frag of op.v) {
if (frag && typeof frag.content === 'string') {
text += frag.content;
}
}
}
}
} else {
text = deepExtract(json);
}
if (text) {
state.contentAccumulator += text;
checkToolCalls(state);
}
} catch (e) {}
}
}
functioncheckToolCalls(state) {
const strictRegex = /(?:^|\r?\n)[ \t]*start:\s*(\{[\s\S]*?\})\s*end(?![A-Za-z0-9_])/g;
const looseRegex = /start:\s*(\{[\s\S]*?\})\s*end(?![A-Za-z0-9_])/g;
let match;
construnOnce = (regex) => {
while ((match = regex.exec(state.contentAccumulator)) !== null) {
const jsonContent = match[1];
const toolData = safeJSONParse(jsonContent);
if (!toolData || !toolData.name) continue;
executeTool(toolData.name, toolData.arguments || {});
state.contentAccumulator =
state.contentAccumulator.slice(0, match.index) +
`\n[Processed:${toolData.name}]\n` +
state.contentAccumulator.slice(match.index + match[0].length);
regex.lastIndex = Math.max(0, match.index);
}
};
runOnce(strictRegex);
runOnce(looseRegex);
constMAX_BUFFER = 20000;
if (state.contentAccumulator.length > MAX_BUFFER) {
state.contentAccumulator = state.contentAccumulator.slice(-10000);
}
}
asyncfunctionexecuteTool(name, args) {
const callId = Date.now() + Math.random();
activeToolCalls.push(callId);
// Fiddler 相关工具不显示弹窗
const silentTools = ['get_role_card', 'fiddler_mark_done'];
if (!silentTools.includes(name)) {
showOverlay(`🔧 执行工具: ${name}`);
}
try {
const result = awaitcallMCPTool(name, args);
let text = "执行完成";
if (result.success) {
text = result.result?.content?.[0]?.text || result.result?.stdout || JSON.stringify(result.result);
if (name === 'get_role_card') {
window.commandResults = `
📊 MCP初始化成功
---
${text}
---
`;
} elseif (name === 'fiddler_mark_done') {
// 标记完成后刷新状态
refreshFiddlerStatus();
window.commandResults += `\n✅ ${text}\n---\n`;
} else {
window.commandResults += `
📊 工具 ${name} 结果:
${text}
---
`;
}
} else {
window.commandResults += `\n❌ 工具 ${name} 失败: ${result.error}\n---\n`;
}
} catch (e) {
window.commandResults += `\n❌ 工具 ${name} 异常: ${e.message}\n---\n`;
} finally {
activeToolCalls = activeToolCalls.filter(id => id !== callId);
}
}
// ==================== XHR 拦截器 ====================
const originalOpen = XMLHttpRequest.prototype.open;
const originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function(method, url) {
this._url = url;
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function(body) {
if (this._url && this._url.includes('/api/v0/chat/completion') && body) {
try {
if (typeof body === 'string') {
const data = JSON.parse(body);
const originalPrompt = typeof data.prompt === 'string' ? data.prompt : null;
if (originalPrompt != null) {
let modifiedPrompt = originalPrompt;
REPLACE_RULES.forEach(rule => {
rule.original.lastIndex = 0;
if (rule.original.test(originalPrompt)) {
modifiedPrompt = originalPrompt.replace(rule.original, rule.replacement);
}
});
if (modifiedPrompt !== originalPrompt) {
data.prompt = modifiedPrompt;
body = JSON.stringify(data);
setTimeout(() => {
window.commandResults = '';
window.shouldSendAfterStream = false;
}, 1000);
}
}
}
} catch (e) {}
}
if (this._url && this._url.includes('/api/v0/chat/completion')) {
this._mcpSSEState = {
processedIndex: 0,
sseBuffer: '',
contentAccumulator: '',
};
this.addEventListener('progress', () => {
if (this.readyState === 3 && this.responseText && this._mcpSSEState) {
const state = this._mcpSSEState;
const newData = this.responseText.substring(state.processedIndex);
state.processedIndex = this.responseText.length;
state.sseBuffer += newData;
processBuffer(state);
}
});
this.addEventListener('loadend', () => {
const finalCheck = setInterval(() => {
if (activeToolCalls.length === 0) {
clearInterval(finalCheck);
if (window.commandResults) {
hideOverlay();
simulateTypeAndSend(window.MCP_SEND_PLACEHOLDER);
}
}
}, 500);
});
}
return originalSend.call(this, body);
};
// ==================== 快捷键 ====================
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.shiftKey && e.key === 'F') {
e.preventDefault();
if (controlPanel) {
controlPanel.style.display = controlPanel.style.display === 'none' ? 'block' : 'none';
}
}
});
// ==================== 初始化 ====================
createControlPanel();
})();Fiddler 发送抓包
DeepSeek 分析


建议看原文
https://www.52pojie.cn/thread-2088427-1-3.html