mirror of
https://github.com/langgenius/dify.git
synced 2026-04-26 13:45:57 +08:00
feat: add unique id in mcp tool dsl
This commit is contained in:
@ -630,6 +630,7 @@ class ToolProviderMCPApi(Resource):
|
||||
parser.add_argument("icon", type=str, required=True, nullable=False, location="json")
|
||||
parser.add_argument("icon_type", type=str, required=True, nullable=False, location="json")
|
||||
parser.add_argument("icon_background", type=str, required=False, nullable=True, location="json", default="")
|
||||
parser.add_argument("server_identifier", type=str, required=True, nullable=False, location="json")
|
||||
args = parser.parse_args()
|
||||
user = current_user
|
||||
if not validators.url(args["server_url"]):
|
||||
@ -643,6 +644,7 @@ class ToolProviderMCPApi(Resource):
|
||||
icon_type=args["icon_type"],
|
||||
icon_background=args["icon_background"],
|
||||
user_id=user.id,
|
||||
server_identifier=args["server_identifier"],
|
||||
)
|
||||
)
|
||||
|
||||
@ -657,21 +659,13 @@ class ToolProviderMCPApi(Resource):
|
||||
parser.add_argument("icon_type", type=str, required=True, nullable=False, location="json")
|
||||
parser.add_argument("icon_background", type=str, required=False, nullable=True, location="json")
|
||||
parser.add_argument("provider_id", type=str, required=True, nullable=False, location="json")
|
||||
parser.add_argument("server_identifier", type=str, required=True, nullable=False, location="json")
|
||||
args = parser.parse_args()
|
||||
if not validators.url(args["server_url"]):
|
||||
if "[__HIDDEN__]" in args["server_url"]:
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Server URL is not valid.")
|
||||
MCPToolManageService.update_mcp_provider(
|
||||
tenant_id=current_user.current_tenant_id,
|
||||
name=args["name"],
|
||||
server_url=args["server_url"],
|
||||
icon=args["icon"],
|
||||
icon_type=args["icon_type"],
|
||||
icon_background=args["icon_background"],
|
||||
provider_id=args["provider_id"],
|
||||
)
|
||||
return {"result": "success"}
|
||||
|
||||
@setup_required
|
||||
|
||||
@ -414,25 +414,6 @@ class ToolManager:
|
||||
tool_entity.runtime.runtime_parameters.update(runtime_parameters)
|
||||
return tool_entity
|
||||
|
||||
@classmethod
|
||||
def get_tool_runtime_from_mcp(
|
||||
cls,
|
||||
tenant_id: str,
|
||||
provider_id: str,
|
||||
tool_name: str,
|
||||
) -> Tool:
|
||||
"""
|
||||
get tool runtime from mcp
|
||||
"""
|
||||
return cls.get_tool_runtime(
|
||||
provider_type=ToolProviderType.MCP,
|
||||
provider_id=provider_id,
|
||||
tool_name=tool_name,
|
||||
tenant_id=tenant_id,
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
tool_invoke_from=ToolInvokeFrom.PLUGIN,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_hardcoded_provider_icon(cls, provider: str) -> tuple[str, str]:
|
||||
"""
|
||||
@ -673,7 +654,7 @@ class ToolManager:
|
||||
)
|
||||
result_providers[f"workflow_provider.{user_provider.name}"] = user_provider
|
||||
if "mcp" in filters:
|
||||
mcp_providers = MCPToolManageService.retrieve_mcp_tools(tenant_id)
|
||||
mcp_providers = MCPToolManageService.retrieve_mcp_tools(tenant_id, for_list=True)
|
||||
for mcp_provider in mcp_providers:
|
||||
result_providers[f"mcp_provider.{mcp_provider.name}"] = mcp_provider
|
||||
|
||||
@ -724,7 +705,7 @@ class ToolManager:
|
||||
provider: MCPToolProvider | None = (
|
||||
db.session.query(MCPToolProvider)
|
||||
.filter(
|
||||
MCPToolProvider.id == provider_id,
|
||||
MCPToolProvider.server_identifier == provider_id,
|
||||
MCPToolProvider.tenant_id == tenant_id,
|
||||
)
|
||||
.first()
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
"""add mcp server tool and app server
|
||||
|
||||
Revision ID: 9e4b39294dc8
|
||||
Revises: 4474872b0ee6
|
||||
Create Date: 2025-06-12 10:58:14.199433
|
||||
Revision ID: 58eb7bdb93fe
|
||||
Revises: 0ab65e1cc7fa
|
||||
Create Date: 2025-06-25 09:36:07.510570
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
@ -11,7 +11,7 @@ import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '9e4b39294dc8'
|
||||
revision = '58eb7bdb93fe'
|
||||
down_revision = '0ab65e1cc7fa'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
@ -30,11 +30,14 @@ def upgrade():
|
||||
sa.Column('parameters', sa.Text(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='app_mcp_server_pkey')
|
||||
sa.PrimaryKeyConstraint('id', name='app_mcp_server_pkey'),
|
||||
sa.UniqueConstraint('tenant_id', 'app_id', name='unique_app_mcp_server_tenant_app_id'),
|
||||
sa.UniqueConstraint('tenant_id', 'server_code', name='unique_app_mcp_server_tenant_server_code')
|
||||
)
|
||||
op.create_table('tool_mcp_providers',
|
||||
sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False),
|
||||
sa.Column('name', sa.String(length=40), nullable=False),
|
||||
sa.Column('server_identifier', sa.String(length=24), nullable=False),
|
||||
sa.Column('server_url', sa.Text(), nullable=False),
|
||||
sa.Column('server_url_hash', sa.String(length=64), nullable=False),
|
||||
sa.Column('icon', sa.String(length=255), nullable=True),
|
||||
@ -47,6 +50,7 @@ def upgrade():
|
||||
sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP(0)'), nullable=False),
|
||||
sa.PrimaryKeyConstraint('id', name='tool_mcp_provider_pkey'),
|
||||
sa.UniqueConstraint('tenant_id', 'name', name='unique_mcp_provider_name'),
|
||||
sa.UniqueConstraint('tenant_id', 'server_identifier', name='unique_mcp_provider_server_identifier'),
|
||||
sa.UniqueConstraint('tenant_id', 'server_url_hash', name='unique_mcp_provider_server_url')
|
||||
)
|
||||
|
||||
@ -1443,7 +1443,11 @@ class EndUser(Base, UserMixin):
|
||||
|
||||
class AppMCPServer(Base):
|
||||
__tablename__ = "app_mcp_servers"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("id", name="app_mcp_server_pkey"),)
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="app_mcp_server_pkey"),
|
||||
db.UniqueConstraint("tenant_id", "app_id", name="unique_app_mcp_server_tenant_app_id"),
|
||||
db.UniqueConstraint("tenant_id", "server_code", name="unique_app_mcp_server_tenant_server_code"),
|
||||
)
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
tenant_id = db.Column(StringUUID, nullable=False)
|
||||
app_id = db.Column(StringUUID, nullable=False)
|
||||
|
||||
@ -201,11 +201,14 @@ class MCPToolProvider(Base):
|
||||
db.PrimaryKeyConstraint("id", name="tool_mcp_provider_pkey"),
|
||||
db.UniqueConstraint("tenant_id", "server_url_hash", name="unique_mcp_provider_server_url"),
|
||||
db.UniqueConstraint("tenant_id", "name", name="unique_mcp_provider_name"),
|
||||
db.UniqueConstraint("tenant_id", "server_identifier", name="unique_mcp_provider_server_identifier"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
# name of the mcp provider
|
||||
name: Mapped[str] = mapped_column(db.String(40), nullable=False)
|
||||
# server identifier of the mcp provider
|
||||
server_identifier: Mapped[str] = mapped_column(db.String(24), nullable=False)
|
||||
# encrypted url of the mcp provider
|
||||
server_url: Mapped[str] = mapped_column(db.Text, nullable=False)
|
||||
# hash of server_url for uniqueness check
|
||||
|
||||
@ -50,7 +50,14 @@ class MCPToolManageService:
|
||||
|
||||
@staticmethod
|
||||
def create_mcp_provider(
|
||||
tenant_id: str, name: str, server_url: str, user_id: str, icon: str, icon_type: str, icon_background: str
|
||||
tenant_id: str,
|
||||
name: str,
|
||||
server_url: str,
|
||||
user_id: str,
|
||||
icon: str,
|
||||
icon_type: str,
|
||||
icon_background: str,
|
||||
server_identifier: str,
|
||||
) -> ToolProviderApiEntity:
|
||||
server_url_hash = hashlib.sha256(server_url.encode()).hexdigest()
|
||||
existing_provider = (
|
||||
@ -80,20 +87,24 @@ class MCPToolManageService:
|
||||
authed=False,
|
||||
tools="[]",
|
||||
icon=json.dumps({"content": icon, "background": icon_background}) if icon_type == "emoji" else icon,
|
||||
server_identifier=server_identifier,
|
||||
)
|
||||
db.session.add(mcp_tool)
|
||||
db.session.commit()
|
||||
return ToolTransformService.mcp_provider_to_user_provider(mcp_tool)
|
||||
|
||||
@staticmethod
|
||||
def retrieve_mcp_tools(tenant_id: str) -> list[ToolProviderApiEntity]:
|
||||
def retrieve_mcp_tools(tenant_id: str, for_list: bool = False) -> list[ToolProviderApiEntity]:
|
||||
mcp_providers = (
|
||||
db.session.query(MCPToolProvider)
|
||||
.filter(MCPToolProvider.tenant_id == tenant_id)
|
||||
.order_by(MCPToolProvider.name)
|
||||
.all()
|
||||
)
|
||||
return [ToolTransformService.mcp_provider_to_user_provider(mcp_provider) for mcp_provider in mcp_providers]
|
||||
return [
|
||||
ToolTransformService.mcp_provider_to_user_provider(mcp_provider, for_list=for_list)
|
||||
for mcp_provider in mcp_providers
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def list_mcp_tool_from_remote_server(cls, tenant_id: str, provider_id: str):
|
||||
@ -123,6 +134,7 @@ class MCPToolManageService:
|
||||
updated_at=int(mcp_provider.updated_at.timestamp()),
|
||||
description=I18nObject(en_US="", zh_Hans=""),
|
||||
label=I18nObject(en_US=mcp_provider.name, zh_Hans=mcp_provider.name),
|
||||
plugin_unique_identifier=mcp_provider.server_identifier,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -150,6 +162,7 @@ class MCPToolManageService:
|
||||
icon: str,
|
||||
icon_type: str,
|
||||
icon_background: str,
|
||||
server_identifier: str,
|
||||
):
|
||||
mcp_provider = cls.get_mcp_provider_by_provider_id(provider_id, tenant_id)
|
||||
if mcp_provider is None:
|
||||
@ -158,6 +171,8 @@ class MCPToolManageService:
|
||||
mcp_provider.icon = (
|
||||
json.dumps({"content": icon, "background": icon_background}) if icon_type == "emoji" else icon
|
||||
)
|
||||
mcp_provider.server_identifier = server_identifier
|
||||
|
||||
if "[__HIDDEN__]" in server_url:
|
||||
db.session.commit()
|
||||
return
|
||||
@ -182,7 +197,6 @@ class MCPToolManageService:
|
||||
mcp_provider.tools = "[]"
|
||||
mcp_provider.encrypted_credentials = "{}"
|
||||
mcp_provider.server_url_hash = server_url_hash
|
||||
|
||||
db.session.commit()
|
||||
except IntegrityError as e:
|
||||
db.session.rollback()
|
||||
|
||||
@ -46,14 +46,15 @@ class ToolTransformService:
|
||||
|
||||
if provider_type == ToolProviderType.BUILT_IN.value:
|
||||
return str(url_prefix / "builtin" / provider_name / "icon")
|
||||
elif provider_type in {ToolProviderType.API.value, ToolProviderType.WORKFLOW.value, ToolProviderType.MCP.value}:
|
||||
elif provider_type in {ToolProviderType.API.value, ToolProviderType.WORKFLOW.value}:
|
||||
try:
|
||||
if isinstance(icon, str):
|
||||
return cast(dict, json.loads(icon))
|
||||
return icon
|
||||
except Exception:
|
||||
return {"background": "#252525", "content": "\ud83d\ude01"}
|
||||
|
||||
elif provider_type == ToolProviderType.MCP.value:
|
||||
return icon
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
@ -189,11 +190,11 @@ class ToolTransformService:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def mcp_provider_to_user_provider(db_provider: MCPToolProvider) -> ToolProviderApiEntity:
|
||||
def mcp_provider_to_user_provider(db_provider: MCPToolProvider, for_list: bool = False) -> ToolProviderApiEntity:
|
||||
from services.tools.mcp_tools_mange_service import MCPToolManageService
|
||||
|
||||
return ToolProviderApiEntity(
|
||||
id=db_provider.id,
|
||||
id=db_provider.server_identifier if not for_list else db_provider.id,
|
||||
author=db_provider.user.name if db_provider.user else "Anonymous",
|
||||
name=db_provider.name,
|
||||
icon=db_provider.provider_icon,
|
||||
|
||||
Reference in New Issue
Block a user