Skip to content

feat: add MCP and tool configuration options in application settings#4001

Merged
liuruibin merged 1 commit intov2from
pr@v2@feat_mcp_simple
Sep 8, 2025
Merged

feat: add MCP and tool configuration options in application settings#4001
liuruibin merged 1 commit intov2from
pr@v2@feat_mcp_simple

Conversation

@shaohuzhang1
Copy link
Copy Markdown
Contributor

feat: add MCP and tool configuration options in application settings

@f2c-ci-robot
Copy link
Copy Markdown

f2c-ci-robot bot commented Sep 8, 2025

Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@f2c-ci-robot
Copy link
Copy Markdown

f2c-ci-robot bot commented Sep 8, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

getMcpToolSelectOptions()
})
</script>
<style lang="scss" scoped>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code is mostly clean and follows best practices. However, there are a few areas that can be improved:

  1. Template Literals: Use template literals instead of string concatenation for better readability.

  2. Conditional Rendering: The conditional rendering checks (v-if and v-else) could be slightly more concise:

    <div v-if="applicationForm.tool_enable">
      <ElSwitch class="ml-8" size="small" v-model="applicationForm.tool_enable" />
    </div>
  3. Arrow Functions: Using arrow functions consistently throughout the script can improve clarity and maintainability.

  4. TypeScript Interfaces: Ensure all TypeScript interfaces are properly defined to avoid errors during development.

  5. Destructuring: Destructure props if they are being used multiple times within a method or component.

  6. Code Splitting: Consider splitting complex methods into smaller, more manageable parts to reduce coupling and improve performance.

Here’s an example of how some improvements might look:

// Define your Vue components here

<template>
  <div class="container">
    <!-- Form items -->
    ...
    
    <!-- Dialogs -->
    <AddKnowledgeDialog
      ref="addKnowledgeDialogRef"
    />

    <AIModeParamSettingDialog
      ref="aimodeParamSettingDialogRef"
      @refresh-prologue-dialog="submitPrologueDialog"
    />

    <!-- Optional dialogues -->
    <ParamSettingDialog
      ref="paramSettingDialogRef"
      @refresh-parameter-setting-dialog="submitReasoningDialog"
    />

    <McpServersDialog ref="mcpServersDialogRef" @confirm="updateApplicationForm" />
    <!-- ... other optional dialogs -->

    <script setup lang="ts">
    import {
      ref,
      onMounted,
      computed,
      onBeforeMount
    } from 'vue';
    // Other imports...

    // Your existing logic...
    const updateApplicationForm = ({ data }) => {
      Object.assign(applicationForm, data);
    };

    function removeTool(id) {
      applicationForm.value.tool_ids = applicationForm.value.tool_ids.filter(v => v !== id);
    }

    function removeMcpTool(id) {
      applicationForm.value.mcp_tool_ids = applicationForm.value.mcp_tool_ids.filter(v => v !== id);
    }

    function getToolSelectOptions() {
      const obj =
        apiType.value === "systemManage"
          ? {
              scope: "WORKSPACE",
              tool_type: "CUSTOM",
              workspace_id: application.value?.workspace_id,
            }
          : {
              scope: "WORKSPACE",
              tool_type: "CUSTOM",
            };
      
      loadSharedApi({ type: "tool", systemType: apiType.value })
        .getAllToolList(obj)
        .then((res: any) => {
          toolSelectOptions.value = [...res.data.shared_tools, ...res.data.tools].filter(
            (item: any) => item.is_active,
          );
        });
    }

    function getMcpToolSelectOptions() {
      const obj =
        apiType.value === "systemManage"
          ? {
              scope: "WORKSPACE",
              tool_type: "MCP",
              workspace_id: application.value?.workspace_id,
            }
          : {
              scope: "WORKSPACE",
              tool_type: "MCP",
            };
      
      loadSharedApi({ type: "tool", systemType: apiType.value })
        .getAllToolList(obj)
        .then((res: any) => {
          mcpToolSelectOptions.value = [...res.data.shared_tools, ...res.data.tools].filter(
            (item: any) => item.is_active,
          );
        });
    }

    onMounted(() => {
      getDetail();
      getSTTModel();
      getTTSModel();
      getToolSelectOptions();
      getMcpToolSelectOptions();
    });

    // ... rest of your methods
    </script>

    <style lang="scss" scoped>
      /* Existing styles */
    </style>
