MCP Servers
MCP servers extend your agent with tools from external services. Define them in your protocol, and agents automatically discover and use their tools at runtime.
There are three types of MCP servers:
| Source | Description | Example |
|---|---|---|
remote | HTTP-based MCP servers, managed by the platform | Figma, Sentry, GitHub |
device | Local MCP servers running on the agent's machine via @octavus/computer | Browser automation, filesystem |
consumer | Inline MCP servers defined in your server-sdk process via createInlineMcpServer() | Custom integrations, third-party APIs |
Defining MCP Servers
MCP servers are defined in the mcpServers: section. The key becomes the namespace for all tools from that server.
mcpServers:
figma:
description: Figma design tool integration
source: remote
display: description
browser:
description: Chrome DevTools browser automation
source: device
display: name
github:
description: Repository management - issues, pull requests, code
source: consumer
display: nameFields
| Field | Required | Description |
|---|---|---|
description | Yes | What the MCP server provides |
source | Yes | remote, device, or consumer (see source types above) |
display | No | How tool calls appear in UI: hidden, name, description, stream, title (default: description) |
title | No | UI label shown when display: title; applies to every tool in this namespace (hides description and arguments) |
connection | No | When to connect: eager or lazy (default: lazy). remote only. |
execution | No | Where the MCP process runs: sandbox (default) or device. remote only. See Device Execution. |
Display Modes
Display modes control visibility of all tool calls from the MCP server, using the same modes as regular tools:
| Mode | Behavior |
|---|---|
hidden | Tool calls run silently |
name | Shows tool name while executing |
description | Shows tool description while executing |
Making MCP Servers Available
Like tools, MCP servers defined in mcpServers: must be referenced in agent.mcpServers to be available:
mcpServers:
figma:
description: Figma design tool integration
source: remote
display: description
sentry:
description: Error tracking and debugging
source: remote
display: name
browser:
description: Chrome DevTools browser automation
source: device
display: name
filesystem:
description: Filesystem access for reading and writing files
source: device
display: hidden
agent:
model: anthropic/claude-sonnet-4-5
system: system
mcpServers: [figma, sentry, browser, filesystem]
tools: [set-chat-title]
agentic: true
maxSteps: 100Tool Namespacing
All MCP tools are automatically namespaced using __ (double underscore) as a separator. The namespace comes from the mcpServers key.
For example, a server defined as browser: that exposes navigate_page and click produces:
browser__navigate_pagebrowser__click
A server defined as figma: that exposes get_design_context produces:
figma__get_design_context
The namespace is stripped before calling the MCP server - the server receives the original tool name. This convention matches Anthropic's MCP integration in Claude Desktop and ensures tool names stay unique across servers.
What the LLM Sees
When an agent has both regular tools and MCP servers configured, the LLM sees all tools combined:
Protocol tools:
set-chat-title
Remote MCP tools (auto-discovered):
figma__get_design_context
figma__get_screenshot
sentry__get_issues
sentry__get_issue_details
Device MCP tools (auto-discovered):
browser__navigate_page
browser__click
browser__take_snapshot
filesystem__read_file
filesystem__write_file
filesystem__list_directory
Consumer MCP tools (provided by the server-sdk):
github__get-pr-overview
github__list-issuesYou don't define individual MCP tool schemas in the protocol - remote and device tools are auto-discovered from each MCP server at runtime, and consumer tools are supplied by the server-sdk.
Remote MCP Servers
Remote MCP servers (source: remote) connect to HTTP-based MCP endpoints. The platform manages the connection, authentication, and tool discovery.
Configuration happens in the Octavus platform UI:
- Add an MCP server to your project (URL + authentication)
- The server's slug must match the namespace in your protocol
- The platform connects, discovers tools, and makes them available to the agent
Connection Modes
The connection field controls when the platform connects to a remote MCP server:
| Mode | Behavior |
|---|---|
lazy | (default) The agent activates integrations on demand at runtime. The agent starts responding immediately. |
eager | The platform connects and discovers tools before the first LLM request. Tools are guaranteed available from message 1. |
mcpServers:
sentry:
source: remote
connection: eager # Always connected upfront
display: name
notion:
source: remote
# connection defaults to lazy - agent activates when needed
display: descriptionWith lazy connection (the default), the agent receives two built-in tools - one for listing available integrations and one for activating them. The agent decides which integrations it needs based on the conversation and activates them on demand. This avoids paying connection latency for integrations the agent doesn't end up using.
With eager connection, the platform connects to the MCP server before the first LLM request, exactly like a declared tool. Use this when the agent needs the MCP's tools from the very first message.
The connection field is only valid on source: remote - device MCPs (source: device) have their own connection mechanism through the server-sdk. The connection field is respected for remote MCPs with execution: device the same way as sandbox MCPs.
Authentication
Remote MCP servers support multiple authentication methods:
| Auth Type | Description |
|---|---|
| MCP OAuth | Standard MCP OAuth flow |
| API Key | Static API key sent as a header |
| Bearer | Bearer token authentication |
| None | No authentication required |
Authentication is configured per-project - different projects can connect to the same MCP server with different credentials.
Device Execution
The execution field controls where a remote MCP server's STDIO process runs. By default (execution: sandbox), the process runs in the platform's sandbox. When set to execution: device, the STDIO process runs on the agent's computer (VM or desktop) instead.
mcpServers:
code-tools:
description: Code analysis and refactoring tools
source: remote
execution: device # STDIO process runs on the agent's computer
display: name
sentry:
description: Error tracking
source: remote
# execution defaults to sandbox - runs in the platform
display: nameWhen to Use
Use execution: device when the MCP server needs access to the agent's local environment - for example, tools that read from the local filesystem, interact with running processes, or need CLIs installed on the device.
Rules
executionis only meaningful forsource: remoteMCPs that use STDIO transport. HTTP-transport remote MCPs always connect from the platform regardless of theexecutionsetting.executionis invalid onsource: deviceandsource: consumerMCPs - they already run outside the platform. Using it produces a validation error.- The
connectionfield (eagerorlazy) is respected for device-executed MCPs the same way as sandbox-executed MCPs.
Device MCP Servers
Device MCP servers (source: device) run on the consumer's machine. The consumer provides the MCP tools via the @octavus/computer package (or any ToolProvider implementation) through the server-sdk.
When an agent has device MCP servers:
- The consumer creates a
Computerwith matching namespaces @octavus/computerdiscovers tools from each MCP server- Tool schemas are sent to the platform via the server-sdk
- Tool calls flow back to the consumer for execution
See @octavus/computer for the full integration guide.
Namespace Matching
The mcpServers keys in the protocol must match the keys in the consumer's Computer configuration:
# protocol.yaml
mcpServers:
browser: # ← must match
source: device
filesystem: # ← must match
source: deviceconst computer = new Computer({
mcpServers: {
browser: Computer.stdio('chrome-devtools-mcp', ['--browser-url=...']),
filesystem: Computer.stdio('@modelcontextprotocol/server-filesystem', [dir]),
},
});If the consumer provides a namespace not declared in the protocol, the platform rejects it.
Consumer MCP Servers
Consumer MCP servers (source: consumer) are defined inline in your server-sdk process. Tool schemas and handlers live in your code; the platform learns the namespace from the protocol and routes tool calls to your process via the same dynamicToolSchemas channel that device MCPs use.
mcpServers:
github:
description: Repository management - issues, pull requests, code
source: consumer
display: name
agent:
mcpServers:
- githubThe protocol declaration is intentionally minimal - the SDK supplies tool names and JSON schemas at runtime, so adding or evolving tools doesn't require a protocol change.
Use consumer MCPs when:
- The integration's credentials should never reach the platform (OAuth tokens, customer API keys).
- You want to group an integration's tools (
github__list-prs,github__get-issue) without enumerating each one in YAML. - You want type-safe handler arguments via Zod schemas.
See createInlineMcpServer in the server-sdk reference for the full implementation guide.
Namespace Matching
The protocol namespace must match the namespace passed to createInlineMcpServer():
# protocol.yaml
mcpServers:
github: # ← must match
source: consumerconst github = createInlineMcpServer('github', {
/* tools... */
});
session = client.agentSessions.attach(sessionId, {
mcpServers: [github],
});If the SDK provides a namespace not declared in the protocol, those tools are filtered out at the runtime boundary and the LLM never sees them.
Thread-Level Scoping
Threads can scope which MCP servers are available, the same way they scope tools:
handlers:
user-message:
Start research:
block: start-thread
thread: research
mcpServers: [figma, browser]
tools: [set-chat-title]
system: research-promptThis thread can use Figma and browser tools, but not sentry or filesystem - even if those are available on the main agent.
On-Demand MCP Servers
By default, an agent can only call MCP tools whose namespace is listed in mcpServers. With onDemandMcpServers, a scope can opt into every connected MCP of a given source at runtime, without enumerating each one in the protocol.
Remote MCPs are connected at the project level from the Octavus dashboard. Normally, each connected MCP that the agent should be able to use has to be declared in the protocol - connecting a new MCP means editing the protocol and redeploying. onDemandMcpServers removes that round-trip: once a source is opted in, any MCP connected to the project under that source becomes available to the agent immediately.
Currently supported for source: remote.
Protocol-level declaration
Add an onDemandMcpServers: section alongside mcpServers:, keyed by source. Each entry configures how the matched MCPs appear in tool lists:
mcpServers:
figma:
description: Figma design tool integration
source: remote
display: description
onDemandMcpServers:
remote:
description: Additional connected integrations
display: name
execution: device # on-demand MCPs run on the agent's computer
contextRetention:
toolResults: { retainLast: 5 }On-demand MCP definitions also support the execution field. When set, all MCPs matched by that on-demand source inherit the execution mode.
Scope-level opt-in
The agent and individual start-thread blocks each choose whether to pick up on-demand MCPs, by listing the sources they want:
agent:
mcpServers: [figma]
onDemandMcpServers: [remote]
handlers:
user-message:
focused:
block: start-thread
mcpServers: [figma]
# no onDemandMcpServers - this thread does NOT see on-demand MCPs
broad:
block: start-thread
mcpServers: [figma]
onDemandMcpServers: [remote]Rules
- A scope's tool list includes every connected MCP of any referenced source, whether or not any protocol declares that slug.
- Undeclared namespaces inherit
description,display, andcontextRetentionfrom the per-source entry inonDemandMcpServers. - Scopes decide independently - threads do not inherit
onDemandMcpServersfrom their parent, the same rule asmcpServers:. - Tool namespaces are always the connector's slug (for example
notion__search,linear__create_issue). Source keys are never namespaces.
Workers opt into on-demand MCPs the same way: through start-thread blocks inside steps. A worker without a start-thread that lists a source won't see on-demand MCPs of that source.
Workers
Workers can declare and use MCP servers using the same mcpServers: syntax. Workers resolve their own MCP connections independently - they don't inherit from a parent interactive agent.
# Worker protocol
mcpServers:
sentry:
description: Error tracking and debugging
source: remote
display: name
browser:
description: Chrome DevTools browser automation
source: device
display: name
steps:
Start research:
block: start-thread
thread: research
model: anthropic/claude-sonnet-4-5
system: system
mcpServers: [sentry, browser]
maxSteps: 10Since workers don't have a global agent: section, MCP servers are scoped per-thread via start-thread - the same way tools and skills work in workers. Remote MCP connections are project-scoped, so workers in the same project share the same OAuth connections.
See Workers for the full worker protocol reference.
Full Example
mcpServers:
figma:
description: Figma design tool integration
source: remote
connection: eager
display: description
sentry:
description: Error tracking and debugging
source: remote
display: name
browser:
description: Chrome DevTools browser automation
source: device
display: name
filesystem:
description: Filesystem access for reading and writing files
source: device
display: hidden
shell:
description: Shell command execution
source: device
display: name
tools:
set-chat-title:
description: Set the title of the current chat.
parameters:
title: { type: string, description: The title to set }
agent:
model: anthropic/claude-opus-4-6
system: system
mcpServers: [figma, sentry, browser, filesystem, shell]
tools: [set-chat-title]
thinking: medium
maxSteps: 300
agentic: true
triggers:
user-message:
input:
USER_MESSAGE: { type: string }
handlers:
user-message:
Add message:
block: add-message
role: user
prompt: user-message
input: [USER_MESSAGE]
display: hidden
Respond:
block: next-messageCloud-Only Agent
Agents that only use remote MCP servers don't need @octavus/computer:
mcpServers:
figma:
description: Figma design tool integration
source: remote
connection: eager # Need design tools from message 1
display: description
sentry:
description: Error tracking and debugging
source: remote
# Lazy (default) - agent activates when debugging is needed
display: name
tools:
submit-code:
description: Submit code to the user.
parameters:
code: { type: string }
agent:
model: anthropic/claude-sonnet-4-5
system: system
mcpServers: [figma, sentry]
tools: [submit-code]
agentic: true