Commit 61ce29cd authored by jan.koester's avatar jan.koester
Browse files

mcp support editor

parent e6f85436
Loading
Loading
Loading
Loading
+1 −0
Changes for editor/CMakeLists.txt: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ add_executable(blogi-editor
    src/webedit_session.cpp
    src/webedit_server.cpp
    src/webedit_api.cpp
    src/webedit_mcp.cpp
    src/htmlimport.cpp
)

+20 −0
Changes for editor/html/index.html: 20 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -330,6 +330,7 @@
                    <li class="set-nav-item active" data-section="language" data-i18n="Language">Sprache</li>
                    <li class="set-nav-item" data-section="ai" data-i18n="I18N_AI">KI</li>
                    <li class="set-nav-item" data-section="connection" data-i18n="I18N_CONNECTION">Verbindung</li>
                    <li class="set-nav-item" data-section="mcp" data-i18n="I18N_MCP">MCP</li>
                </ul>
            </div>
            <div class="set-content" id="settings-content">
@@ -383,6 +384,25 @@
                    </div>
                </div>

                <!-- MCP API tokens section -->
                <div id="settings-mcp" class="set-section" style="display:none">
                    <h4 data-i18n="I18N_MCP">MCP</h4>
                    <p class="hint" data-i18n="I18N_MCP_HINT">Mit einem API-Token k&ouml;nnen externe MCP-Clients (z.B. Claude Desktop/Code) diesen Editor per Model Context Protocol steuern. Sendet der Client "Authorization: Bearer &lt;Token&gt;" an /mcp.</p>
                    <div class="set-field">
                        <label data-i18n="I18N_MCP_LABEL">Bezeichnung</label>
                        <input type="text" id="settings-mcp-label" placeholder="z.B. Claude Desktop">
                    </div>
                    <div class="set-field">
                        <button id="btn-settings-mcp-create" class="set-save-btn" data-i18n="I18N_MCP_CREATE">Token erzeugen</button>
                        <span id="settings-mcp-status" class="set-status"></span>
                    </div>
                    <div class="set-field" id="settings-mcp-new-token-wrap" style="display:none">
                        <label data-i18n="I18N_MCP_NEW_TOKEN">Neues Token (jetzt kopieren, wird nicht erneut angezeigt)</label>
                        <input type="text" id="settings-mcp-new-token" readonly onclick="this.select()">
                    </div>
                    <div id="settings-mcp-list" class="conn-list"></div>
                </div>

                <!-- Plugin settings section (loaded dynamically) -->
                <div id="settings-plugin" class="set-section" style="display:none">
                    <div id="settings-plugin-content"></div>
+13 −0
Changes for editor/html/js/api.js: 13 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -336,6 +336,19 @@ var EditorApi = (function() {
            return request('DELETE', '/api/connection/delete/' + id);
        },

        // MCP API tokens
        getMcpTokens: function() {
            return request('GET', '/api/mcp/tokens');
        },

        createMcpToken: function(label) {
            return request('POST', '/api/mcp/tokens', { label: label });
        },

        revokeMcpToken: function(id) {
            return request('DELETE', '/api/mcp/tokens/' + id);
        },

        connectToConnection: function(id) {
            return request('POST', '/api/connection/connect/' + id, {}).then(function(resp) {
                if (resp && resp.blogUrl && resp.authid) {
+65 −0
Changes for editor/html/js/editor.js: 65 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -1110,6 +1110,10 @@
            document.getElementById('settings-ai-status').textContent = '';
        });

        document.getElementById('settings-mcp-new-token-wrap').style.display = 'none';
        document.getElementById('settings-mcp-label').value = '';
        loadMcpTokens();

        // Load plugin settings nav items
        var nav = document.querySelector('#settings-dialog .set-nav');
        // Remove previously added plugin nav items
@@ -1140,6 +1144,47 @@
        document.getElementById('settings-dialog').showModal();
    }

    function loadMcpTokens() {
        EditorApi.getMcpTokens().then(function(resp) {
            renderMcpTokenList(resp.tokens || []);
        }).catch(function() {});
    }

    function renderMcpTokenList(tokens) {
        var list = document.getElementById('settings-mcp-list');
        list.innerHTML = '';

        if (tokens.length === 0) {
            list.innerHTML = '<p class="hint" style="padding:0.5em">' +
                I18n.t('I18N_MCP_NO_TOKENS', 'Keine Tokens') + '</p>';
            return;
        }

        tokens.forEach(function(token) {
            var item = document.createElement('div');
            item.className = 'conn-item';

            var label = document.createElement('span');
            label.textContent = (token.label || I18n.t('I18N_MCP_UNNAMED', '(unbenannt)')) +
                ' — ' + (token.created || '') +
                (token.last_used ? ' • ' + I18n.t('I18N_MCP_LAST_USED', 'zuletzt verwendet') +
                    ': ' + token.last_used : '');
            item.appendChild(label);

            var del = document.createElement('button');
            del.textContent = '✕';
            del.title = I18n.t('I18N_MCP_REVOKE', 'Widerrufen');
            del.style.marginLeft = 'auto';
            del.addEventListener('click', function(e) {
                e.stopPropagation();
                EditorApi.revokeMcpToken(token.id).then(loadMcpTokens);
            });
            item.appendChild(del);

            list.appendChild(item);
        });
    }

    function loadPluginSettingsSection(pluginId) {
        var contentEl = document.getElementById('settings-plugin-content');
        contentEl.innerHTML = '<p class="hint">Lade...</p>';
@@ -1244,6 +1289,26 @@
            document.getElementById('settings-dialog').close();
            openConnectionManager();
        });

        // MCP token creation
        document.getElementById('btn-settings-mcp-create').addEventListener('click', function() {
            var status = document.getElementById('settings-mcp-status');
            var label = document.getElementById('settings-mcp-label').value;
            status.textContent = I18n.t('I18N_SAVING', 'Saving...');
            EditorApi.createMcpToken(label).then(function(resp) {
                status.textContent = '';
                document.getElementById('settings-mcp-label').value = '';
                var wrap = document.getElementById('settings-mcp-new-token-wrap');
                var tokenInput = document.getElementById('settings-mcp-new-token');
                tokenInput.value = resp.token;
                wrap.style.display = 'block';
                tokenInput.select();
                loadMcpTokens();
            }).catch(function() {
                status.textContent = I18n.t('I18N_SAVE_FAILED', 'Save failed');
                status.className = 'set-status error';
            });
        });
    }

    // --- AI dialog ---
+608 −121

File changed.

Preview size limit exceeded, changes collapsed.

Loading