Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Dd Arch

БесплатноНе проверен

A dynamic tool management platform that allows creating, editing, and executing Python code tools via a web UI, exposing them as MCP tools through Streamable HT

GitHubEmbed

Описание

A dynamic tool management platform that allows creating, editing, and executing Python code tools via a web UI, exposing them as MCP tools through Streamable HTTP.

README

DDD 架构 · MCP 工具管理平台。

快速启动

启动 MySQL 8.0(首次创建数据卷时会执行 docs/init.sql):

docker compose -f docs/docker-compose.yml up -d

安装后端依赖:

uv sync --extra dev

安装并构建前端:

cd frontend
npm install
npm run build
cd ..

启动 HTTP + MCP Streamable HTTP:

source .venv/bin/activate
python -m dd_arch.app.application

如果没有激活虚拟环境,也可以直接通过 uv 调用:

uv run python -m dd_arch.app.application

启动后主要入口:

/api       管理端 REST API
/mcp       MCP Streamable HTTP
/          frontend/dist 静态前端

停止 MySQL:

docker compose -f docs/docker-compose.yml down

如需重新执行初始化 SQL,先删除数据卷:

docker compose -f docs/docker-compose.yml down -v
docker compose -f docs/docker-compose.yml up -d

⚠️ 安全前提(RCE):本平台允许从 Web 提交并在服务器进程内执行任意 Python 代码,本质是远程代码执行。当前采用进程内 exec(最简,完全 RCE,无沙箱)仅适用于受信任的内网/单用户环境。编辑类接口必须置于受信任网络或加鉴权后再对外。命名空间预置的最小 __builtins__ 不构成安全边界;沙箱隔离是预留扩展点(IToolExecutorPort 可替换为受限/子进程实现)。

权威规格见 spec.md,执行进度见 progress.md

架构总览

项目采用轻量六边形架构,并额外保留通用类型层和启动层。工具来自数据库,不再有静态注册中心或工具目录。

                 +-------------+
                 |   trigger   |  HTTP / MCP 入站适配
                 +------+------+
                        |
                 +------v------+
                 |     api     |  DTO / 响应契约
                 +------+------+
                        |
                 +------v------+
                 |   domain    |  领域模型 / 领域服务 / 接口
                 +------^------+
                        |
        +---------------+---------------+
        |        infrastructure         |  DB / Cache / Event / Metrics / Executor
        +-------------------------------+

types 提供跨层共享的错误码、异常、响应和分页类型。
app 作为组合根装配所有层,并负责生命周期。

核心约束:

  • domain 不依赖 FastAPI、SQLAlchemy、MCP、infrastructure 等外部技术;也不真正 exec 代码(编译执行是 IToolExecutorPort 的 infra 职责,domain 只定义接口)。
  • 简单编排直接放在 domain service 中;trigger 只做协议适配、参数接收、响应包装。
  • infrastructure 实现领域层定义的 repository/port 接口,不反向依赖 trigger
  • app 是唯一知道所有层实现细节的组合根,负责依赖注入、生命周期和挂载。
  • 数据库、repository、service 主链路使用同步调用;FastAPI/MCP 入口保留 async 协议函数,并通过线程池调用同步服务。

项目结构

.
├── resources/
│   └── application.yaml          # 默认运行配置
├── docs/init.sql                 # MySQL schema
├── pyproject.toml                # 项目依赖和构建配置
├── docs/spec.md                  # 项目权威规格
├── docs/progress.md              # 执行进度
├── docs/step-*.md                # 分步骤规格
├── tests/                        # 自动化测试
├── frontend/                     # Vue 管理端(含工具编辑器)
└── src/dd_arch/
    ├── types/                    # 通用基础类型
    ├── api/                      # HTTP/API 契约
    ├── domain/                   # 领域核心(tooldef / invocation)
    ├── infrastructure/           # 外部技术实现(含 ToolExecutorPort)
    ├── trigger/                  # HTTP/MCP 入站适配器
    └── app/                      # 组合根、启动入口和运行配置加载

分层职责

types/ 通用类型层

