---
> *Language: [中文](#pi-mcp-market) | [English](#pi-mcp-market-en)*
>

# pi-mcp-market

在 Pi 编码助手中搜索、预览、安装和卸载 MCP 服务器。与 `pi-mcp-adapter` 协同工作——本扩展负责**发现与配置**，adapter 负责**连接与运行**。

支持简体中文和英文界面，通过语言切换命令即时切换。

## 安装

```bash
pi install npm:pi-mcp-market
```

重启 Pi 后生效。需要同时安装 `pi-mcp-adapter`（用于实际连接 MCP 服务器）。

## 快速开始

打开市场面板：

```
/mcp-market [查询词]
```

面板打开后立即显示，各市场源**独立并发加载**——先完成的源先显示条目。

### 切换语言

```bash
/mcp-market lang zh        # 切换到中文
/mcp-market lang en        # 切换到英文
# 或通过独立命令:
/mcp-market-lang zh|en
```

语言选择会持久化到 `~/.pi/agent/pi-mcp-market/language.json`，重启后保持。

面板标题、提示文字、错误信息、认证徽章标签等所有 UI 文字都会同步切换。

语言自动检测顺序：
1. 持久化的语言配置文件（显式选择优先）
2. 环境变量 `PI_MCP_MARKET_LANG=zh` 或 `PI_MCP_MARKET_LANG=en`
3. 系统 `LANG` 环境变量（以 `zh` 开头则选中文，否则英文）
4. 默认：中文

### 面板操作

| 操作 | 功能 |
|------|------|
| 直接打字 | 即时模糊搜索名称/描述/标签 |
| `↑` / `↓` | 移动光标，显示服务器详情 |
| `Enter` | 预览配置，再按一次确认安装或卸载 |
| `←` / `→` | 切换市场源（全部 / 各 registry） |
| `Esc` | 清空搜索（再按关闭） |
| `Ctrl+C` | 关闭面板 |

### 徽章说明

| 徽章 | 含义 |
|------|------|
| `✅` | 无需认证，开箱即用（自动从 `entry.auth` 推导） |
| `🔑` | 需要 ENV Key（Bearer Token / API Key，带获取地址提示） |
| `🔐` | 需要 OAuth |
| `❓` | 认证类型未知 |
| `● 已安装` | 已安装到 mcp.json |
| `⚠ 待配置` | 已安装但必填环境变量缺失 |
| `⏳` | 该源正在加载 |
| `⚠` | 该源加载失败 |

空启动后会自动预装未装 adapter 的提示。配置完成后运行 `/reload` 刷新 MCP 工具。

### 安装流程

```
Enter → 预览配置 JSON → Enter 确认安装 / Esc 取消
```

安装前会显示将要写入 `~/.pi/agent/mcp.json` 的完整配置片段，包括认证类型和服务端地址。确认后即写入，不需要离开面板。

有必填环境变量的服务器会先显示表单填写，再进入预览确认。`Esc` 可跳过填写，标记为「待配置」。

表单填写时，**每个必填字段都会显示获取入口**：
- 如果注册表提供了获取地址（`whereToGet`），会显示 `获取地址：https://...`，可直接访问
- 否则显示环境变量名供用户搜索

预览确认阶段也会在提示区显示：
```
需要设置环境变量 $XXX（安装后运行 /reload 生效）
获取地址：https://...
```

### 已安装 / 待配置清单

用 `←/→` 切换到 `已安装` 源，可以查看当前 `mcp.json` 中所有服务器的状态：

- `✅ 已就绪` — 已安装且配置完整
- `⚠ 待配置` — 已安装但环境变量缺失或需要 OAuth 授权（括号中列出缺失的变量名）

### 安装后使用

市场写入 mcp.json 后，需要通知 adapter 加载新配置：

```
/mcp reconnect          # 重新连接所有 MCP 服务器
/mcp reconnect <服务名>  # 只重连一个
# 或直接
/reload
```

然后打开 `/mcp` 面板查看各服务器状态：
- 绿色 ✅ — 已连接
- 黄色 ⚠ — 需要认证（运行 `/mcp-auth <服务名>`）
- 红色 ❌ — 连接失败

#### 常见连接失败原因

| 连接方式 | 失败现象 | 解决方法 |
|----------|----------|----------|
| `npx` 命令 | `Connection closed`，进程闪退 | 在终端手动运行 `npx -y <包名>` 看具体错误（包名拼错、Node 版本不够、缺少依赖等） |
| `url` 远程 | `401 Unauthorized` / `endpoint returned application/json` | 检查是否需要 API Key，在 mcp.json 中配置 `auth: "bearer"` + `bearerTokenEnv`；或访问官方文档确认正确的 endpoint URL |
| `url` 远程 | `OAuth required` | 运行 `/mcp-auth <服务名>` 完成 OAuth 授权 |
| `bearerTokenEnv` | `env var not set` | 确保环境变量已设置，例如 `export MY_API_KEY=xxx`，然后 `/reload` |

#### 获取 API Key 的通用方法

1. 查找该服务的**官方网站**（通常可在市场的详情描述中找到 GitHub 或官网链接）
2. 注册账号，进入开发者设置 / API Keys 页面
3. 创建 API Key 并设置到环境变量 `export <KEY_NAME>=<your_key>`
4. 运行 `/reload` 重试

默认内置三个市场源，零配置即用：

| 源 | 条目数 | 安装方式 | 认证提示 |
|-----|---------|--------------|---------|
| **官方 Registry** | ~200 | 远程 URL | 自动提取 header 中的获取地址 + websiteUrl 兜底 |
| **Smithery** | ~2,000 | `npx @smithery/cli run` | 运行时交互式配置 |
| **DeepNLP** | ~11,700 | OneKey 远程 URL 或 npx (GitHub) | 显示获取地址（credits 计费，非全免费） |

配置自定义源：编辑 `<agentDir>/pi-mcp-market/registries.json`：

```json
{
  "registries": [
    { "id": "my-registry", "name": "我的源", "url": "https://example.com/mcp-registry.json" }
  ]
}
```

支持的格式：`native`（默认）、`official`、`smithery`、`deepnlp`、`glama`。详情见手册配置一节。

## 使用示例

**搜索 MCP 服务器：**

```
/mcp market map
```

面板显示所有来源中名称、描述、标签含 "map" 的服务器。

**安装 Google Maps MCP：**

1. `↑/↓` 定位到 Google Maps → 右侧显示 `🔑` 标识（需要 API Key）和工具数量
2. `Enter` → 如果有必填环境变量，先显示表单，输入时可见获取地址或提示
3. 确认预览 → 显示环境变量名和对应获取地址（如有）
4. `Enter` 确认 → 写入 `~/.pi/agent/mcp.json`
5. 运行 `/reload` 生效

**查看工具详情：**

光标停留在服务器上时，详情行显示该服务暴露的工具数量（如 `🧰 7 tools`），以及是否支持安装前预览。

## 配置参考

### registries.json

存放于 `<agentDir>/pi-mcp-market/registries.json`。

```json
{
  "registries": [
    { "id": "official", "name": "官方 Registry", "url": "https://registry.modelcontextprotocol.io/v0/servers", "format": "official" },
    { "id": "smithery", "name": "Smithery", "url": "https://registry.smithery.ai/servers", "format": "smithery" },
    { "id": "deepnlp", "name": "DeepNLP", "url": "https://www.deepnlp.org/api/mcp_marketplace/v1?page_id=0&count_per_page=500", "format": "deepnlp" }
  ]
}
```

文件不存在或损坏时自动回退上述默认源。空数组 `{ "registries": [] }` 禁用所有远程源。

#### 认证

```json
{
  "id": "private-source",
  "name": "私有源",
  "url": "https://example.com/registry",
  "headers": { "Authorization": "Bearer {{API_KEY}}" },
  "apiKeyEnv": "MY_REGISTRY_KEY"
}
```

- `headers` — 静态请求头，支持 `{{API_KEY}}` 占位符
- `apiKeyEnv` — 环境变量名，运行时读取（**不落盘**），未设置时该源直接失败

#### 格式说明

| format | 输入 | 传输方式 | 安装形式 |
|--------|------|----------|----------|
| `native` | `MarketServer[]` | entry 内任意 | 原样写入 mcp.json |
| `official` | `{ servers: [{ server: { name, title, description, remotes } }] }` | `server.remotes[]` 中的 `streamable-http` URL | 远程 URL |
| `smithery` | `{ servers: [{ qualifiedName, displayName }] }` | 无 | `npx -y @smithery/cli run <qualifiedName>` |
| `deepnlp` | `{ items: [{ content_name, id, description, github, ext_info: { tools } }] }` | OneKey URL（`https://agent.deepnlp.org/mcp?server_name=...&onekey=...`）或 npx | 远程 URL 优先（OneKey 路径经 DeepNLP 代理，使用 **credits** 计费：免费试用额度 → Pro $9.9/月） |
| `glama` | `{ servers: [...] }` | 无 | 仅元数据，所有条目均跳过 |

### 安全保证

写入目标为 `<agentDir>/mcp.json`（通常是 `~/.pi/agent/mcp.json`）。

- 文件不存在 → 创建
- 文件损坏 → 备份为 `.backup-<时间戳>.json`，报错通知，**不自动覆盖**
- 每次修改前重读文件，只增删目标条目，不碰其他配置

> ⚠️ 环境变量值按 MCP 标准明文存储在 mcp.json，请妥善保管文件权限。

## 开发

```bash
npm install
npm run typecheck   # tsc --noEmit
npm test            # vitest run（61 个测试）
```

测试使用临时的 `PI_CODING_AGENT_DIR`，不影响真实配置。

## 架构概要

```
┌──────────────┐  /mcp market → openMarket()
│   index.ts    │──→ 从 registries.json 读取源列表
└──────┬───────┘     → 面板立即打开
       │
       ▼
┌──────────────┐          ┌───────────────────┐
│ market-panel │──→ 逐源  │   loadRemoteRegistry()  │←─ 官方 Registry
│  (TUI 面板)  │   加载   │   (catalog.ts)     │←─ Smithery
│              │   完成   │                    │←─ DeepNLP
└──────────────┘          └───────────────────┘
       │  每个源完成 → applyRegistryResult()
       ▼  追加到 aggregatedServers → 重渲染
┌──────────────┐
│  mcp.json   │←── Enter → 预览 → 确认 → 写入
└──────────────┘
```

- `index.ts` — 扩展入口，命令注册
- `src/i18n.ts` — 国际化字典（中文/英文）
- `src/lang-config.ts` — 语言持久化（读/写 `language.json`）
- `src/config.ts` — mcp.json 原子读写，registry 配置管理
- `src/catalog.ts` — 远程源获取 + 各格式归一化
- `src/market-panel.ts` — 键盘驱动的 TUI 面板（已适配 i18n）
- `src/registry-detect.ts` — adapter 检测
- `src/types.ts` — 共享类型定义

---

<br>
<br>

---
> *Language: [中文](#pi-mcp-market) | [English](#pi-mcp-market-en)*
>

# <a name="pi-mcp-market-en"></a>pi-mcp-market

Search, preview, install, and uninstall MCP servers in the Pi coding agent. Works alongside `pi-mcp-adapter` — this extension handles **discovery and configuration**, the adapter handles **connection and runtime**.

Supports both Chinese and English UI via a runtime language switch.

## Install

```bash
pi install npm:pi-mcp-market
```

Restart Pi after installation. `pi-mcp-adapter` is also required (for actually connecting MCP servers).

## Quick Start

Open the market panel:

```
/mcp-market [query]
```

The panel opens immediately. Each market source loads **independently and concurrently** — results appear as each source finishes.

### Switch Language

```bash
/mcp-market lang zh        # Switch to Chinese
/mcp-market lang en        # Switch to English
# Or via a dedicated command:
/mcp-market-lang zh|en
```

The language choice is persisted to `~/.pi/agent/pi-mcp-market/language.json` and survives restarts.

All panel text — title, hints, error messages, auth badges — switches immediately.

Auto-detection order:
1. Persisted language config (explicit user choice wins)
2. Environment variable `PI_MCP_MARKET_LANG=zh` or `PI_MCP_MARKET_LANG=en`
3. System `LANG` env var (if starts with `zh`, picks Chinese; otherwise English)
4. Default: Chinese

### Panel Controls

| Key | Action |
|-----|--------|
| Type | Instant fuzzy search on name/description/tags |
| `↑` / `↓` | Navigate, view server details |
| `Enter` | Preview config (press again to confirm install or uninstall) |
| `←` / `→` | Switch source (All / individual registries) |
| `Esc` | Clear search (press again to close) |
| `Ctrl+C` | Close panel |

### Badge Reference

| Badge | Meaning |
|-------|---------|
| `✅` | No auth required (auto-derived from `entry.auth`) |
| `🔑` | Needs ENV Key (Bearer Token / API Key, with acquisition hints) |
| `🔐` | Needs OAuth |
| `❓` | Unknown auth type |
| `● Installed` | Installed to mcp.json |
| `⚠ Needs config` | Installed but required env vars missing |
| `⏳` | Source loading |
| `⚠` | Source failed to load |

A hint about installing pi-mcp-adapter shows automatically if it is not detected. Run `/reload` after configuration to refresh MCP tools.

### Install Flow

```
Enter → Preview config JSON → Enter to confirm / Esc to cancel
```

The panel shows the full config snippet that will be written to `~/.pi/agent/mcp.json`, including auth type and server address. Confirm and it writes immediately — no need to leave the panel.

Servers with required environment variables show a form first, then the preview confirmation. `Esc` skips the form and marks the server as "Needs config".

During form entry, **each required field shows an acquisition link**:
- If the registry provides a URL (`whereToGet`), it shows the URL directly
- Otherwise it shows the env var name for the user to find

### Installed / Pending List

Switch to the `Installed` source with `←/→` to see all servers in your current `mcp.json`:

- `✅ Ready` — Installed and fully configured
- `⚠ Needs config` — Installed but missing env vars or OAuth (missing keys listed in parentheses)

### Post-Install Usage

After the market writes to mcp.json, notify the adapter to load the new config:

```
/mcp reconnect          # Reconnect all MCP servers
/mcp reconnect <name>   # Reconnect only one
# Or simply
/reload
```

Then open the `/mcp` panel to see server status:
- Green ✅ — Connected
- Yellow ⚠ — Needs auth (run `/mcp-auth <name>`)
- Red ❌ — Connection failed

#### Common Connection Failures

| Connection Type | Failure | Solution |
|----------------|---------|----------|
| `npx` command | `Connection closed`, process exits | Manually run `npx -y <package>` in terminal to see the error (wrong package name, Node version, missing deps) |
| `url` remote | `401 Unauthorized` / `endpoint returned application/json` | Check if API Key is needed; configure `auth: "bearer"` + `bearerTokenEnv` in mcp.json; verify the correct endpoint URL |
| `url` remote | `OAuth required` | Run `/mcp-auth <server-name>` to complete OAuth authorization |
| `bearerTokenEnv` | `env var not set` | Set the env var, e.g. `export MY_API_KEY=xxx`, then `/reload` |

#### Getting an API Key

1. Find the service's **official website** (GitHub or homepage links appear in the market detail)
2. Register an account, go to Developer Settings / API Keys
3. Create an API Key and set it as an environment variable `export KEY_NAME=<your_key>`
4. Run `/reload` to retry

Three built-in market sources, zero configuration required:

| Source | Count | Install Method | Auth Hints |
|--------|-------|----------------|------------|
| **Official Registry** | ~200 | Remote URL | Auto-extracts `whereToGet` from headers + websiteUrl fallback |
| **Smithery** | ~2,000 | `npx @smithery/cli run` | Interactive runtime config |
| **DeepNLP** | ~11,700 | OneKey remote URL or npx (GitHub) | Shows acquisition URL (credits-based billing, not fully free) |

Configure custom sources by editing `<agentDir>/pi-mcp-market/registries.json`:

```json
{
  "registries": [
    { "id": "my-registry", "name": "My Source", "url": "https://example.com/mcp-registry.json" }
  ]
}
```

Supported formats: `native` (default), `official`, `smithery`, `deepnlp`, `glama`.

## Usage Examples

**Search MCP servers:**

```
/mcp market map
```

The panel shows servers from all sources whose name, description, or tags contain "map".

**Install Google Maps MCP:**

1. Navigate with `↑/↓` to Google Maps → `🔑` badge (needs API Key) and tool count shown
2. `Enter` → form for required env var appears with acquisition URL if available
3. Confirm preview → shows env var name and acquisition URL
4. `Enter` to confirm → writes to `~/.pi/agent/mcp.json`
5. Run `/reload` to activate

**View tool details:**

When a server is focused, the detail line shows the exposed tool count (e.g. `🧰 7 tools`) and whether the config can be previewed before install.

## Configuration

### registries.json

Located at `<agentDir>/pi-mcp-market/registries.json`.

```json
{
  "registries": [
    { "id": "official", "name": "Official Registry", "url": "https://registry.modelcontextprotocol.io/v0/servers", "format": "official" },
    { "id": "smithery", "name": "Smithery", "url": "https://registry.smithery.ai/servers", "format": "smithery" },
    { "id": "deepnlp", "name": "DeepNLP", "url": "https://www.deepnlp.org/api/mcp_marketplace/v1?page_id=0&count_per_page=500", "format": "deepnlp" }
  ]
}
```

If the file is missing or corrupt, the above defaults are used. An empty array `{ "registries": [] }` disables all remote sources.

#### Auth

```json
{
  "id": "private-source",
  "name": "Private Source",
  "url": "https://example.com/registry",
  "headers": { "Authorization": "Bearer {{API_KEY}}" },
  "apiKeyEnv": "MY_REGISTRY_KEY"
}
```

- `headers` — Static request headers with `{{API_KEY}}` placeholder support
- `apiKeyEnv` — Read from `process.env` at request time (never persisted); source fails when unset

#### Format Reference

| format | Input | Transport | Install Form |
|--------|-------|-----------|--------------|
| `native` | `MarketServer[]` | From entry | Written verbatim to mcp.json |
| `official` | `{ servers: [{ server: { name, title, description, remotes } }] }` | `streamable-http` from `server.remotes[]` | Remote URL |
| `smithery` | `{ servers: [{ qualifiedName, displayName }] }` | None | `npx -y @smithery/cli run <qualifiedName>` |
| `deepnlp` | `{ items: [{ content_name, id, description, github, ext_info: { tools } }] }` | OneKey URL (`https://agent.deepnlp.org/mcp?server_name=...&onekey=...`) or npx | Remote URL preferred (OneKey routes through DeepNLP proxy, **credits-based billing**: free trial → Pro $9.9/month) |
| `glama` | `{ servers: [...] }` | None | Metadata only, all entries skipped |

### Safety Guarantees

All writes target `<agentDir>/mcp.json` (usually `~/.pi/agent/mcp.json`).

- Missing file → created
- Corrupt file → backed up as `.backup-<timestamp>.json`, error reported, **never silently overwritten**
- Each mutation re-reads the file first; only adds/removes the target entry, leaves other config untouched

> ⚠️ Env var values are stored in plaintext per the MCP standard. Protect your file permissions.

## Development

```bash
npm install
npm run typecheck   # tsc --noEmit
npm test            # vitest run (61 tests)
```

Tests use a temporary `PI_CODING_AGENT_DIR` and never touch real configuration.

## Architecture

```
┌──────────────┐  /mcp market → openMarket()
│   index.ts    │──→ reads source list from registries.json
└──────┬───────┘     → panel opens immediately
       │
       ▼
┌──────────────┐          ┌───────────────────┐
│ market-panel │──→ per   │   loadRemoteRegistry()  │← Official Registry
│  (TUI panel) │    source│   (catalog.ts)     │← Smithery
│              │    load  │                    │← DeepNLP
└──────────────┘          └───────────────────┘
       │  each source done → applyRegistryResult()
       ▼  appended to aggregatedServers → re-render
┌──────────────┐
│  mcp.json   │←── Enter → preview → confirm → write
└──────────────┘
```

- `index.ts` — Extension entry, command registration
- `src/i18n.ts` — i18n dictionary (Chinese/English)
- `src/lang-config.ts` — Language persistence (read/write `language.json`)
- `src/config.ts` — Atomic mcp.json I/O, registry config management
- `src/catalog.ts` — Remote source fetching + format normalization
- `src/market-panel.ts` — Keyboard-driven TUI panel (i18n-aware)
- `src/registry-detect.ts` — Adapter detection
- `src/types.ts` — Shared type definitions