feat: MCP 后端切到 deta.city 远程端点 + 账号登录门槛
- .mcp.json / cordis.patch.yml 改为远程 streamable-http(https://deta.city/mcp-api/mcp),凭据经环境变量 DETA_TOKEN - 新增 bin/deta-login.mjs:deta.city 账号登录,写 ~/.deta/credentials.json 与 ~/.deta/env(均 0600) - 新增 plugins/deta/README.md:端点/凭据语义、两种宿主安装、本地 stdio 开发形态 - 本地 stdio 形态改为默认注释关闭(仅本机开发,不校验账号、不隔离工作区)
This commit is contained in:
@@ -16,6 +16,10 @@ DETA 领域能力在各类 Agent harness 上的分发仓:**一份产物,多
|
||||
## 安装(Codex)
|
||||
|
||||
```bash
|
||||
# 先登录(一次性,需要 deta.city 账号):换取 DETA_TOKEN
|
||||
node ~/Dev/ant/deta-agent-plugins/plugins/deta/bin/deta-login.mjs
|
||||
source ~/.deta/env # 让 DETA_TOKEN 进入当前 shell 环境
|
||||
|
||||
# 从 Git(分发用)
|
||||
codex plugin marketplace add https://git.deta.city/deta/deta-agent-plugins.git
|
||||
|
||||
@@ -26,6 +30,9 @@ codex plugin list
|
||||
codex plugin add deta@deta
|
||||
```
|
||||
|
||||
未登录(环境里没有 `DETA_TOKEN`)时,MCP 端点会返回 **401**——含义是
|
||||
「当前环境没有可用的 deta.city 登录态」,重新执行上面的登录两步即可。
|
||||
|
||||
## 内容
|
||||
|
||||
| 插件 | 技能 | 能力 | 依赖 |
|
||||
@@ -34,22 +41,37 @@ codex plugin add deta@deta
|
||||
|
||||
## 前置条件
|
||||
|
||||
`deta` 插件的 MCP 后端是领域服务的无头 MCP 服务:
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| MCP 端点 | `https://deta.city/mcp-api/mcp`(MCP Streamable HTTP) |
|
||||
| 凭据来源 | **deta.city 账号**;`bin/deta-login.mjs` 登录取令牌,经环境变量 `DETA_TOKEN` 传给 harness |
|
||||
| 凭据文件 | `~/.deta/credentials.json`(令牌 + 账号 + 端点)、`~/.deta/env`(`export DETA_TOKEN=...`),均 0600 |
|
||||
|
||||
端点除探活接口(服务端 `GET /health`,经 Nginx 前缀对外为 `/mcp-api/health`)外全部需要鉴权:
|
||||
|
||||
- 未带凭据 / 凭据失效 → `401`(提示重新登录,不回显凭据);
|
||||
- 服务端认证服务不可用 → `500`,同样不放行;
|
||||
- 各账号在服务端有独立工作区(`<工作区根>/<账号 ID>`),互不可见。
|
||||
|
||||
### 本地 stdio 形态(开发用,默认关闭)
|
||||
|
||||
本机开发时也可以直连领域服务的无头 MCP 服务(`bin/deta-mcp.sh`,stdio),
|
||||
它**不校验 deta.city 账号、不隔离工作区**,仅供本机迭代领域能力:
|
||||
|
||||
```bash
|
||||
cd ~/Dev/ant/ant-copilot && npm run build
|
||||
node dist/src/headless/mcp-server.js # 冒烟:应等待 stdin/stdout
|
||||
```
|
||||
|
||||
环境变量:
|
||||
该形态的环境变量:
|
||||
|
||||
| 变量 | 缺省 | 说明 |
|
||||
|------|------|------|
|
||||
| `DETA_SERVER_ROOT` | `~/Dev/ant/ant-copilot` | 领域服务仓库根目录(内部路径) |
|
||||
| `ANT_HEADLESS_WORKSPACE` | `<cwd>/workspace` | AML 工作目录(`aml.xml` / `building.json` 落盘处,名称由底层服务决定) |
|
||||
|
||||
编译与校验类工具需要编译服务在线(`localhost:8000`);未在线时返回明确错误,
|
||||
读写类工具可离线工作。
|
||||
编译与校验类工具需要编译服务在线(服务端为 `DETA_GSA_URL`,缺省 `localhost:8000`);
|
||||
未在线时返回明确错误,读写类工具可离线工作。
|
||||
|
||||
## 本地迭代
|
||||
|
||||
@@ -117,8 +139,9 @@ node apps/cli/lib/bin.js --profile headless --dump-config \
|
||||
# 输出中应出现 `# == .../plugins/deta/cordis.patch.yml` 与 deta-mcp 行
|
||||
```
|
||||
|
||||
`cordis.patch.yml` 里远程端点那段已按公开形态写好(`streamable-http` + Bearer 头),
|
||||
当前默认启用的是本地 stdio 行;服务端化完成后注释切换即可。
|
||||
`cordis.patch.yml` 当前默认启用**远程端点**(`streamable-http` +
|
||||
`Authorization: Bearer ${DETA_TOKEN}`,指向 `https://deta.city/mcp-api/mcp`);
|
||||
本地 stdio 段保留为注释、标注「本机开发用,默认关闭」,需要时手工切换。
|
||||
|
||||
## 已知缺陷(实测,2026-09-10)
|
||||
|
||||
@@ -160,9 +183,11 @@ Duplicate namespace name 'deta'; Namespace names must be unique.
|
||||
.agents/plugins/api_marketplace.json # Codex API key 登录用户市场
|
||||
plugins/deta/ # 同一目录 = Codex 插件根 = dsh 组合包根
|
||||
├── .codex-plugin/plugin.json # Codex 插件清单
|
||||
├── .mcp.json # Codex MCP 声明(含 Codex 私有键)
|
||||
├── .mcp.json # Codex MCP 声明(远程 streamable-http)
|
||||
├── package.json # dsh 组合包声明(dsh.bundle.patch)
|
||||
├── cordis.patch.yml # dsh 配置层(挂载 MCP 服务)
|
||||
├── bin/deta-mcp.sh # 本地 MCP 启动器(开发用)
|
||||
├── bin/deta-login.mjs # 登录助手(~/.deta/credentials.json + ~/.deta/env)
|
||||
├── bin/deta-mcp.sh # 本地 stdio 启动器(开发用,默认关闭)
|
||||
├── README.md # 插件说明(安装/凭据/401 语义)
|
||||
└── skills/aml-design/SKILL.md # 领域技能(两宿主共享)
|
||||
```
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"deta": {
|
||||
"command": "./bin/deta-mcp.sh",
|
||||
"args": [],
|
||||
"cwd": ".",
|
||||
"env_vars": [
|
||||
"DETA_SERVER_ROOT",
|
||||
"ANT_HEADLESS_WORKSPACE"
|
||||
],
|
||||
"default_tools_approval_mode": "approve",
|
||||
"supports_parallel_tool_calls": false
|
||||
"type": "streamable-http",
|
||||
"url": "https://deta.city/mcp-api/mcp",
|
||||
"bearer_token_env_var": "DETA_TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# deta 插件(Codex 插件 / dsh 组合包)
|
||||
|
||||
DETA 领域能力(AML 建筑模型读写、编译校验、围护结构统计、空间邻接查询)
|
||||
以**远程 MCP 服务**形态挂进 Agent harness:同一个目录既是 Codex 插件根,
|
||||
也是 dsh 组合包根,两端共享 `skills/` 与同一份 MCP 后端。
|
||||
|
||||
## 端点与凭据
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| 端点 | `https://deta.city/mcp-api/mcp`(MCP Streamable HTTP) |
|
||||
| 凭据来源 | **deta.city 账号**(令牌经 `POST https://deta.city/prod-api/login` 换取) |
|
||||
| 传参方式 | 环境变量 `DETA_TOKEN`(Codex 侧 `bearer_token_env_var`;dsh 侧 `Authorization: Bearer ${DETA_TOKEN}`) |
|
||||
|
||||
端点除探活接口(服务端 `GET /health`,经 Nginx 前缀对外为 `/mcp-api/health`)外**全部需要鉴权**:
|
||||
|
||||
- 请求未带凭据、凭据失效/过期 → **401**(响应体为可读提示,不回显凭据)。
|
||||
401 的含义是「当前环境没有可用的 deta.city 登录态」,不是工具或模型出错;
|
||||
重新执行 `node bin/deta-login.mjs` 并 `source ~/.deta/env` 即可。
|
||||
- 服务端认证服务不可用(`ANT_ADMIN_SERVER` 未配置或不可达)→ 500,同样不放行。
|
||||
|
||||
账号的工作区在服务端按账号隔离(`<工作区根>/<账号 ID>`),
|
||||
不同账号的设计源码互不可见;同一账号的新会话继续使用自己的工作区。
|
||||
|
||||
## 安装(Codex)
|
||||
|
||||
```bash
|
||||
# 1. 先登录(一次性;需要 deta.city 账号)
|
||||
node ~/Dev/ant/deta-agent-plugins/plugins/deta/bin/deta-login.mjs
|
||||
# → 写入 ~/.deta/credentials.json 与 ~/.deta/env(均 0600)
|
||||
|
||||
# 2. 让 DETA_TOKEN 进入当前 shell 环境
|
||||
source ~/.deta/env
|
||||
|
||||
# 3. 安装插件
|
||||
codex plugin marketplace add https://git.deta.city/deta/deta-agent-plugins.git
|
||||
codex plugin add deta@deta
|
||||
```
|
||||
|
||||
登录助手也支持自建/预发环境:`node bin/deta-login.mjs --base-url https://<host>`。
|
||||
|
||||
## 安装(dsh)
|
||||
|
||||
```bash
|
||||
node ~/Dev/ant/deta-agent-plugins/plugins/deta/bin/deta-login.mjs
|
||||
source ~/.deta/env
|
||||
dsh plugin --profile <name> add ~/Dev/ant/deta-agent-plugins/plugins/deta
|
||||
```
|
||||
|
||||
`cordis.patch.yml` 默认启用远程 `streamable-http` 段(Bearer 取自 `DETA_TOKEN`)。
|
||||
|
||||
## 本地 stdio 形态(开发用)
|
||||
|
||||
`bin/deta-mcp.sh` 走本机 stdio(`node dist/src/headless/mcp-server.js`),
|
||||
**仅本机开发用,默认关闭**:不校验 deta.city 账号、不隔离工作区。
|
||||
需要在本机迭代领域能力时,打开 `cordis.patch.yml` 里注释掉的 stdio 段
|
||||
(并注释掉远程段),设置 `DETA_SERVER_ROOT` 指向已构建的领域服务仓库:
|
||||
|
||||
```bash
|
||||
cd ~/Dev/ant/ant-copilot && npm run build
|
||||
node dist/src/headless/mcp-server.js # 冒烟:应等待 stdin/stdout
|
||||
```
|
||||
|
||||
## 文件
|
||||
|
||||
```
|
||||
.codex-plugin/plugin.json Codex 插件清单
|
||||
.mcp.json Codex MCP 声明(远程 streamable-http)
|
||||
package.json dsh 组合包声明(dsh.bundle.patch)
|
||||
cordis.patch.yml dsh 配置层(挂载 MCP 服务)
|
||||
bin/deta-login.mjs 登录助手(写 ~/.deta/credentials.json + ~/.deta/env)
|
||||
bin/deta-mcp.sh 本地 stdio 启动器(开发用)
|
||||
skills/aml-design/SKILL.md 领域技能
|
||||
```
|
||||
Executable
+228
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* DETA 登录助手(Node ESM,零第三方依赖)
|
||||
*
|
||||
* 用 deta.city 账号换取 API 令牌,供 MCP 远程端点鉴权使用:
|
||||
*
|
||||
* node bin/deta-login.mjs [--base-url https://deta.city]
|
||||
*
|
||||
* 流程:
|
||||
* 1. 交互式读取用户名/密码(密码不回显);
|
||||
* 2. POST <base>/prod-api/login { username, password };
|
||||
* 3. 成功 → 写 ~/.deta/credentials.json 与 ~/.deta/env(均 0600);
|
||||
* 4. 失败 → 打印服务端 msg,退出码非 0。
|
||||
*
|
||||
* 凭据纪律:token 只写在本次 stdout 与上述两个 0600 文件里,
|
||||
* 不写日志、不写 stderr、不写其它位置。
|
||||
*/
|
||||
|
||||
import { mkdir, writeFile, chmod } from 'node:fs/promises';
|
||||
import { homedir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const DEFAULT_BASE_URL = 'https://deta.city';
|
||||
const REQUEST_TIMEOUT_MS = 20_000;
|
||||
|
||||
function fail(message) {
|
||||
console.error(`[deta-login] ${message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/** `--base-url <url>` / `--base-url=<url>`;缺省 https://deta.city,末尾斜杠去掉 */
|
||||
function parseBaseUrl(argv) {
|
||||
let baseUrl = process.env.DETA_BASE_URL || DEFAULT_BASE_URL;
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const arg = argv[i];
|
||||
if (arg === '--base-url') {
|
||||
const next = argv[i + 1];
|
||||
if (!next) fail('--base-url 缺少取值');
|
||||
baseUrl = next;
|
||||
i++;
|
||||
} else if (arg.startsWith('--base-url=')) {
|
||||
baseUrl = arg.slice('--base-url='.length);
|
||||
} else if (arg === '-h' || arg === '--help') {
|
||||
console.log('用法:node bin/deta-login.mjs [--base-url https://deta.city]');
|
||||
process.exit(0);
|
||||
} else {
|
||||
fail(`未知参数:${arg}`);
|
||||
}
|
||||
}
|
||||
return baseUrl.trim().replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 读一行输入。hidden=true 时不回显(密码);
|
||||
* 非 TTY(管道/CI)时同样按行读取,便于自动化。
|
||||
*/
|
||||
let pendingInput = '';
|
||||
|
||||
/** 从暂存缓冲里切出一行(跨 chunk 保留剩余数据),无完整行返回 null */
|
||||
function takeLine() {
|
||||
const index = pendingInput.search(/[\r\n]/);
|
||||
if (index < 0) return null;
|
||||
const line = pendingInput.slice(0, index);
|
||||
const skip = pendingInput[index] === '\r' && pendingInput[index + 1] === '\n' ? 2 : 1;
|
||||
pendingInput = pendingInput.slice(index + skip);
|
||||
return line;
|
||||
}
|
||||
|
||||
function readLine({ hidden }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 上一次读取可能已经缓冲了后续行(管道一次性写入多行)
|
||||
const buffered = takeLine();
|
||||
if (buffered !== null) {
|
||||
resolve(buffered);
|
||||
return;
|
||||
}
|
||||
|
||||
const stdin = process.stdin;
|
||||
const isTTY = Boolean(stdin.isTTY);
|
||||
let buffer = '';
|
||||
let settled = false;
|
||||
|
||||
const cleanup = () => {
|
||||
stdin.removeListener('data', onData);
|
||||
stdin.removeListener('end', onEnd);
|
||||
stdin.removeListener('error', onError);
|
||||
if (isTTY && typeof stdin.setRawMode === 'function') stdin.setRawMode(false);
|
||||
stdin.pause();
|
||||
};
|
||||
const finish = (value) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
cleanup();
|
||||
// TTY 下 raw mode 不回显回车,这里补一个换行;非 TTY(管道)不额外输出
|
||||
if (isTTY) process.stdout.write('\n');
|
||||
resolve(value);
|
||||
};
|
||||
const onData = (chunk) => {
|
||||
const text = typeof chunk === 'string' ? chunk : chunk.toString('utf8');
|
||||
if (!isTTY) {
|
||||
// 非交互:不回显,按行切分,剩余数据留给下一次读取
|
||||
pendingInput += text;
|
||||
const line = takeLine();
|
||||
if (line !== null) finish(line);
|
||||
return;
|
||||
}
|
||||
for (const ch of [...text]) {
|
||||
if (ch === '\n' || ch === '\r') return finish(buffer);
|
||||
if (ch === '\u0003') {
|
||||
// Ctrl-C
|
||||
process.stdout.write('\n');
|
||||
process.exit(130);
|
||||
}
|
||||
if (ch === '\u0004') return finish(buffer); // Ctrl-D
|
||||
if (ch === '\u007f' || ch === '\b') {
|
||||
if (buffer && !hidden) process.stdout.write('\b \b');
|
||||
buffer = buffer.slice(0, -1);
|
||||
continue;
|
||||
}
|
||||
buffer += ch;
|
||||
if (!hidden) process.stdout.write(ch);
|
||||
}
|
||||
};
|
||||
// 输入结束:非 TTY 时把残留(末行无换行)也交出去
|
||||
const onEnd = () => {
|
||||
if (!isTTY && pendingInput) {
|
||||
const rest = pendingInput;
|
||||
pendingInput = '';
|
||||
finish(rest);
|
||||
return;
|
||||
}
|
||||
finish(buffer);
|
||||
};
|
||||
const onError = (err) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
cleanup();
|
||||
reject(err);
|
||||
};
|
||||
|
||||
if (isTTY && typeof stdin.setRawMode === 'function') stdin.setRawMode(true);
|
||||
stdin.resume();
|
||||
stdin.on('data', onData);
|
||||
stdin.on('end', onEnd);
|
||||
stdin.on('error', onError);
|
||||
});
|
||||
}
|
||||
|
||||
/** 单引号安全转义,供 `export DETA_TOKEN='...'` 使用 */
|
||||
function shellSingleQuote(value) {
|
||||
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
||||
}
|
||||
|
||||
async function writePrivateFile(filePath, content) {
|
||||
await writeFile(filePath, content, { mode: 0o600 });
|
||||
// 已存在的文件不被 mode 改写,显式收紧
|
||||
await chmod(filePath, 0o600).catch(() => undefined);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const baseUrl = parseBaseUrl(process.argv.slice(2));
|
||||
|
||||
process.stdout.write(`DETA 登录(${baseUrl})\n`);
|
||||
process.stdout.write('用户名:');
|
||||
const username = (await readLine({ hidden: false })).trim();
|
||||
if (!username) fail('用户名不能为空');
|
||||
|
||||
process.stdout.write('密码:');
|
||||
const password = await readLine({ hidden: true });
|
||||
if (!password) fail('密码不能为空');
|
||||
|
||||
const loginUrl = `${baseUrl}/prod-api/login`;
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(loginUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username, password }),
|
||||
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
||||
});
|
||||
} catch (err) {
|
||||
fail(`无法连接 ${loginUrl}(${err instanceof Error ? err.message : String(err)})`);
|
||||
}
|
||||
|
||||
let payload = null;
|
||||
try {
|
||||
payload = await response.json();
|
||||
} catch {
|
||||
payload = null;
|
||||
}
|
||||
|
||||
const token = typeof payload?.token === 'string' ? payload.token : '';
|
||||
if (!response.ok || !token || (typeof payload?.code === 'number' && payload.code !== 200)) {
|
||||
const msg = payload?.msg || `登录失败(HTTP ${response.status})`;
|
||||
fail(msg);
|
||||
}
|
||||
|
||||
const loginUsername = typeof payload.username === 'string' && payload.username ? payload.username : username;
|
||||
const dir = join(homedir(), '.deta');
|
||||
await mkdir(dir, { recursive: true, mode: 0o700 });
|
||||
await chmod(dir, 0o700).catch(() => undefined);
|
||||
|
||||
const credentials = {
|
||||
token,
|
||||
username: loginUsername,
|
||||
baseUrl,
|
||||
loginAt: new Date().toISOString(),
|
||||
};
|
||||
const credentialsPath = join(dir, 'credentials.json');
|
||||
const envPath = join(dir, 'env');
|
||||
await writePrivateFile(credentialsPath, `${JSON.stringify(credentials, null, 2)}\n`);
|
||||
await writePrivateFile(
|
||||
envPath,
|
||||
`# DETA MCP 凭据(由 bin/deta-login.mjs 生成,勿提交版本库)\n` +
|
||||
`# 用法:source ~/.deta/env\n` +
|
||||
`export DETA_TOKEN=${shellSingleQuote(token)}\n`,
|
||||
);
|
||||
|
||||
// token 只在这里(stdout)出现一次;stderr 与其它文件均不含凭据
|
||||
console.log(`DETA_TOKEN=${token}`);
|
||||
console.log(`✅ 登录成功:${loginUsername} @ ${baseUrl}`);
|
||||
console.log(`凭据已写入 ${credentialsPath}(0600),环境变量已写入 ${envPath}(0600)`);
|
||||
console.log(`使用:source ~/.deta/env 后再启动 harness(DETA_TOKEN 随环境传给 https://deta.city/mcp-api/mcp)`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
fail(err instanceof Error ? err.message : String(err));
|
||||
});
|
||||
@@ -4,29 +4,37 @@
|
||||
# 本层只做一件事:把 DETA 领域能力作为 MCP 服务挂进 harness。
|
||||
# 工具以 mcp__deta__<tool> 暴露(与 Codex 侧同名)。
|
||||
#
|
||||
# ── 公开发布形态(远程端点,推荐)─────────────────────────────
|
||||
# 服务端化完成后启用本节,并删除下面的本地 stdio 节。
|
||||
# 凭据:deta.city 账号。先 `node bin/deta-login.mjs` 登录(写入 ~/.deta/credentials.json
|
||||
# 与 ~/.deta/env),再 `source ~/.deta/env` 让 DETA_TOKEN 进入环境。
|
||||
# 端点 https://deta.city/mcp-api/mcp 除 /health 外都要鉴权,无凭据一律 401。
|
||||
#
|
||||
# ── 远程端点形态(Streamable HTTP,默认启用)───────────────────
|
||||
# 服务端:deta.city 上的无头 MCP 服务(ant-copilot src/headless/mcp-http-server.ts),
|
||||
# 经 Nginx 反代暴露;各账号的工作区在服务端按账号隔离。
|
||||
#
|
||||
- insert:
|
||||
- id: deta-mcp
|
||||
name: '@deepseek-ai/dsh-mcp-client'
|
||||
config:
|
||||
serverName: deta
|
||||
transport: streamable-http
|
||||
url: https://deta.city/mcp-api/mcp
|
||||
headers:
|
||||
Authorization: !!js '`Bearer ${process.env.DETA_TOKEN ?? ''}`'
|
||||
#
|
||||
# ── 本地形态(本机开发用,默认关闭)───────────────────────────
|
||||
# 走 stdio 直连本机已构建的领域服务,不校验 deta.city 账号、不隔离工作区,
|
||||
# 只在迭代领域能力时临时启用:把下面整节取消注释,同时注释掉上面的远程节。
|
||||
# 需要 DETA_SERVER_ROOT 指向已构建的领域服务仓库(缺省见启动器脚本)。
|
||||
#
|
||||
# - insert:
|
||||
# - id: deta-mcp
|
||||
# name: '@deepseek-ai/dsh-mcp-client'
|
||||
# config:
|
||||
# serverName: deta
|
||||
# transport: streamable-http
|
||||
# url: https://deta.city/workspace-api/mcp
|
||||
# headers:
|
||||
# Authorization: !!js '`Bearer ${process.env.DETA_TOKEN ?? ''}`'
|
||||
#
|
||||
# ── 本地形态(当前可用:本机已构建的领域服务,stdio)─────────
|
||||
# 需要 DETA_SERVER_ROOT 指向已构建的领域服务仓库(缺省见启动器脚本)。
|
||||
- insert:
|
||||
- id: deta-mcp
|
||||
name: '@deepseek-ai/dsh-mcp-client'
|
||||
config:
|
||||
serverName: deta
|
||||
transport: stdio
|
||||
command: node
|
||||
args:
|
||||
- !!js '`${process.env.DETA_SERVER_ROOT ?? process.env.HOME + "/Dev/ant/ant-copilot"}/dist/src/headless/mcp-server.js`'
|
||||
env:
|
||||
ANT_HEADLESS_WORKSPACE: !!js process.env.ANT_HEADLESS_WORKSPACE ?? ''
|
||||
# transport: stdio
|
||||
# command: node
|
||||
# args:
|
||||
# - !!js '`${process.env.DETA_SERVER_ROOT ?? process.env.HOME + "/Dev/ant/ant-copilot"}/dist/src/headless/mcp-server.js`'
|
||||
# env:
|
||||
# ANT_HEADLESS_WORKSPACE: !!js process.env.ANT_HEADLESS_WORKSPACE ?? ''
|
||||
|
||||
Reference in New Issue
Block a user