这一层放跨层共享且不携带业务流程的基础类型,主要包括:

  • 统一错误码。
  • 工具异常和业务异常。
  • HTTP 统一响应信封 {code, info, data}
  • 内部分页结果。

它可以被各层引用,但不主动依赖业务层或基础设施层。

api/ 契约层

这一层描述管理端 API 的输入输出契约,主要包括:

  • 工具定义、服务状态、调用日志、日志统计等 DTO。
  • API 错误响应构造工具。

api 层不处理业务流程,只定义 trigger 和 service 之间稳定的数据形状。

domain/ 领域层

领域层是业务核心,不包含框架代码和数据库代码。

domain/
├── tooldef/                      # 工具定义子域(Web 动态工具核心)
│   ├── model/                    # ToolDefinitionAggregate / 参数与状态值对象 / 编译产物 VO
│   ├── adapter/repository/       # 工具定义、工具配置仓储接口
│   ├── adapter/port/             # 代码执行器端口接口(IToolExecutorPort)
│   └── service/                  # 参数→JSON Schema、参数矫正等领域规则
└── invocation/                   # 工具调用子域
    ├── model/                    # 调用日志、调用事件、状态值对象
    ├── adapter/repository/       # 调用日志仓储接口
    ├── adapter/port/             # 事件发布、指标等端口接口
    └── service/                  # 调用日志和统计领域规则

这一层解决的问题:

  • 一个动态工具如何表达:名称、描述、代码串、是否异步、tags、参数列表、状态(DRAFT/ENABLED/DISABLED)。
  • 参数列表如何生成 JSON Schema,原始入参如何按类型矫正。
  • 每个工具的运行时配置如何表达。
  • 工具调用成功、失败、耗时、错误如何记录为领域事实。
  • 调用事件如何作为领域事件发布给外部处理器。
  • repository/port 的能力边界是什么(Repository=本地数据,Port=代码执行/事件/指标等外部能力)。

infrastructure/ 基础设施层

基础设施层负责把领域接口落到具体技术实现。

infrastructure/
├── dao/                          # SQLAlchemy 查询封装
│   └── po/                       # ORM 持久化对象(tool_definition / tool_invocation_log)
├── adapter/
│   ├── repository/               # 领域 repository 的实现
│   └── port/                     # 领域 port 的实现(含 ToolExecutorPort)
├── cache/                        # 进程内 TTL 缓存
└── logging/                      # 审计日志后台批量写入

这一层解决的问题:

  • 数据库表和领域对象之间的转换(tags/parameters/status 的 JSON↔对象)。
  • 工具定义、调用日志的持久化。
  • 工具定义的 cache-aside 缓存。
  • 代码执行器ToolExecutorPort):把工具的 codecompile+exec 到受控命名空间取出入口函数,按 name+sha256(code) 缓存编译产物,工具更新即 invalidate,按 is_async 分派。
  • 领域事件的进程内分发。
  • 审计日志后台批量写入。
  • 配置文件和数据库连接。

领域服务同时负责这些简单编排:

  • 工具创建/更新时构造聚合、校验、编译验证(编译失败回滚),并失效执行器缓存。
  • 工具执行前检查工具是否存在、是否启用、是否需要 ctx 配置。
  • 工具执行支持普通 def handler(...)async def handler(...)
  • 将执行成功或失败转为领域事件。
  • 草稿试跑(用编辑中、尚未保存的临时定义即时编译执行)与已存工具试跑(绕过 ENABLED 校验),两者记 source='test' 日志、不发 MCP 调用事件。
  • 分页查询日志、查询详情、统计和清理历史日志。
  • 将领域事件转为审计日志入队。

trigger/ 触发层

触发层是入站适配器,负责把外部协议转换为用例调用。

trigger/
├── http/                         # FastAPI 管理 API
└── mcp/                          # 官方 MCP low-level server 和 Streamable HTTP

HTTP 侧主要提供:

