MCP Server
Manage your Runbear agents from Claude Code, Claude Desktop, Cursor, and other MCP clients, with a reference for every tool, error, and limit.
On this page
The Runbear MCP server is a hosted Model Context Protocol endpoint that lets an AI client — Claude Code, Claude Desktop, Cursor, and other MCP-compatible tools — read and manage the agents in your Runbear organization. Instead of clicking through the dashboard, you can describe what you want in natural language ("update the Support agent's instructions", "schedule the Standup agent for 9am") and your client makes the change through the MCP server.
This is the opposite direction from Custom MCP: there, Runbear is the client that connects out to your tools. Here, Runbear is the server that your AI client connects into to manage your agents.
What you can do#
From any connected MCP client you can:
- Manage agents — list agents, read their full configuration, create agents, and update an agent's name, model, and instructions.
- Edit instructions and contexts — add, update, or remove the named context blocks that make up an agent's behavior.
- Connect apps and tools — search the Runbear app catalog (Notion, Slack, Stripe, Linear, and more), attach integrations to an agent, and authorize them.
- Set up triggers and schedules — create app-event and HTTP webhook triggers or recurring and one-time scheduled jobs, and run scheduled jobs on demand.
- Deploy to Slack — install an agent into a Slack workspace, join channels, and go live.
- Inspect runs — pull recent execution traces to debug behavior and improve your agents.
- Ship files to a Claude Agent SDK agent — upload a project or a large workspace, as the Agent Skills do.
Connect#
The server URL is:
https://api.runbear.io/mcpWhen you add the server, your client opens a Runbear sign-in window so you can authorize access (see Authentication). After you approve, the client stores the token and you can start issuing commands.
Claude Code#
claude mcp add --transport http runbear https://api.runbear.io/mcpRun any Runbear command afterward and Claude Code will prompt you to sign in the first time.
Claude Desktop / claude.ai#
Open Settings → Connectors → Add custom connector, paste https://api.runbear.io/mcp, click Connect, and complete the Runbear sign-in.
Cursor, VS Code, Windsurf, Zed, and other clients#
Clients with native remote-MCP support can add the URL directly. For clients that connect through mcp-remote, use:
{
"mcpServers": {
"runbear": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://api.runbear.io/mcp"]
}
}
}Transport#
The server speaks the MCP Streamable HTTP transport: POST, GET, and DELETE on https://api.runbear.io/mcp. It is stateless, so it keeps no session between requests, and it does not offer the older HTTP+SSE transport. A client that supports only that older transport can connect through mcp-remote, as shown above.
Requests from a web page on another origin are refused with 403 and {"error": "invalid_origin"}. Desktop and command-line clients send no browser origin and are unaffected.
Authentication and permissions#
The Runbear MCP server is protected by OAuth 2.0. Authorization is handled by Runbear's identity provider, which your MCP client discovers automatically — you never paste an API key or token by hand. The server publishes its OAuth protected-resource metadata at https://api.runbear.io/.well-known/oauth-protected-resource/mcp, and every 401 points to it in the resource_metadata parameter of its WWW-Authenticate header.
Every connection is:
- Tied to your user account — the server acts as you, with your permissions.
- Scoped to your organization — you can only see and change agents in the organization you signed in to.
Removing the server from your client, or signing out there, deletes the client's copy of the token. It doesn't revoke the token on Runbear's side.
Access is governed by least-privilege scopes:
| Scope | Grants |
|---|---|
read:agents | Read agents, contexts, attached tools, and triggers; list Slack workspaces, channels, and users; get Slack install links; search the integration catalog; look up trigger types, trigger components, and connected app accounts |
write:agents | Create and update agents, contexts, integrations, and triggers; upload projects and workspace files, and check workspace upload status |
deploy:agents | Deploy agents to Slack (deploy_to_slack) and join channels (join_slack_channels) only |
read:traces | View execution traces (also requires an Admin or Owner role) |
Scopes are checked per tool: a call without the scope it needs returns a tool error rather than failing the connection.
Connection errors#
These are HTTP responses to the request itself, before any tool runs:
| Status | Body error | When |
|---|---|---|
401 | (none) | The request has no bearer token. The WWW-Authenticate header carries no error either, so your client starts the sign-in flow |
401 | invalid_token | The token is expired or invalid, or your account belongs to several organizations and none is set as the default (see above). Until a pending fix ships, error_description is the same generic text in both cases |
403 | insufficient_scope | You signed in, but your account isn't a member of any Runbear organization |
403 | invalid_origin | A browser page on another origin sent the request |
Available tools#
A client you connect yourself gets 39 tools, grouped below by what they manage. Most agent-scoped tools take an agentId; use list_agents to find it. Each tool needs the scope in its row.
Agents#
| Tool | Scope | What it does |
|---|---|---|
list_agents | read:agents | List the agents in your organization, newest first, with createdByMe so you can tell whose agents they are. Filter by name with query; page with limit (1-100, default 20) and cursor |
get_agent | read:agents | Read an agent's full configuration: name, description, model, system instruction, team, contexts, and whether it's a personal agent |
create_agent | write:agents | Create an agent from a name, system instruction, optional team label, and optional contexts. type selects the runtime: mastra (Classic, the default here) or claude-agent-sdk. The dashboard defaults to Claude Agent SDK instead. The server picks the model, so a model passed on create is ignored; change it afterwards with update_agent. Returns the new agent's id and its dashboard url |
update_agent | write:agents | Change an agent's name, description, model, max tokens, system instruction, or team. Only the fields you pass change |
get_personal_agent | read:agents | Read your own personal agent (the one behind the Inbox Agent), or null if you don't have one |
Instructions and contexts#
| Tool | Scope | What it does |
|---|---|---|
list_contexts | read:agents | List the named context blocks attached to an agent |
create_context | write:agents | Add a named context block, and return its dashboard url |
update_context | write:agents | Rewrite a context block by id |
delete_context | write:agents | Remove a context block. The agent stops using it from its next message |
Apps and integrations#
| Tool | Scope | What it does |
|---|---|---|
search_integration_catalog | read:agents | Search the Runbear integration catalog (Notion, Slack, Stripe, Linear, and more). Returns each match's key, name, description, authType, and categories; up to 30 results by default |
add_integration | write:agents | Register a catalog integration on an agent by its key. credentialScope is per_user (the default: each person who talks to the agent connects their own account) or shared (one connection for everyone); personal agents always use shared. excludedTools hides individual tools from the agent. Registering never authorizes: the result says whether authorizationRequired is still true |
list_integrations | read:agents | List the integrations registered on an agent. Being listed doesn't mean an integration is usable; check with get_integration_authorization |
authorize_integration | write:agents | Start or retry authorization for a registered integration. See Authorizing an integration for the statuses it returns |
get_integration_authorization | read:agents | Check whether you can use an integration now: authorized, authorization_required, approval_pending, or unknown. It never issues a URL |
remove_integration | write:agents | Remove an integration from an agent and delete the secrets Runbear stored for it. It doesn't revoke access at the provider; do that in the provider's own settings if you need to |
Triggers and schedules#
| Tool | Scope | What it does |
|---|---|---|
list_triggers | read:agents | List an agent's event triggers (kind: "external") and scheduled jobs (kind: "scheduled") |
get_trigger | read:agents | Read one trigger or scheduled job in full. Until a pending fix ships, the result doesn't include an HTTP webhook trigger's URL; copy it from the trigger's page in the dashboard |
list_supported_trigger_types | read:agents | Browse what you can create: app-event and HTTP webhook components (narrow with query, such as github) plus the two scheduled-job types, periodic and once |
describe_pipedream_trigger_component | read:agents | Get the settings a trigger component needs. Call it repeatedly, passing back dynamicPropsId and the values chosen so far, until no required setting is left |
generate_pipedream_connect_token | read:agents | Get a link you open in a browser to connect an app account for a trigger. Pass the app's appSlug. The link expires after about 4 hours |
find_pipedream_account_id | read:agents | Look up an app account you already connected for triggers, so you can reuse it instead of connecting again. Returns null when there is none |
create_external_trigger | write:agents | Create an event trigger: an app event, or an HTTP webhook that fires when a request arrives at its URL. Schedule components (keys starting with schedule-) are refused; use create_scheduled_job instead. Accepts a triggerPrompt and a notificationConfig (Slack, Microsoft Teams, or email destinations). Until a pending fix ships, the result doesn't include an HTTP webhook trigger's URL; copy it from the trigger's page in the dashboard |
create_scheduled_job | write:agents | Create a recurring (periodic, cron) or one-time (once) scheduled job. Give it exactly one destination: Slack (slackAppInstallationId plus target), Microsoft Teams (teamsTarget), or none (notify: false) |
update_trigger | write:agents | Change a trigger or scheduled job. On an event trigger: triggerPrompt, filterPrompt, configuredProps, status (ACTIVE or INACTIVE), and notificationConfig. On a scheduled job: name, prompt, config, and its Slack or Teams destination |
delete_trigger | write:agents | Permanently delete a trigger or scheduled job |
run_trigger_now | write:agents | Run a scheduled job immediately, optionally with a one-off prompt. App-event and HTTP webhook triggers can't be run on demand; they fire only when a real event arrives |
Slack#
| Tool | Scope | What it does |
|---|---|---|
list_slack_installations | read:agents | List the Slack workspaces connected to your organization, and whether each uses the shared Runbear app or a custom Slack app |
get_slack_install_link | read:agents | Get a one-click install link for the shared Runbear Slack app, and a link to the agent's Slack page in the dashboard for a custom app |
deploy_to_slack | deploy:agents | Connect an agent to your workspace through the shared Runbear app, or return an install link if the app isn't installed yet. mode: "custom" returns a dashboard link instead, where you finish setting up a custom Slack app; pass botName (English letters, numbers, spaces, apostrophes, periods, and hyphens, at most 35 characters) to pre-fill it. Refuses personal agents |
join_slack_channels | deploy:agents | Add a workspace's bot to up to 50 channels. Only public channels can be joined this way; for a private channel, type /invite @your-bot in Slack. Returns a result per channel |
list_slack_channels | read:agents | List channels in a workspace, with whether the bot is a member. Page with limit (1-200, default 100) and cursor |
list_slack_users | read:agents | List users in a workspace, to find a user id for a direct-message destination |
Traces#
| Tool | Scope | What it does |
|---|---|---|
list_recent_agent_traces | read:traces | List an agent's recent runs with their input, output, latency, and reactions. limit is 1-20 (default 10) and lookbackDays is 1-7 (default 7) |
get_agent_trace | read:traces | Read one run in detail, including its steps and tool calls |
Both trace tools also require the Admin or Owner role and read access to the agent. They read an agent that uses HIPAA data handling from its separate protected tracing path.
Claude Agent SDK agents#
These tools work only on Claude Agent SDK agents; on any other agent they return {"status": "blocked", "reasons": ["agent_must_be_claude_agent_sdk"]}. They take the agent's id or its dashboard URL, and you need permission to edit the agent. Agent Skills is the ready-made way to use them.
| Tool | Scope | What it does |
|---|---|---|
create_project_upload | write:agents | Step 1 of a project deploy: get an upload URL for a project zip (at most 50 MiB), valid for 6 days. PUT the zip to it with Content-Type: application/zip |
finalize_project_upload | write:agents | Step 2: queue the uploaded zip to be validated and installed in the agent's workspace. The response only confirms the deploy was queued; there is no status tool for project deploys |
create_workspace_upload | write:agents | Get one resumable upload URL per compressed archive shard, for a workspace too large for a project deploy |
finalize_workspace_upload | write:agents | Queue the uploaded shards to be verified and extracted into the agent's workspace |
get_workspace_upload_status | write:agents | Check a workspace upload. When it reports completed, the files are in the workspace and load on the agent's next run |
Authorizing an integration#
Registering an integration and authorizing it are separate steps. The usual flow is search_integration_catalog → add_integration → authorize_integration → get_integration_authorization. An integration can't be used while add_integration or get_integration_authorization says authorization is still required.
authorize_integration returns one of these statuses:
| Status | Meaning |
|---|---|
auth_url | Open the returned authUrl in a browser and approve access. Then call get_integration_authorization to confirm |
authorized | Nothing to do; the integration is ready |
approval_pending | The integration is waiting for an admin's approval (see Tool approvals) |
authorization_unavailable | There is no browser sign-in to start from here: the integration uses a static key or no authentication, or each user connects their own account from the agent's chat. message says what to do instead |
authorization_started | Only in a session bound to one agent. The agent delivers the sign-in step to the user itself, so there is no URL |
requires_web_setup | Only in a session bound to one agent, for a Custom MCP server. Open the returned settingsUrl and authorize it in the dashboard |
integration_not_found | The id isn't an integration on this agent. Call list_integrations |
Never paste an API key, bearer token, or MCP server URL into the chat to set up an integration. When an app needs a secret, or you want to connect your own MCP server, set it up in the dashboard at https://app.runbear.io/agents/<agentId>/integrations, where credentials are stored in the vault and masked.
Setting up triggers#
App-event triggers#
An app-event trigger is created in five steps:
list_supported_trigger_typeswith aquerysuch asgmail, to find the component key.describe_pipedream_trigger_componentwith that key. Repeat it, passing back the previousdynamicPropsIdand the values chosen so far, until the component has no required setting left.find_pipedream_account_idfor the app. If it returnsnull, callgenerate_pipedream_connect_token, open the link, connect the account, and look it up again.create_external_triggerwith the component key, its settings, the connected account, and optionally atriggerPromptandnotificationConfig.get_triggerto read the trigger back and confirm how it's configured.
If the trigger's prompt uses another app (for example "file a Linear ticket"), register and authorize that app on the agent first, as described in Authorizing an integration.
HTTP webhook triggers use the same flow with the HTTP / Webhook component. Until a pending fix ships, neither create_external_trigger nor get_trigger returns the public URL to send requests to: open the trigger's page in the dashboard and copy its Webhook URL. Anyone who sends a request to that URL runs the agent, so treat it as a secret. See Triggers for what the agent receives.
Rules#
- Schedules. A
periodicjob takes a 5-field cron expression and an IANAtimezonesuch asAmerica/Los_Angeles, and shouldn't run more often than once an hour. Aoncejob takesexecuteAt, a Unix time in milliseconds, which should be in the future. Until a pending fix ships, the MCP server doesn't enforce either rule: a more frequent cron is accepted, and a pastexecuteAtruns the job immediately. - Delays. To make an event trigger wait before running, start its
triggerPromptwith@delay(10m)or@delay(2h): minutes or hours, at most 24 hours. The agent never sees the directive. Delays apply to event triggers only. - Where the output goes. An event trigger delivers each run's result to the destinations in its
notificationConfig: Slack (a DM or a channel), Microsoft Teams (a chat or a channel), or email, plus failed runs whennotifyOnErrorsistrue. A scheduled job has exactly one destination: a Slack DM or channel (slackAppInstallationIdplustarget), or a Microsoft Teams chat or channel (teamsTarget, which posts a new message rather than a threaded reply). The two can't be combined.notifydefaults totrue; withnotify: falseand no destination, which is required when you give neither, the job runs silently: its tool calls still happen, but the reply isn't posted anywhere. - Limits. An organization can have up to 50 event triggers by default, and triggered runs share a daily budget. See Triggers → Limits.
- Run now.
run_trigger_nowworks on scheduled jobs. On event triggers it works only for legacy schedule-based triggers, which can no longer be created. - Scheduling from chat.
create_scheduled_jobis refused when an admin has turned off Scheduling from chat under Settings → Agents. It is on by default. Until a pending fix ships, the refusal message still names the setting's old label, "Allow bots to create scheduled triggers". - Filters.
filterPromptonupdate_triggersets the plain-language condition that decides which events run the agent. It is in limited availability; see Triggers → Filtering events.
Prompts#
The server offers one MCP prompt, setup_runbear_trigger. It takes a request argument that describes the workflow in plain language ("when a Zoom meeting ends, summarize it to #team-notes") and walks your client through authorizing every app the workflow needs, discovering the right trigger component, creating the trigger, and reading it back.
The server exposes no MCP resources.
Built-in tools on an agent#
Every new agent created in the dashboard or with create_agent gets Runbear's own MCP server attached as one of its tools, bound to that agent. Through it the agent can edit its own instructions, contexts, integrations, and triggers, and read its own traces — for example, when a user asks it in Slack to "also check Linear from now on". On Claude Agent SDK agents these tools appear to the model as mcp__runbear__<tool>, which is the name hooks match on.
A session bound to one agent differs from a client you connect yourself:
- Every tool acts on that agent only, and none takes an
agentId. list_agents,create_agent,get_personal_agent, and the Slack tools aren't available, so the user has to supply Slack ids for a destination.- The Claude Agent SDK tools are available only when the agent is itself a Claude Agent SDK agent.
- A trigger or context that belongs to another agent is refused with
host_agent_ownership_required.
Admins turn this off for new agents with Settings → Agents → Built-in tools. Existing agents keep what they have. Agents created with the REST API's POST /v1/agents don't get these tools.
Tool errors#
A tool that refuses a call returns a JSON body that says why, usually as an MCP tool result with isError: true, so your client can show the reason and carry on:
| Body | Meaning |
|---|---|
{"error": "insufficient_scope", "required": "...", "granted": [...]} | Your token lacks the scope the tool needs. Reconnect and grant it |
{"error": "forbidden", "reason": "admin_role_required"} | The trace tools need the Admin or Owner role |
{"error": "forbidden", "reason": "agent_read_permission_required"} | You don't have read access to the agent whose traces you asked for |
{"error": "forbidden", "reason": "hipaa_data_handling"} | The agent uses HIPAA data handling and Runbear's protected trace store is not enabled |
{"error": "forbidden", "reason": "host_agent_ownership_required"} | In a session bound to one agent, the trigger or context belongs to a different agent |
{"type": "error", "message": "..."} | A trigger or scheduled job couldn't be created or changed: the trigger limit was reached, the component is a schedule component or can't be deployed, the Slack or Teams destination is unreachable, or scheduling from chat is turned off. message explains it |
Some tools report a refusal as a normal result with a status instead:
deploy_to_slackandget_slack_install_linkreturnstatus: "unsupported_for_personal_agent"for a personal agent, which can't be deployed to Slack.- The Claude Agent SDK tools return
status: "blocked"withreasons, such asagent_must_be_claude_agent_sdkoragent_modify_permission_required.
Example prompts#
List my Runbear agents and show the model each one uses.
Update the Support agent's instructions to always greet the user by name.
Add a context block to the Sales agent describing our refund policy.
Search the app catalog for Linear and attach it to the Triage agent.
Schedule the Standup agent to run every weekday at 9am in #team-standup.
Deploy the Onboarding agent to our Slack workspace.
Show me the last 10 runs of the Billing agent and any errors.Security#
- The server acts as you. It uses your account's permissions, only within your organization. Removing the server from your client doesn't revoke its token on Runbear's side, so treat a machine with a connected client like any signed-in device.
- Writes are explicit. Your client asks before each change, and operations that deploy or modify agents require the corresponding scope.
- Never paste credentials into chat. When an integration needs a secret (API keys, bearer tokens, custom MCP headers), set it up in the Runbear dashboard at
https://app.runbear.io/agents/<agentId>/tools, where credentials are stored in the vault and masked. Conversation transcripts are retained by your client and LLM provider, so secrets pasted into chat would be exposed in scrollback and logs.
Limitations#
The MCP server covers the core agent-management workflow. These still need the dashboard:
- Knowledge-base sync (Notion, Confluence, Google Drive, SharePoint, websites).
- Advanced model settings such as temperature, reasoning effort, and response format. Over MCP you can set only the model and max tokens.
- Custom Slack app setup.
deploy_to_slackwithmode: "custom"hands off to a dashboard page. - Private Slack channels. The bot can join only public channels over MCP; invite it to private ones from Slack.
- Slack for personal agents. Personal agents can't be deployed to Slack.
- Trigger sources other than app events, HTTP webhooks, and scheduled jobs, such as inbox events.
We're closing these gaps — expect the tool set to grow.
Related#
- Custom MCP — connect your MCP servers and tools to an agent (Runbear as the client)
- Agent Skills — deploy a local Claude Code project to a Claude Agent SDK agent
- Triggers — how triggers and scheduled jobs behave
- Tool integrations API — attach tools to an agent over REST instead
- Getting started — create an agent and deploy it
- Model Context Protocol — the open standard behind MCP