首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Fiddler+白嫖deepseek MCP

Fiddler+白嫖deepseek MCP

作者头像
小田测测看
发布2026-06-17 19:28:21
发布2026-06-17 19:28:21
620
举报

直接放代码 吾爱大佬出品

代码语言:javascript
复制
// ==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;">&#128295;</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>&#128202; 请求: <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;">
                    &#128640; 初始化 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;">
                    &#128230; 分析 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;">
                    &#128260; 刷新状态
                </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;">
                    &#128465;&#65039; 清空数据
                </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 = `&#128230; 分析 ${data.pending} 个请求`;
                } else {
                    analyzeBtn.style.background = '#2196F3';
                    analyzeBtn.textContent = '&#128230; 分析 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('&#128230; 正在获取 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 = `
&#128230; 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&#128202; 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 = `
&#128202; MCP初始化成功
---
${text}
---
`;
            }
        });

        const btn = document.getElementById('btn-init');
        if (btn) {
            btn.textContent = '&#9989; 已初始化';
            btn.style.background = '#888';
            setTimeout(() => {
                btn.textContent = '&#128640; 初始化 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(`&#128295; 执行工具: ${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 = `
&#128202; MCP初始化成功
---
${text}
---
`;
                } elseif (name === 'fiddler_mark_done') {
                    // 标记完成后刷新状态
                    refreshFiddlerStatus();
                    window.commandResults += `\n&#9989; ${text}\n---\n`;
                } else {
                    window.commandResults += `
&#128202; 工具 ${name} 结果:
${text}
---
`;
                }
            } else {
                window.commandResults += `\n&#10060; 工具 ${name} 失败: ${result.error}\n---\n`;
            }
        } catch (e) {
            window.commandResults += `\n&#10060; 工具 ${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 发送抓包

  • • 抓包后选中请求
  • • 右键 → MCP工具 → 发送选中到MCP
  • • 看到提示"已发送 x 个请求"

DeepSeek 分析

  • • 打开 https://chat.deepseek.com/
  • • 点击右上角 **📦 分析 Fiddler 请求

建议看原文

https://www.52pojie.cn/thread-2088427-1-3.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-02-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程拾光 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档