GET    /api/status
GET    /api/tools
GET    /api/tools/{name}
POST   /api/tools                      # 创建:code + parameters + is_async + tags + config
PUT    /api/tools/{name}               # 更新:同创建请求体
DELETE /api/tools/{name}               # 删除
POST   /api/tools/{name}/enable
POST   /api/tools/{name}/disable
POST   /api/tools/test                 # 草稿试跑(body 含 definition,不读/写库)
POST   /api/tools/{name}/test          # 已存工具试跑(绕过 ENABLED)
GET    /api/logs
GET    /api/logs/stats
GET    /api/logs/{id}
DELETE /api/logs?before=ISO_DATETIME

MCP 侧主要提供:

  • tools/list:只暴露启用状态的工具。
  • tools/call:把 MCP 调用转换为工具执行用例。
  • Streamable HTTP ASGI app:挂载到 FastAPI 的 /mcp

app/ 启动层

启动层是组合根,负责把所有层连接起来。

app/
├── application.py                # 进程启动入口,按配置选择 HTTP 或 stdio
├── container.py                  # dependency-injector 容器和 ApplicationContext
├── persistence.py                # session/事务边界和仓储装配
└── config/                       # YAML 配置加载、数据库/FastAPI/MCP 组件配置

这一层解决的问题:

  • 加载 resources/application.yaml 和可选 resources/application-local.yaml
  • 创建数据库 engine、session factory、DAO、repository、port(含 ToolExecutorPort)和 service。
  • 工具全部来自 DB(tool_definition 表),由 Web 端创建,不做工具目录自动发现。
  • 将事件订阅者注册到事件总线。
  • 构建 HTTP routers、MCP server 和前端静态挂载。
  • 在 lifespan 中建表、启动/停止日志写入器、管理 MCP session manager、释放数据库连接。

关键运行链路

管理 API 链路

HTTP request
  -> trigger/http controller
  -> domain service / repository interface
  -> infrastructure repository / dao / cache
  -> Response{code, info, data}

典型场景:

  • 工具列表:返回工具定义(含代码、参数、状态、input_schema、运行时配置)。
  • 创建/更新:在 service 中开启事务,校验并编译验证代码(编译失败回滚,返回 COMPILE_ERROR),写入后失效执行器缓存。
  • 启用/禁用:写入状态并失效缓存。
  • 配置随工具创建/更新写入,工具执行时若声明 ctx 可读取。
  • 日志查询:读取调用日志表并转换为前端 DTO。

MCP 工具调用链路

MCP tools/call
  -> trigger/mcp
  -> 工具执行服务
  -> 工具定义仓储查询(经缓存)
  -> domain 检查工具状态
  -> ToolExecutorPort 取/编译可调用对象(按 name+code 哈希缓存)
  -> 按 is_async 分派执行(同步服务中封装 async handler)
  -> 发布成功或失败领域事件
  -> 审计日志订阅者入队
  -> 文本结果返回 MCP client

这条链路保证:

  • 未注册工具返回统一错误码(UNKNOWN_TOOL)。
  • 禁用/草稿工具不会进入实际函数执行(TOOL_DISABLED)。
  • HTTP/MCP 入口通过线程池调用同步用例,避免同步数据库操作直接阻塞事件循环。
  • async 工具仍可执行,但会在线程内独立运行事件循环。
  • 日志和指标由事件订阅者处理,不阻塞主调用流程。

数据模型

默认 MySQL schema 见 init.sql

tool_definition
  动态工具定义:code、is_async、tags_json、parameters_json、config_json、status

tool_invocation_log
  工具调用日志、状态、耗时、错误、source(mcp/test)和创建时间

开发和测试可使用 sqlite:///path/to/dev.db。生产默认配置使用 mysql+pymysql

配置

默认配置在 resources/application.yaml

server:
  host: 127.0.0.1
  port: 8003
mcp:
  transport: streamable-http
  http-path: /mcp
  frontend-dist: frontend/dist
database:
  url: mysql+pymysql://root:[email protected]:3306/mcp_admin?charset=utf8mb4
  pool-size: 20
  max-overflow: 10

