MCP tools and protocol
OpenViking Server includes an MCP (Model Context Protocol) endpoint. Clients supporting Streamable HTTP can connect directly. Clients supporting only stdio can use the proxy in the Agent Plugins package.
Quick setup? See MCP Clients for client configuration snippets and platform-specific notes. This page covers the full tool reference and advanced configuration.
Prerequisites
Use a running OpenViking service and credentials for that service. For a new self-hosted deployment, follow the Quick Start first. A managed or existing service does not require a local server installation.
The MCP endpoint is at http://<server>:1933/mcp, sharing the same process and port as the REST API.
Client Connections
The following table links the available connection configurations. Verify tool discovery and a permitted data read with your client version:
| Platform | Integration Method |
|---|---|
| Claude Code | type: http |
| Trae | Standard MCP config |
| Cursor | Standard MCP config |
| ChatGPT | Custom App with OAuth; see the OAuth guide |
| Codex | MCP configuration in the Codex integration |
| OpenCode | Native OpenCode mcp config |
| Manus | Standard MCP config |
| Claude.ai / Claude Desktop | Native OAuth 2.1 (see 11-oauth) |
Authentication
MCP uses the server authentication configuration. In API Key mode, use a User/Admin key with either header:
X-Api-Key: <your-key>Authorization: Bearer <your-key>
Only dev mode disables authentication; binding to localhost alone does not. OAuth clients follow the authorization flow below; see Authentication for other server modes.
Client Configuration
Generic MCP Clients
Clients accepting mcpServers and custom headers can use the following example. Check the client documentation for its field names and transport settings:
{
"mcpServers": {
"openviking": {
"url": "https://your-server.com/mcp",
"headers": {
"Authorization": "Bearer your-api-key-here"
}
}
}
}Claude Code
Claude Code requires "type": "http". Add via CLI:
claude mcp add --transport http openviking \
https://your-server.com/mcp \
--header "Authorization: Bearer your-api-key-here"Or in .mcp.json:
{
"mcpServers": {
"openviking": {
"type": "http",
"url": "https://your-server.com/mcp",
"headers": {
"Authorization": "Bearer your-api-key-here"
}
}
}
}Add --scope user to make the config global (shared across all projects).
OpenCode
Configure ~/.config/opencode/opencode.json:
{
"mcp": {
"openviking": {
"type": "remote",
"url": "https://your-server.com/mcp",
"enabled": true,
"oauth": false,
"headers": {
"Authorization": "Bearer your-api-key-here"
}
}
}
}Claude.ai / Claude Desktop (OAuth)
For remote connectors configured through the Claude.ai / Claude Desktop connector UI, use the OAuth flow below. OpenViking ships a native OAuth 2.1 implementation (DCR + PKCE + opaque tokens, backed by SQLite, with a Studio consent screen for authorization) so no external proxy is needed.
Enable oauth.enabled on the server and configure HTTPS as described in the OAuth guide. Then connect the client to https://your-server.com/mcp and complete authorization in the browser.
See the OAuth 2.1 Guide and Public Access Guide for:
- Studio consent flow and the optional 6-character-code fallback for cross-device authorization
- HTTP (local) and HTTPS (production) deployment, including Caddy and nginx reverse-proxy templates plus a docker-compose example
- Connecting Claude.ai / Claude Desktop step by step
OPENVIKING_PUBLIC_BASE_URLand theoauthconfig block- Token model (
ovat_/ovrt_/ovac_prefixes) and revocation
Available MCP Tools
The built-in MCP tools are listed below. Use the connected server's tools/list response to determine which tools are available:
| Tool | Description | Key Parameters |
|---|---|---|
find | Fast semantic retrieval without session context. context_type="skill" on its own switches to package-level skill retrieval: one hit per skill package, its URI pointing at that package's SKILL.md and its summary taken from the skill itself, even when an auxiliary file inside the package is what matched. Without target_uri it searches both your own skills and the account-shared viking://agent/skills. Mixing skill with another context type keeps the generic retrieval path | query, target_uri (optional), limit, min_score, level (optional), context_type (optional), read_content (optional — inline each hit's content), events_time_decay_protection (optional) |
search | Deep semantic retrieval; mode="context" assembles injection-ready context and replaces the former recall tool. list mode also returns one hit per skill package, its URI pointing at SKILL.md and its summary taken from the package itself, but limit applies before that merge, so a package matching in several files takes several slots and fewer than limit results come back | query, mode (list or context), target_uri (list mode only), session_id (optional), limit, min_score, level (list mode), context_type (optional), events_time_decay_protection (optional in both modes), plus context-mode quotas, purpose, max_tokens, detail or detail_by_category, dedup_turns, exclude_uris, peer_scope, scalar other_peer_penalty or other_peer_penalties by category, and rewrite (off or auto) |
read | Read one or more viking:// URIs. PNG, JPEG, GIF, and WebP return native MCP image content; WAV, MP3, FLAC, OGG, and M4A return native audio content. Video is not supported because MCP has no standard video content block | uris (single string or array), offset, limit (text lines) |
list | List entries under a viking:// directory | uri, recursive, offset, limit, sort_by, sort_order (optional) |
tree | Show the recursive directory tree under a viking:// URI, indented by depth — use when you need a full picture of the file tree (prefer list for a single level, glob for filename patterns) | uri (optional), level_limit (default 3), node_limit (default 1000), offset, limit, include_abstract (optional — also show each directory's summary; for a skill directory that is its name and description) |
remember | Store messages into long-term memory (triggers extraction) | messages (list of {role, content}) |
write | Write text to a viking:// file (create/overwrite/append). Parent directories are created automatically; use read first to see current content before overwriting, and prefer edit for changing part of an existing file. Skill packages are not maintained this way: the caller's own skills/ subtree is refused, and a write under viking://agent/skills produces a plain file that skips skill installation — use add_skill | uri, content, mode (optional: replace default — overwrites or creates if missing; append — appends or creates if missing; create — fails if it exists), wait (optional, block until re-indexed), timeout (optional), acl (optional) |
edit | Replace an exact string with new text in an existing viking:// file — for targeted changes instead of a full rewrite. The file is left unchanged if old_string is not found, or matches multiple times while replace_all is false. Editing a file inside a skill package does not re-run skill installation — use add_skill | uri, old_string, new_string, replace_all (optional), wait (optional, block until re-indexed), timeout (optional) |
add_resource | Add a local file or URL as a resource (local files trigger a progressive upload flow) | path, temp_file_id (optional), description (optional), watch_interval (optional, minutes — auto-refresh cadence for remote URLs), processing_mode (optional: semantic_and_vectors default, or vectors_only to skip VLM semantic understanding and only vectorize current files), to (optional, target viking://resources/... URI; if omitted when watch_interval > 0, the watch auto-binds to the resource's created URI), args (optional parser-specific options, including {"parse_mode":"no_split"} to parse each source document into one Markdown body, {"feishu_access_token":"u-..."} for one-time Feishu user-token imports, or access/refresh tokens plus an optional feishu_app_id / feishu_app_secret pair for Feishu user-token watches), acl (optional) |
add_skill | Create, install, or replace an agent skill. New skills pass the full SKILL.md text; Git and GitHub tree URLs install every skill in the source unless skills names some; a local SKILL.md, directory, or zip returns a signed upload URL like add_resource | data (SKILL.md text) or path (Git URL or local path), skills (optional), target_uri (optional; viking://agent/skills shares with the account), list_only (optional) |
list_watches | List watch tasks (auto-refresh subscriptions) visible to the current agent. Each entry shows target URI, refresh interval (minutes), active/paused status, and next scheduled execution time | none |
cancel_watch | Cancel (delete) a watch task by its target URI. To change the cadence or pause temporarily, cancel and re-add with a new watch_interval | to_uri (must match the watch task's to value, e.g. viking://resources/...) |
grep | Regex content search across viking:// files | uri, pattern (string or array), case_insensitive, node_limit |
glob | Find files matching a glob pattern | pattern, uri (optional scope), node_limit |
forget | Delete any viking:// URI (use search to find it first; pass recursive=true to delete a directory). Deleting a skill directory this way leaves the skill's privacy configuration behind; remove a skill with ov skills remove or DELETE /api/v1/skills/{name} | uri, recursive (optional) |
health | Check OpenViking service health | none |
list_users | Find user IDs in the caller's account; credentials are excluded by default, including for administrators | query (ID substring), limit (100), page (1), include_credentials (false; true requires ADMIN/ROOT) |
list_groups | List group IDs in the caller's account without membership | None |
get_acl | Read direct, inherited and effective ACL; requires resource manage or account ADMIN | uri |
set_acl | Update a shared resource ACL; authorize against the permissions before the change | uri, acl |
To address your own workspace from an MCP tool, use the home alias viking://~. It expands to viking://user/<current-user> on every control plane (REST API, ov CLI, SDKs, and MCP alike), so viking://~/notes/todo.md resolves to viking://user/<current-user>/notes/todo.md. Responses always echo the expanded canonical URI, and those canonical URIs are accepted as tool input as well.
The uid-less spelling viking://user/<segment>/... (memories, resources, skills, peers, privacy, sessions) is no longer accepted; such calls fail with an error that points at the viking://~/... replacement. viking://user on its own is the container of user spaces, not a shortcut to yours. See Viking URI for details.
Note: MCP exposes the minimum closure for watch management (
list_watches+cancel_watch). Pause / resume / trigger and the unifiedupdateverb are intentionally not exposed here — use the REST/api/v1/watches/*endpoints or theov task watchCLI for those operations.
Feishu/Lark imports without
args.feishu_access_tokenkeep the existing app/tenant-token behavior and can be watched. One-time user-token imports pass onlyargs.feishu_access_token; user-token watches must also passargs.feishu_refresh_token. They may passargs.feishu_app_idandargs.feishu_app_secrettogether for that watch, or fall back to the server app credentials. The app must match the issuer of the user token.
processing_mode=vectors_onlyskips the VLM semantic-understanding stage. It does not generate or refresh.abstract.md/.overview.md; it only vectorizes current non-hidden resource files, preserving any older semantic artifacts that already exist.
Resource permissions and sharing
All account users may call list_users and list_groups; neither tool accepts a different account. The default output contains only user IDs and a matching total, or group IDs. Even administrators must explicitly set include_credentials=true to include available credentials. A USER requesting credentials receives PERMISSION_DENIED, even when the query matches no users. Trusted auth mode forbids credential disclosure. Group membership remains available through the admin API.
get_acl and set_acl require resource manage permission. A resource manager does not gain account administrator privileges. write and add_resource accept an optional acl object; explicit ACL changes require manage on an existing target or inherited from the parent for a new target. Omitting ACL preserves an existing target's permissions or inherits on creation. Remote imports, temp-file imports and signed local uploads all carry ACL to the kernel's authorization checks.
For example, set_acl accepts:
{
"uri": "viking://resources/project-a",
"acl": {
"acl_mode": "restricted",
"entries": [{"principal": "user:bob", "level": "read"}]
}
}entries replaces direct grants; omit it to preserve them. inherit includes parent grants; restricted uses only direct grants. Reset with {"acl_mode":"inherit","entries":[]}. A restricted ACL can remove the caller's own access; account ADMIN retains implicit management access.
Failed tool calls set MCP isError=true and retain business codes such as PERMISSION_DENIED in text. Tools supporting structured output also include error.code/message/details alongside the existing result text. Partial batch reads or searches preserve successful results and report failed items separately.
Adding local-file resources (single-step upload)
The add_resource tool accepts both remote URLs and local file paths, handled differently:
- Remote URL (
http(s)://,git@,ssh://,git://): single round-trip — the server fetches and ingests directly. - Local file path: the tool returns an upload instruction (plain prose). The agent POSTs the file as
multipart/form-data(field namefile) to thetemp_uploadURL given in the response. The URL embeds a one-shot token (10-minute TTL by default) that authorizes the upload, so no API key is needed. The server automatically submits ingestion and returns the acceptance result; processing can continue in the background. The agent does not calladd_resourceagain.
In api_key auth mode, the token retains the role of the issuing MCP call, for both API-key and OAuth callers. Uploads are rejected if the user no longer exists, the identity is being deleted, or the role has been downgraded. A later promotion does not expand an existing token's permissions. Trusted-mode upload tokens continue to use the USER role.
A client that can read the source bytes and send a multipart HTTP request can upload without the ov CLI. A sandbox must provide those capabilities; an inaccessible local path alone cannot transfer a file. The token upload reuses the authenticated temp_upload route (API key first, otherwise the one-shot ?token=) and its TempUploadStore persistence, so the same local / shared upload modes apply. Note: the one-shot token is held in-process, so in a multi-worker deployment the add_resource call and the follow-up upload POST must reach the same worker (or run single-worker) for the token to resolve.
When you must set OPENVIKING_PUBLIC_BASE_URL
The upload URL the tool returns is resolved server-side in this order:
- Environment variable
OPENVIKING_PUBLIC_BASE_URL server.public_base_urlinov.conf- Request headers
X-Forwarded-Host/X-Forwarded-Proto(forwarded by the reverse-proxy chain) - Request
Hostheader (direct connection) - Listen-address fallback:
http://{host}:{port}
If the server runs behind a reverse proxy (nginx / cloud LB / k8s ingress / MCP proxy), set OPENVIKING_PUBLIC_BASE_URL explicitly. Layers 3–5 are inferred and break in these cases:
- The reverse proxy / MCP proxy does not forward
X-Forwarded-*headers - The server listens on
0.0.0.0(fallback URL contains0.0.0.0, unreachable from agents) - Multi-hop proxy with host rewriting
When the variable is unset and inference is used, the tool response automatically appends a hint asking the user to configure it. Docker Compose example:
services:
openviking:
# Prefer ghcr.io. If it is hard to reach, use openviking-cn-beijing.cr.volces.com/volcengine/openviking:latest
image: ghcr.io/volcengine/openviking:latest
environment:
OPENVIKING_PUBLIC_BASE_URL: "https://ov.your-domain.com"Troubleshooting
Connection refused
Likely cause: openviking-server is not running, or is running on a different port.
Fix: Verify the server is running:
curl http://localhost:1933/health
# Expected: {"status": "ok"}Authentication errors
Likely cause: The client key is invalid, expired, or not valid for tenant data access.
Fix: Use a valid user/admin key for the target account. In api_key mode, root keys are reserved for administration. See Authentication Guide.
References
Client configuration references: Claude Code MCP, OpenCode MCP servers.