Skip to content

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:

PlatformIntegration Method
Claude Codetype: http
TraeStandard MCP config
CursorStandard MCP config
ChatGPTCustom App with OAuth; see the OAuth guide
CodexMCP configuration in the Codex integration
OpenCodeNative OpenCode mcp config
ManusStandard MCP config
Claude.ai / Claude DesktopNative 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:

json
{
  "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:

bash
claude mcp add --transport http openviking \
  https://your-server.com/mcp \
  --header "Authorization: Bearer your-api-key-here"

Or in .mcp.json:

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:

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_URL and the oauth config 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:

ToolDescriptionKey Parameters
findFast 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 pathquery, target_uri (optional), limit, min_score, level (optional), context_type (optional), read_content (optional — inline each hit's content), events_time_decay_protection (optional)
searchDeep 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 backquery, 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)
readRead 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 blockuris (single string or array), offset, limit (text lines)
listList entries under a viking:// directoryuri, recursive, offset, limit, sort_by, sort_order (optional)
treeShow 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)
rememberStore messages into long-term memory (triggers extraction)messages (list of {role, content})
writeWrite 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_skilluri, 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)
editReplace 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_skilluri, old_string, new_string, replace_all (optional), wait (optional, block until re-indexed), timeout (optional)
add_resourceAdd 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_skillCreate, 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_resourcedata (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_watchesList 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 timenone
cancel_watchCancel (delete) a watch task by its target URI. To change the cadence or pause temporarily, cancel and re-add with a new watch_intervalto_uri (must match the watch task's to value, e.g. viking://resources/...)
grepRegex content search across viking:// filesuri, pattern (string or array), case_insensitive, node_limit
globFind files matching a glob patternpattern, uri (optional scope), node_limit
forgetDelete 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)
healthCheck OpenViking service healthnone
list_usersFind user IDs in the caller's account; credentials are excluded by default, including for administratorsquery (ID substring), limit (100), page (1), include_credentials (false; true requires ADMIN/ROOT)
list_groupsList group IDs in the caller's account without membershipNone
get_aclRead direct, inherited and effective ACL; requires resource manage or account ADMINuri
set_aclUpdate a shared resource ACL; authorize against the permissions before the changeuri, 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 unified update verb are intentionally not exposed here — use the REST /api/v1/watches/* endpoints or the ov task watch CLI for those operations.

Feishu/Lark imports without args.feishu_access_token keep the existing app/tenant-token behavior and can be watched. One-time user-token imports pass only args.feishu_access_token; user-token watches must also pass args.feishu_refresh_token. They may pass args.feishu_app_id and args.feishu_app_secret together for that watch, or fall back to the server app credentials. The app must match the issuer of the user token.

processing_mode=vectors_only skips 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:

json
{
  "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 name file) to the temp_upload URL 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 call add_resource again.

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:

  1. Environment variable OPENVIKING_PUBLIC_BASE_URL
  2. server.public_base_url in ov.conf
  3. Request headers X-Forwarded-Host / X-Forwarded-Proto (forwarded by the reverse-proxy chain)
  4. Request Host header (direct connection)
  5. 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 contains 0.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:

yaml
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:

bash
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.

Open source under the AGPL-3.0 License. Font licenses