本地敏感配置写入 resources/application-local.yaml,会覆盖默认配置,且已被 .gitignore 忽略。

运行说明

本地敏感配置可写入 resources/application-local.yaml。例如开发时可使用 SQLite:

database:
  url: sqlite:///./dev.db

直接用模块方式启动服务,host、port、MCP transport 和路径都从 resources/application.yaml 读取:

python -m dd_arch

开发前端时也可以单独启动 Vite:

cd frontend
npm run dev

Vite 会把 /api/mcp 代理到 http://127.0.0.1:8003

在 Web 端创建工具

  1. 打开前端,进入 Tools 页,点击「New Tool」。
  2. 填写:
    • 名称(合法 Python 标识符)、描述。
    • 代码框:定义入口函数 def handler(...)async def handler(...)(异步工具需勾选「Async」开关并与代码一致)。需要读取运行时配置时,在签名里加 ctx 参数(ctx.config 为该工具的 KV 配置)。
    • 参数列表:逐行配置参数名/类型/必填/默认/描述,保存时由后端生成 JSON Schema。
    • tags(逗号分隔)。
  3. 保存前可在「Test Run」面板填入测试参数一键试跑(草稿试跑,无需先保存,编译失败会直接显示 COMPILE_ERROR)。
  4. 点击「Save Tool」:后端编译校验通过后入库(默认 DRAFT),编译失败返回 info 并不落库。
  5. 回到列表 enable 工具;启用后 MCP 客户端 tools/list 即可见、tools/call 可调用。

示例代码(同步):

def handler(a, b):
    return a + b

示例代码(异步):

import asyncio


async def handler(seconds):
    await asyncio.sleep(seconds)
    return f"slept {seconds}s"

当前数据库主链路是同步的;HTTP/MCP 入口会把用例调用放入线程池执行。

测试

运行后端测试:

uv run pytest

运行前端类型检查和生产构建:

cd frontend
npm run build

当前测试覆盖:

  • domain 不依赖 infrastructure、trigger、app、FastAPI、SQLAlchemy、MCP。
  • executor:sync/async 工具编译与分派、语法错误与 is_async 不符返回 COMPILE_ERRORbuild_input_schemacoerce_arguments(字符串转型与必填校验)。
  • 工具 CRUD:创建→编译校验→enable→MCP 列表可见;坏代码 create 返回 COMPILE_ERROR 且不落库。
  • 测试运行:草稿试跑返回结果且不创建工具、坏代码草稿试跑返回 ok=false, code=COMPILE_ERROR;已存工具试跑对 DRAFT/DISABLED 工具仍能执行;测试调用记 source='test' 且不计入 stats()
  • 执行用例:DISABLED 拦截并发 ToolFailedEvent;成功调用返回结果并经订阅者批量落库。
  • 50 个 async def handler + await asyncio.sleep(1) 通过线程池并发调用总耗时小于 5 秒。

已验证内容

当前已完成的本地验证包括:

  • src/dd_arch 导入检查(全包可 import,无残留旧模块引用)。
  • uv run pytest(18 项全绿)。
  • frontend/npm run build(vue-tsc 类型检查 + vite 构建通过)。
  • SQLite 库下 FastAPI lifespan 启动和关闭、MCP session manager 初始化。
  • /api/status/api/tools CRUD、/api/tools/test 草稿试跑和 enable(经 ASGI 实测)。
  • 工具定义 cache-aside、执行器编译缓存与失效。
  • domain 依赖边界扫描。
  • 前端统一信封拆包、工具编辑器与测试运行面板构建通过。

from github.com/ollo-kitty/mcp

Установка Dd Arch

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/ollo-kitty/mcp

FAQ

Dd Arch MCP бесплатный?

Да, Dd Arch MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Dd Arch?

Нет, Dd Arch работает без API-ключей и переменных окружения.

Dd Arch — hosted или self-hosted?

Доступен hosted-вариант: Unyly запускает сервер в облаке, локальная установка не обязательна.

Как установить Dd Arch в Claude Desktop, Claude Code или Cursor?

Открой Dd Arch на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Dd Arch with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development