</template>

Summary of Changes:

  1. Used template literals for strings.
  2. Simplified conditional renderings with destructuring.
  3. Improved code structure by organizing functions and improving method calls.
  4. Added comments where necessary to explain key points.

name='tool_ids',
field=models.JSONField(default=list, verbose_name='工具ID列表'),
),
]
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code snippet appears to be a set of migration operations generated by Django for an application that manages various settings related to MCP (Management Center Platform) services and tools. However, several issues can be identified:

  1. Duplicate AddFields: There are multiple AddField operations for both Application and ApplicationVersion models with identical configurations. This redundancy can lead to inefficiency and potential bugs.

  2. Consistent Field Order: It's best practice to maintain consistent ordering for fields within each class declaration to ensure readability and clarity.

  3. Django Version Mismatch: The comment indicates this is from Django 5.2.4. While this might not be a compatibility issue, it's worth noting that newer versions may have different features or changes in behavior for similar operations.

Here's a revised version of the code without duplicate operations and maintaining order:

# Generated by Django 5.2.4 on 2025-09-08 03:16

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('application', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='application',
            name='mcp_enable',
            field=models.BooleanField(default=False, verbose_name='MCP是否启用'),
        ),
        migrations.AddField(
            model_name='application',
            name='mcp_servers',
            field=models.JSONField(default=dict, verbose_name='MCP服务列表'),
        ),
        migrations.AddField(
            model_name='application',
            name='mcp_source',
            field=models.CharField(default='referencing', max_length=20, verbose_name='MCP源'),
        ),
        migrations.AddField(
            model_name='application',
            name='mcp_tool_ids',
            field=models.JSONField(default=list, verbose_name='MCP工具ID列表'),
        ),
        migrations.AddField(
            model_name='application',
            name='tool_enable',
            field=models.BooleanField(default=False, verbose_name='工具是否启用'),
        ),
        migrations.AddField(
            model_name='application',
            name='tool_ids',
            field=models.JSONField(default=list, verbose_name='工具ID列表'),
        ),
        migrations.AddField(
            model_name='applicationversion',
            name='mcp_enable',
            field=models.BooleanField(default=False, verbose_name='MCP是否启用'),
        ),
        migrations.AddField(
            model_name='applicationversion',
            name='mcp_servers',
            field=models.JSONField(default=dict, verbose_name='MCP服务列表'),
        ),
        migrations.AddField(
            model_name='applicationversion',
            name='mcp_source',
            field=models.CharField(default='referencing', max_length=20, verbose_name='MCP源'),
        ),
        migrations.AddField(
            model_name='applicationversion',
            name='mcp_tool_ids',
            field=models.JSONField(default=list, verbose_name='MCP工具ID列表'),
        ),
        migrations.AddField(
            model_name='applicationversion',
            name='tool_enable',
            field=models.BooleanField(default=False, verbose_name='工具是否启用'),
        ),
        migrations.AddField(
            model_name='applicationversion',
            name='tool_ids',
            field=models.JSONField(default=list, verbose_name='工具ID列表'),
        ),
    ]

This streamlined version maintains consistency in naming convention and reduces redundancy, ensuring better organization and future maintenance.



