Skip to content

Commit 62a9e29

Browse files
authored
feat: add OpenViking control plane MCP server + CLI (#408)
* feat(openviking-controlplane): add control-plane MCP server and CLI Add a new package that exposes the OpenViking control plane (topapi · top cluster) collection-management Actions as both an MCP server and a Typer CLI, sharing one core (client.py) so each Action is available from both front-ends. - 6 core Actions: list / create / get / delete / usage / api-key (GetOpenVikingCollectionUserAccess) - Pluggable auth (common/auth.py): dev-phase ManualHeadersAuth replays headers supplied manually (e.g. copied from the browser); AuthProvider leaves room for a future AK/SK signer or dedicated API key without touching client/tool/cli. - MCP server defaults to stdio (uvx-launchable); create/delete are exposed with confirm-first guidance in their tool descriptions. - Lazy config from VIKING_HOST / VIKING_HEADERS_FILE|VIKING_HEADERS / VIKING_SCHEMA / OPENVIKING_PROJECT; headers file accepts JSON or raw 'Key: Value' blocks. * feat(openviking-controlplane): target console proxy endpoint, verified live Switch the request model to the console proxy the browser actually uses, and verify the read-only Actions against the live staging console. - Endpoint: POST {schema}://{host}/api/top/{service}/{region}/{api_version}/{Action} with Action/Version in the path (no query params); body is the Action params. - Extract host/region/service/api_version into config (VIKING_HOST default console.volcengine.com, VIKING_REGION=cn-beijing, VIKING_API_SERVICE=vikingdb, VIKING_API_VERSION=2025-06-09) and expose them as CLI flags + ControlPlaneConfig.action_path(). - Correct the api-key Action: the doc's GetOpenVikingCollectionUserAccess does not exist on the console; use AccessOpenVikingApiKey (returns the default user's plaintext {UserID, Role, ApiKey}). ListOpenVikingUser only returns a masked key. - Live-verified read-only: list / get / usage / api-key. create/delete unchanged (not exercised live as they are billable). - READMEs updated for the console endpoint, new env vars, and verified Action names. * feat(openviking-controlplane): switch to AgentPlan Bearer auth + data-plane endpoint The control-plane TopAPI is now compiled into the OpenViking data-plane cluster and authenticated with an Ark AgentPlan ApiKey. Replace the dev-phase console-proxy approach accordingly: - auth: drop ManualHeadersAuth (browser cookie/JWT replay); add BearerTokenAuth that sends Authorization: Bearer <key> (the backend only accepts Bearer, not X-API-Key). - endpoint: single base URL config (VIKING_ENDPOINT / --endpoint), default https://api.vikingdb.cn-beijing.volces.com/openviking (reserved public gateway, not live yet); action path is /api/openviking/{Action}, no query. - config: slim to api_key/endpoint/project; drop headers/region/service/ api_version and all header-blob parsing. - client: fix api-key action name AccessOpenVikingApiKey -> GetOpenVikingCollectionUserAccess (the former 404s on the data cluster); emit the new multi-credential create format (VLM/Embedding carry a Credentials[] list; source moves into each credential); for source=agentplan the model ApiKey falls back to the configured key and model names default. - cli: replace --host/--schema/--region/--service/--api-version/--headers-file /--header with --endpoint/-e and --api-key/-k. - docs: rewrite README/README_zh for Bearer-only auth and the new endpoint. Verified against the staging data-plane pod via port-forward: list returns 200, missing auth returns 401, create reaches the backend (blocked only by the account-side AgentPlan order gate, ProductUnordered). End-to-end create/provisioning + data-plane key verification still pending an account with AgentPlan deduction enabled. * refactor(openviking-controlplane): rename API key env var to AGENTPLAN_API_KEY The key is an Ark AgentPlan ApiKey; name the env var accordingly. VIKING_API_KEY -> AGENTPLAN_API_KEY across config, CLI help, and docs. VIKING_ENDPOINT / OPENVIKING_PROJECT are unchanged (not AgentPlan-specific). * docs(openviking-controlplane): add ov-cp agent skill; env-var usage; keep default endpoint - Add skills/openviking-controlplane/SKILL.md documenting the ov-cp workflow (config, commands, agentplan create defaults, cold-start chain, data-plane key usage) and link it from the READMEs. - Show env-var-based CLI usage (export AGENTPLAN_API_KEY, then no per-command flag). - Stop customizing VIKING_ENDPOINT in the primary examples / .mcp.json — use the default endpoint and document overriding it (for port-forward testing) only as a note. * feat(openviking-controlplane): drop AgentFileNum from usage output AgentFileNum is not meaningful for control-plane usage; strip it in the shared client.get_usage so both the CLI and MCP tool omit it. Update the tool docstring accordingly.
1 parent 4f305c5 commit 62a9e29

13 files changed

Lines changed: 2179 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# OpenViking Control Plane — MCP Server + CLI
2+
3+
MCP server **and** CLI for the OpenViking control plane (topapi) — manage OV
4+
libraries (`Collection`). Both front-ends share one core (`client.py`), so a tool
5+
added once is available from MCP and the CLI alike.
6+
7+
Covers the 6 core control-plane Actions:
8+
9+
| Action | MCP tool | CLI command |
10+
|---|---|---|
11+
| `ListOpenVikingCollections` | `list_collections` | `ov-cp list` |
12+
| `CreateOpenVikingCollection` | `create_collection` ⚠️ | `ov-cp create` |
13+
| `GetOpenVikingCollection` | `get_collection` | `ov-cp get <rid>` |
14+
| `DeleteOpenVikingCollection` | `delete_collection` ⚠️ | `ov-cp delete <rid>` |
15+
| `GetOpenVikingUsage` | `get_usage` | `ov-cp usage <rid>` |
16+
| `GetOpenVikingCollectionUserAccess` | `get_collection_api_key` | `ov-cp api-key <rid>` |
17+
18+
## Endpoint
19+
20+
The control-plane TopAPI is compiled into the OpenViking **data-plane cluster**;
21+
each Action is served by the data-plane gateway at:
22+
23+
```text
24+
{endpoint}/api/openviking/{Action}
25+
# default endpoint: https://api.vikingdb.cn-beijing.volces.com/openviking
26+
# full URL e.g.: https://api.vikingdb.cn-beijing.volces.com/openviking/api/openviking/ListOpenVikingCollections
27+
```
28+
29+
The Action lives in the **path** (no `?Action=&Version=` query). The request body
30+
is the Action's params (e.g. `{"ResourceID": "..."}`).
31+
32+
> The default endpoint points at the **reserved** public data-plane gateway (not
33+
> open to traffic yet). For local testing set `--endpoint` / `VIKING_ENDPOINT` to a
34+
> `kubectl port-forward`, e.g. `http://localhost:18080`.
35+
36+
## Authentication
37+
38+
The only method: an **Ark AgentPlan ApiKey**, sent as an `Authorization: Bearer
39+
<key>` header on every request (the backend's `authorizeControlPlaneByArk` reads
40+
the key only from this header — it does **not** accept `X-API-Key`). Auth is
41+
pluggable (`common/auth.py``BearerTokenAuth`); an AK/SK signer can be swapped in
42+
later without touching the rest.
43+
44+
> ⚠️ Write actions like `create` require the account to have **AgentPlan deduction
45+
> activated**, otherwise they return `ProductUnordered`. Read-only actions
46+
> (list/get/usage/delete) are not gated.
47+
48+
### Configuration
49+
50+
| Setting | Env var | CLI flag | Default |
51+
|---|---|---|---|
52+
| Control-plane endpoint (base URL) | `VIKING_ENDPOINT` | `--endpoint` / `-e` | `https://api.vikingdb.cn-beijing.volces.com/openviking` |
53+
| AgentPlan ApiKey | `AGENTPLAN_API_KEY` | `--api-key` / `-k` | — (required) |
54+
| Default project | `OPENVIKING_PROJECT` | `--project` | `default` |
55+
56+
## CLI usage
57+
58+
```bash
59+
uv sync # or: pip install -e .
60+
61+
# set the key once via env, then drop the per-command flag
62+
export AGENTPLAN_API_KEY=ark-xxxxxxxx
63+
64+
# read-only
65+
uv run ov-cp list
66+
uv run ov-cp get <ResourceID>
67+
uv run ov-cp usage <ResourceID>
68+
uv run ov-cp api-key <ResourceID>
69+
70+
# create (consumes paid quota; with source=agentplan only --name is needed —
71+
# model names default, and the model ApiKey falls back to the configured key)
72+
uv run ov-cp create --name my_kb
73+
74+
# delete (irreversible)
75+
uv run ov-cp delete <ResourceID> --yes
76+
```
77+
78+
Flags override env. The endpoint defaults to the public gateway; override it only
79+
for testing (e.g. against a port-forward) with `-e` / `VIKING_ENDPOINT`
80+
`uv run ov-cp -e http://localhost:18080 list`.
81+
`ov-cp --help` works without any config.
82+
83+
## MCP usage (stdio / uvx)
84+
85+
The server defaults to **stdio** transport, so it can be launched as a subprocess by
86+
any MCP client. Add to `.mcp.json`:
87+
88+
```json
89+
{
90+
"mcpServers": {
91+
"openviking-controlplane": {
92+
"command": "uvx",
93+
"args": [
94+
"--from",
95+
"git+https://github.com/volcengine/mcp-server#subdirectory=server/mcp_server_openviking_controlplane",
96+
"mcp-server-openviking-controlplane"
97+
],
98+
"env": {
99+
"AGENTPLAN_API_KEY": "ark-xxxxxxxx"
100+
}
101+
}
102+
}
103+
}
104+
```
105+
106+
For local development point it at your checkout instead:
107+
108+
```json
109+
{
110+
"mcpServers": {
111+
"openviking-controlplane": {
112+
"command": "uv",
113+
"args": ["run", "--directory", "/abs/path/server/mcp_server_openviking_controlplane",
114+
"mcp-server-openviking-controlplane"],
115+
"env": {
116+
"AGENTPLAN_API_KEY": "ark-xxxxxxxx"
117+
}
118+
}
119+
}
120+
}
121+
```
122+
123+
Run with SSE instead via `mcp-server-openviking-controlplane --transport sse`.
124+
125+
## Agent skill
126+
127+
A Claude Code / agent skill that documents the `ov-cp` workflow lives at
128+
[`skills/openviking-controlplane/SKILL.md`](skills/openviking-controlplane/SKILL.md).
129+
Symlink or copy it into your agent's skills directory (e.g. `~/.claude/skills/`) to
130+
let an agent drive the control plane.
131+
132+
> ⚠️ `create_collection` / `delete_collection` create/destroy **billable** resources and
133+
> are exposed as MCP tools; their descriptions instruct the model to confirm with you
134+
> first. Rely on your client's tool-permission prompt as the final gate.
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# OpenViking 控制面 — MCP Server + CLI
2+
3+
OpenViking 控制面(topapi)的 MCP Server **** CLI —— 用于管理 OV 库
4+
`Collection`)。两个前端共用同一套核心(`client.py`),新增一个能力即可同时被 MCP
5+
和 CLI 使用。
6+
7+
覆盖 6 个核心控制面 Action:
8+
9+
| Action | MCP tool | CLI 命令 |
10+
|---|---|---|
11+
| `ListOpenVikingCollections` | `list_collections` | `ov-cp list` |
12+
| `CreateOpenVikingCollection` | `create_collection` ⚠️ | `ov-cp create` |
13+
| `GetOpenVikingCollection` | `get_collection` | `ov-cp get <rid>` |
14+
| `DeleteOpenVikingCollection` | `delete_collection` ⚠️ | `ov-cp delete <rid>` |
15+
| `GetOpenVikingUsage` | `get_usage` | `ov-cp usage <rid>` |
16+
| `GetOpenVikingCollectionUserAccess` | `get_collection_api_key` | `ov-cp api-key <rid>` |
17+
18+
## 端点
19+
20+
控制面 TopAPI 接口已编译进 OpenViking **数据面集群**,每个 Action 由数据面网关在如下路径提供:
21+
22+
```text
23+
{endpoint}/api/openviking/{Action}
24+
# 默认 endpoint:https://api.vikingdb.cn-beijing.volces.com/openviking
25+
# 完整 URL 例:https://api.vikingdb.cn-beijing.volces.com/openviking/api/openviking/ListOpenVikingCollections
26+
```
27+
28+
Action 在 **path** 里(不走 `?Action=&Version=` query)。请求体是该 Action 的参数(如
29+
`{"ResourceID": "..."}`)。
30+
31+
> 默认 endpoint 指向**预留**的公网数据面网关(尚未对外开放)。本地/联调时用
32+
> `--endpoint` / `VIKING_ENDPOINT` 指向一个 `kubectl port-forward`,例如
33+
> `http://localhost:18080`
34+
35+
## 鉴权
36+
37+
唯一方式:**Ark AgentPlan ApiKey**,作为 `Authorization: Bearer <key>` 头随每个请求发送
38+
(后端 `authorizeControlPlaneByArk` 只认 Bearer,**不兼容 `X-API-Key`**)。鉴权是可插拔的
39+
`common/auth.py``BearerTokenAuth`),后续要换 AK/SK 签名时只需替换这一处。
40+
41+
> ⚠️ `create` 等写接口要求账号已**开通 AgentPlan 抵扣**,否则返回 `ProductUnordered`
42+
> 只读接口(list/get/usage/delete)不受此限。
43+
44+
### 配置
45+
46+
|| 环境变量 | CLI 参数 | 默认 |
47+
|---|---|---|---|
48+
| 控制面 endpoint(base URL) | `VIKING_ENDPOINT` | `--endpoint` / `-e` | `https://api.vikingdb.cn-beijing.volces.com/openviking` |
49+
| AgentPlan ApiKey | `AGENTPLAN_API_KEY` | `--api-key` / `-k` | —(必填) |
50+
| 默认 project | `OPENVIKING_PROJECT` | `--project` | `default` |
51+
52+
## CLI 用法
53+
54+
```bash
55+
uv sync # 或:pip install -e .
56+
57+
# 把 key 用环境变量配一次,之后免传参
58+
export AGENTPLAN_API_KEY=ark-xxxxxxxx
59+
60+
# 只读
61+
uv run ov-cp list
62+
uv run ov-cp get <ResourceID>
63+
uv run ov-cp usage <ResourceID>
64+
uv run ov-cp api-key <ResourceID>
65+
66+
# 建库(消耗付费配额;source=agentplan 时只需 --name,
67+
# 模型名取默认、模型 ApiKey 回落到配置的 key)
68+
uv run ov-cp create --name my_kb
69+
70+
# 删库(不可逆)
71+
uv run ov-cp delete <ResourceID> --yes
72+
```
73+
74+
命令行参数优先于环境变量。端点默认指向公网网关;仅在测试时(如指向 port-forward)才用
75+
`-e` / `VIKING_ENDPOINT` 覆盖:`uv run ov-cp -e http://localhost:18080 list`
76+
`ov-cp --help` 不需要任何配置即可运行。
77+
78+
## MCP 用法(stdio / uvx)
79+
80+
Server 默认 **stdio** 传输,可被任意 MCP 客户端作为子进程拉起。`.mcp.json` 配置:
81+
82+
```json
83+
{
84+
"mcpServers": {
85+
"openviking-controlplane": {
86+
"command": "uvx",
87+
"args": [
88+
"--from",
89+
"git+https://github.com/volcengine/mcp-server#subdirectory=server/mcp_server_openviking_controlplane",
90+
"mcp-server-openviking-controlplane"
91+
],
92+
"env": {
93+
"AGENTPLAN_API_KEY": "ark-xxxxxxxx"
94+
}
95+
}
96+
}
97+
}
98+
```
99+
100+
本地开发可改指向你的代码检出:
101+
102+
```json
103+
{
104+
"mcpServers": {
105+
"openviking-controlplane": {
106+
"command": "uv",
107+
"args": ["run", "--directory", "/abs/path/server/mcp_server_openviking_controlplane",
108+
"mcp-server-openviking-controlplane"],
109+
"env": {
110+
"AGENTPLAN_API_KEY": "ark-xxxxxxxx"
111+
}
112+
}
113+
}
114+
}
115+
```
116+
117+
需要 SSE 时:`mcp-server-openviking-controlplane --transport sse`
118+
119+
> ⚠️ `create_collection` / `delete_collection` 会创建/销毁**付费**资源,且已暴露为 MCP
120+
> tool;其描述会要求模型先与你确认。最终拦截依赖客户端的工具授权弹窗。
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[project]
2+
name = "mcp-server-openviking-controlplane"
3+
version = "0.1.0"
4+
description = "MCP server and CLI for the OpenViking control plane (topapi) collection management"
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
license = {text = "MIT"}
8+
dependencies = [
9+
"mcp[cli]>=1.5.0",
10+
"requests>=2.31.0",
11+
"typer>=0.12.0",
12+
]
13+
14+
[project.scripts]
15+
mcp-server-openviking-controlplane = "mcp_server_openviking_controlplane.server:main"
16+
ov-cp = "mcp_server_openviking_controlplane.cli:main"
17+
18+
[build-system]
19+
requires = ["hatchling"]
20+
build-backend = "hatchling.build"
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
name: openviking-controlplane
3+
description: Manage OpenViking collections (OV libraries) from the command line with `ov-cp` — list / create / get / usage / get the data-plane API key / delete. Use when the user wants to provision or inspect an OpenViking library, fetch a library's data-plane API key, do the create→get-key cold-start, or otherwise drive the OpenViking control plane (topapi). Authenticates with an Ark AgentPlan ApiKey.
4+
---
5+
6+
# OpenViking Control Plane (`ov-cp`)
7+
8+
`ov-cp` is the CLI for the OpenViking control plane (topapi). It manages OV
9+
**collections** (libraries) and shares its core with the
10+
`mcp-server-openviking-controlplane` MCP server, so behavior is identical.
11+
12+
## Setup
13+
14+
Install once (from the package dir): `uv sync` (or `pip install -e .`).
15+
16+
Configure via env vars (CLI flags `-k` / `-e` / `--project` override them):
17+
18+
| Env var | Meaning | Default |
19+
|---|---|---|
20+
| `AGENTPLAN_API_KEY` | Ark AgentPlan ApiKey (sent as `Authorization: Bearer`) | — (required) |
21+
| `VIKING_ENDPOINT` | Control-plane base URL | `https://api.vikingdb.cn-beijing.volces.com/openviking` |
22+
| `OPENVIKING_PROJECT` | Default project | `default` |
23+
24+
```bash
25+
export AGENTPLAN_API_KEY=ark-xxxxxxxx
26+
# VIKING_ENDPOINT defaults to the public gateway — leave it unset for normal use.
27+
```
28+
29+
> The default endpoint is the **reserved** public gateway (not open yet). Override
30+
> `VIKING_ENDPOINT` (or `-e`) only for testing — e.g. point it at a `kubectl
31+
> port-forward` of the data-plane service. The full request URL is
32+
> `{endpoint}/api/openviking/{Action}`.
33+
34+
## Commands
35+
36+
```bash
37+
ov-cp list # list collections (optionally --project X)
38+
ov-cp get <ResourceID> # collection info (Status, models, version, ...)
39+
ov-cp usage <ResourceID> # file counts / estimated cost
40+
ov-cp api-key <ResourceID> # plaintext data-plane key {UserID, Role, ApiKey}
41+
ov-cp create --name my_kb # create a collection (see below)
42+
ov-cp delete <ResourceID> --yes # delete (irreversible; uninstalls the Helm release)
43+
```
44+
45+
Output is JSON. Errors print `Error [Code]: Message` to stderr with exit code 1.
46+
`ov-cp --help` and `ov-cp <cmd> --help` work without any config.
47+
48+
## Creating a collection
49+
50+
⚠️ **Billable + requires the account to have AgentPlan deduction activated** (else
51+
`ProductUnordered`). Confirm with the user before creating. Max 20 libraries/account.
52+
53+
For `--source agentplan` (default) you only need `--name`: the VLM/Embedding model
54+
names default to `doubao-seed-2.0-lite` / `doubao-embedding-vision`, and the model
55+
ApiKey falls back to the configured AgentPlan key.
56+
57+
```bash
58+
ov-cp create --name my_kb
59+
# other sources need explicit model creds:
60+
ov-cp create --name my_kb --source volcengine \
61+
--vlm-api-key-id <id> --vlm-endpoint-id <ep> \
62+
--emb-api-key-id <id> --emb-endpoint-id <ep>
63+
```
64+
65+
## Cold-start chain (create → use the library)
66+
67+
```bash
68+
RID=$(ov-cp create --name my_kb | python3 -c 'import sys,json;print(json.load(sys.stdin)["ResourceID"])')
69+
# Poll until provisioned; api-key times out while Status is INIT.
70+
ov-cp get "$RID" # wait for "Status": "READY"
71+
ov-cp api-key "$RID" # -> the plaintext data-plane key for the library
72+
```
73+
74+
The returned `ApiKey` is the library's **data-plane** key. Use it as
75+
`Authorization: Bearer <key>` against the library's data-plane (e.g.
76+
`GET {endpoint}/health`, `GET {endpoint}/api/v1/system/status`,
77+
`GET {endpoint}/api/v1/fs/ls?uri=viking://`).
78+
79+
## Notes
80+
81+
- Only `Authorization: Bearer` is accepted (no `X-API-Key`).
82+
- Read-only actions (list/get/usage/delete) are not gated by AgentPlan; create and
83+
api-key are.
84+
- `get`/`usage`/`api-key`/`delete` take a `ResourceID` (e.g. `ov-xxxxxxxx`).

server/mcp_server_openviking_controlplane/src/mcp_server_openviking_controlplane/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)