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
Описание
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):把工具的code串compile+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 端创建工具
- 打开前端,进入 Tools 页,点击「New Tool」。
- 填写:
- 名称(合法 Python 标识符)、描述。
- 代码框:定义入口函数
def handler(...)或async def handler(...)(异步工具需勾选「Async」开关并与代码一致)。需要读取运行时配置时,在签名里加ctx参数(ctx.config为该工具的 KV 配置)。 - 参数列表:逐行配置参数名/类型/必填/默认/描述,保存时由后端生成 JSON Schema。
- tags(逗号分隔)。
- 保存前可在「Test Run」面板填入测试参数一键试跑(草稿试跑,无需先保存,编译失败会直接显示
COMPILE_ERROR)。 - 点击「Save Tool」:后端编译校验通过后入库(默认 DRAFT),编译失败返回
info并不落库。 - 回到列表 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_ERROR、build_input_schema与coerce_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/toolsCRUD、/api/tools/test草稿试跑和 enable(经 ASGI 实测)。- 工具定义 cache-aside、执行器编译缓存与失效。
- domain 依赖边界扫描。
- 前端统一信封拆包、工具编辑器与测试运行面板构建通过。
Установка Dd Arch
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/ollo-kitty/mcpFAQ
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
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Dd Arch with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