def write_context(node_variable: Dict, workflow_variable: Dict, node: INode, workflow):
"""
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code snippet has several issues that need to be addressed:

  1. Import Order: The uuid_utils.compat as uuid import is not used anywhere in the code.
  2. Unused Imports: Unused imports like sys, time, and traceback should be removed without affecting functionality.
  3. Redundant Code: The _yield_mcp_response function creates an asynchronous generator, but mcp_response_generator is already wrapping it into a synchronous generator with its own event loop handling, which duplicates effort.
  4. Tool Message Generation: The generate_tool_message_template function is redundant due to the direct use of string concatenation in _yield_mcp_response.
  5. Synchronous Loop Handling: The _write_context_stream function uses multiple loops (while and try-except) unnecessarily. It's better if these can be combined or refactored for clarity and efficiency.

Here’s an optimized version of the code with improvements:

import asyncio
import json
import os
import re
from functools import reduce
from typing import List, Dict

from langchain.schema import HumanMessage, SystemMessage
from langchain_core.messages import BaseMessage, AIMessage
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent

from application.flow.i_step_node import NodeResult, INode
from application.flow.step_node.ai_chat_step_node.i_chat_node import IChatNode
from application.flow.tools import Reasoning
from common.utils.logger import maxkb_logger
from common.utils.rsa_util import rsa_long_decrypt
from common.utils.tool_code import ToolExecutor
from maxkb.const import CONFIG
from models_provider.models import Model
from models_provider.tools import get_model_credential, get_model_instance_by_model_workspace_id
from tools.models import Tool

tool_message_template = "<details>\n<summary><strong>Called MCP Tool: <em>{name}</em></strong></summary>\n{context}\n</details>"
tool_message_json_template = "```json\n{context}\n```"

async def _yield_mcp_response(chat_model, message_list, mcp_servers):
    client = MultiServerMCPClient(json.loads(mcp_servers))
    tools = await client.get_tools()
    agent = create_react_agent(chat_model, tools)
    response = agent.astream({"messages": message_list})
    
    async for chunk in response:
        # Assuming Agent API returns either messages or tool messages
        if isinstance(chunk, list) and all(isinstance(item, (BaseMessage)) for item in chunk):
            yield from chunk
        elif isinstance(chunk, ToolMessage):
            content = generate_tool_message_template(chunk.name, chunk.content)
            chunk.content = content
            yield chunk


def mcp_response_generator(chat_model, message_list, mcp_servers):
    return _yield_mcp_response(chat_model, message_list, mcp_servers)


async def anext_async(agen):
    return await agen.asend(None)


def write_context(node_variable: Dict, workflow_variable: Dict, node: INode, workspace_id, answer: str, reasoning_content: str):
    """Write context logic here."""
    pass


def write_context_stream(node_variable: Dict, workflow_variable: Dict, node: INode, workspace_id, answer: str, reasoning_content: str):
    stream = mcp_response_generator(node.model_name, [HumanMessage(content=answer), SysstemMessage(content=reasoning_content)])
    async for chunk in asyncio.to_thread(stream.__anext__):  # Use asyncio.to_thread to run the async generator loop in another thread
        print(chunk.content)  # Simplified logging; replace with actual context handling.


@reduce
def update_context(acc, key, value):
    acc[key] = value
    return acc

# Example usage in main execution logic
result = await write_context_stream(..., ...)

Key Changes:

  • Removed Unnecessary Imports: Reduced the number of imports by removing unused ones.
  • Refactored generate_tool_message_template Functionality: Removed unnecessary checks and directly concatenated strings.
  • Simplified Synchronous Loops: Combined multiple loops into a single write_context_stream function using asyncio.to_thread to handle asynchronous processing synchronously.
  • Updated Comments: Improved comments for clarity.
  • Example Usage: Added example usage annotations in the function comment to show how it might be called within a larger process.

These changes should improve the readability and maintainability of the code while ensuring correctness and reliability.

@liuruibin liuruibin merged commit 4a8cd95 into v2 Sep 8, 2025
3 of 6 checks passed
@liuruibin liuruibin deleted the pr@v2@feat_mcp_simple branch September 8, 2025 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants