CtrlK
BlogDocsLog inGet started
Tessl Logo
SkillPublic

langbot-mcp-ops

Operate a LangBot instance through its built-in MCP (Model Context Protocol) server. Use when an AI agent needs to manage LangBot — list/create/update/delete bots, agents, pipelines, models, knowledge bases, MCP servers, and skills — over MCP instead of raw HTTP. Covers the /mcp endpoint, API-key auth (web-UI lbk_ keys and the config.yaml global key), the tool surface, and client configuration. Triggers on "langbot mcp", "manage langbot via mcp", "langbot /mcp", "langbot mcp server".

Quality

87%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

SKILL.md
Quality
Evals
Security

LangBot MCP Operations

LangBot exposes an MCP server so AI agents can manage an instance programmatically. It mirrors a curated subset of the HTTP service API. Workspace capabilities are being unified under the Application API catalog (pkg/api/application/; see Unified API in the root AGENTS.md); MCP tool names are not necessarily the catalog operation IDs.

Endpoint

http://<langbot-host>:5300/mcp

Transport: streamable HTTP (stateless, JSON responses). Same host/port as the web UI and HTTP API.

Authentication

Reuses the same API keys as the HTTP API. Send either header:

X-API-Key: <api-key>
# or
Authorization: Bearer <api-key>

Two kinds of key are accepted:

  1. Web-UI key — created in the web UI (sidebar → API Keys), prefixed lbk_. The secret is shown once; only its SHA-256 hash is stored. Each key is bound to one Workspace and has explicit scopes, status, optional expiry, and last-used metadata. The key determines the Workspace; callers cannot switch it with X-Workspace-Id.
  2. Global API key — set in data/config.yaml under api.global_api_key. Requires no login session and no DB record; does not need the lbk_ prefix. It is accepted only by a community instance with exactly one local Workspace and is disabled for SaaS multi-Workspace operation. Leave empty to disable. See the langbot-deploy skill for config details.

Invalid, revoked, or expired keys get 401 Unauthorized. A valid key whose scopes do not authorize a tool gets 403 Forbidden.

To inspect key identity and permissions, call GET /api/v1/system/context with the API key.

Client configuration

{
  "mcpServers": {
    "langbot": {
      "url": "http://<langbot-host>:5300/mcp",
      "headers": { "X-API-Key": "<api-key>" }
    }
  }
}

Plugin permissions

Plugin authorization management uses get_plugin_permissions(author, plugin_name) and revoke_plugin_permissions(author, plugin_name, workspace_operations, capabilities). Revocation replaces grants with a subset; it requires resource.manage. API-key MCP clients cannot confirm/add grants. After installing or upgrading a plugin, direct a member to WebUI to review pending permissions. The marketplace HTTP install option auto_confirm_permissions is used by the setup wizard and remains member-only; setting it with an API key cannot grant permissions. Migration with plugin installation enabled uses the same checks. Pipeline extensions accept allowed_platform_tools as model preferences, not installation grants. See docs/en/plugin/dev/permissions.mdx for HTTP contracts.

Tool surface

create_bot requires bot_data.name and bot_data.adapter as non-empty strings, and bot_data.adapter_config as an object with the adapter's settings. For update_pipeline, fetch the current pipeline before editing: config preserves omitted top-level sections and replaces each supplied section in full, without deep merging. Supplied sections must be objects. The merged configuration is validated before persistence; secret placeholders retain existing values.

Slack quick setup: create a disabled slack-omni bot draft first, then use start_slack_setup with the user's App Configuration access/refresh tokens. Choose socket_mode=true with a browser-reachable OAuth redirect_url, or provide the public HTTPS webhook_url ending in /bots/<bot_uuid>. Poll get_slack_setup_status for the Slack installation authorization URL; the user must authorize installation. On success, apply the returned config using the normal bot update flow. Socket Mode also requires a separately generated app_token (xapp-, scope connections:write). Never log tokens. cancel_slack_setup removes the temporary session without deleting the Slack application. Sessions expire after 15 minutes and are bound to the initiating Workspace, principal, and placement generation. Restarting a failed setup can create another Slack application; inspect the returned app_id first.

The tools wrap the LangBot service layer. Current tools (v1):

create_pipeline and HTTP POST /api/v1/pipelines preserve a supplied config and extensions_preferences; omit config to use installed Runner defaults. Selecting ai.runner.id never grants extension access: an empty plugins list with enable_all_plugins=false still denies that plugin's Tool, EventListener and Command components, while allowing its selected Runner. Editing and copying a pipeline retain these independent settings.

ToolPurpose
get_system_infoVersion, edition, instance id
list_bots / get_bot / create_bot / update_bot / delete_botManage messaging-platform bots (secrets redacted on read)
list_bot_event_route_statusesInspect bot event-route runtime status
list_processors / get_processor / create_processor / update_processor / delete_processorManage the peer Agent, Pipeline and Event processor types
get_processor_metadataDiscover installed event-capable Runner components, schemas and supported event patterns.
list_processor_runs / get_processor_run_eventsRead one Agent or plugin processor run history and logs; paginate with before_id / after_sequence.
debug_agentExecute a synthetic Agent event (processor_uuid, payload); requires runtime.operate. Returns final text and up to 1000 execution events (thinking, text, tool arguments/results). Platform tools use Mock; other configured tools execute normally. Optional payload.mock: errors/results keyed by platform tool name, unsupported_apis lists unavailable platform APIs.
list_pipelines / get_pipeline / create_pipeline / update_pipeline / delete_pipelineManage pipelines
list_llm_models / get_llm_model / list_embedding_models / list_asr_models / list_tts_models / list_model_providersInspect models & providers
list_knowledge_bases / get_knowledge_base / retrieve_knowledge_baseRAG knowledge bases (incl. semantic search)
list_mcp_serversExternal MCP servers LangBot connects to (as a client)
list_skills / get_skillInstalled skills
list_knowledge_engines / get_knowledge_engine_schema / list_knowledge_parsersDiscover RAG configuration
get_pipeline_extensions / update_pipeline_extensionsRead or completely replace extension bindings; all lists and switches required
run_pipelineOne fresh-session turn; requires runtime.operate, executes configured models/tools, never auto-retry an unknown outcome
get_monitoring_records / get_monitoring_detailsBounded Workspace records and existing message/session details
get_sandbox_diagnosticsRead status (resource.view), sessions/errors (audit.view); managed sandbox admission still applies

Mutating tools (create_*, update_*) take a JSON object matching the same shape as the corresponding HTTP API request body. Discover resources with the list_* / get_* tools before mutating; identifiers are UUIDs. Reads require resource.view; mutations require resource.manage. All service calls inherit the immutable Workspace context authenticated at the MCP transport boundary. Pass is_default: true to create_pipeline only when the Workspace does not already have a default pipeline.

How to use

Pipeline plugin extension switches authorize only EventListener, Tool and Command components. Select the Runner independently in AI settings. An empty extension allowlist does not prevent saving, copying or running that Runner. Never enable all plugins or add its plugin to the allowlist as a Runner workaround: that also authorizes its other components. The Runner plugin must still be installed and enabled in the authenticated Workspace, with an available Plugin Runtime.

  1. Get an API key (web UI key, or set api.global_api_key in config.yaml).
  2. Point your MCP client at http://<host>:5300/mcp with the key header.
  3. Call get_system_info to confirm connectivity.
  4. Use list_* tools to discover, then get_* / create_* / update_* / delete_* as needed.

ChatGPT / Codex subscription providers

list_model_providers can return the openai-codex requester. Its OAuth credentials are server-only and are not provider API keys. Never ask a user to paste ChatGPT access tokens, refresh tokens, or a Codex auth cache into an MCP tool or model configuration.

A human connects or disconnects the subscription through Models → provider settings in the LangBot web UI. The provider-scoped /codex/* authentication routes deliberately require a browser-user session and are not exposed as MCP tools or authorized by a LangBot API key. Once connected, models are managed and selected through the normal provider/model workflow. A disconnected provider must be reauthorized; do not silently replace it with API-key billing.

See ChatGPT / Codex subscription for setup, usage limits, and the personal-account versus shared-service boundary.

Provider deletion

The curated MCP surface currently lists providers but has no provider-deletion tool. In the web UI, Edit Provider → Delete asks for confirmation before removing that provider and all its LLM, embedding, and rerank models. This is irreversible; never interpret a request to edit a provider as authorization to delete it.

The equivalent HTTP operation is DELETE /api/v1/provider/providers/{uuid}?cascade=true, requiring resource.manage in the authenticated Workspace. Omitting cascade preserves the existing refusal to delete providers that still have models. Cloud-managed providers remain protected. Cascade deletion removes stored Codex authorization state as well; it is not the same operation as disconnecting an account.

Implementation & maintenance (for LangBot developers)

  • Server: src/langbot/pkg/api/mcp/server.py (FastMCP). Tools call the service layer directly, so the MCP surface stays aligned with the API.
  • Mount: src/langbot/pkg/api/mcp/mount.py — an ASGI dispatcher fronting Quart, authenticating /mcp requests, running the streamable-HTTP session manager.
  • Smoke test: tests/manual/mcp_smoke.py.

When you add, remove, or change an HTTP API endpoint that should be agent-accessible, update the corresponding MCP tool and this skill. The MCP tool surface and the API must stay aligned (see AGENTS.md).

Pitfalls

  • /mcp is the server LangBot exposes. The /api/v1/mcp routes are the client side (managing external MCP servers LangBot connects to). Don't confuse them.
  • A 401 means the key is wrong, missing, revoked, expired, or (for the global key) api.global_api_key is empty or the instance is not an OSS singleton.
  • A 403 means the key is valid but lacks the permission required by the tool.
  • The global key is plaintext in config.yaml — only enable it on trusted/internal deployments and serve over HTTPS.

Default message routes

create_bot without non-empty event_bindings adds two explicit message routes: private chat (chat_type eq person) and group chat (chat_type eq group plus is_at_bot eq true). Both use the Workspace's default Pipeline, or the first available Pipeline. If none exists, first-bot setup creates one with the full default config. Creating a Pipeline via create_agent(kind="pipeline") also uses that full default config. Configure an authorized model before testing replies.

Explicit routes on create are preserved; update_bot never automatically replaces manual routes, including an intentionally empty list. The WebUI message template uses the same private/group conditions and preserves existing routes when applied repeatedly. Unmentioned group messages do not enter the Pipeline. An existing broad route can still match first; inspect route order and diagnostics before changing a member's configuration.

Event processors

Create a processor with kind: "event_processor" and basic information. Without a component it supports no events. Discover installed components with get_processor_metadata, then use update_processor with component_ref and optional parameters. API callers may also supply these when creating an instance. Bind an instance by updating the bot's plugin_processors array with {"processor_uuid": "<instance UUID>", "enabled": true}. This replaces the full subscription list; preserve bindings you want to keep. Do not add plugin processors to event_bindings, which remains exclusive Agent/Pipeline routing. Each enabled subscription independently receives the installed Runner's declared events. Slow or failed subscribers do not prevent other subscribers or the primary route from executing. Installation alone never activates a handler. Reusing an instance shares its configuration and runtime state. Use a separate instance for independent settings. Optional plugin behavior belongs in the Runner config schema. debug_agent accepts the complete typed event in payload.data for this kind. Legacy EventListener plugins remain in the Pipeline lifecycle.

list_processor_runs includes created_at_ms, started_at_ms, and finished_at_ms: Host lifecycle times in epoch milliseconds. Use the start and finish times for elapsed processing time; select a run and call get_processor_run_events for its logs and action results. These times are not internal plugin profiling data.

Unified execution monitoring

Message record reads can renew temporary OneBot image URLs through the connected bot without downloading images. Persisted payloads reference a shared URL catalog; renewal overwrites its current URL so existing references read the new address. Explicitly identified NapCat connections reuse rkeys until their returned TTL expires (appid 1406 uses type 10; appid 1407 uses type 20). Other OneBot implementations use standard get_msg at most once per URL per 30 minutes when original message and image identities are available. Disconnected peers, missing origins, or unsupported APIs leave the stored URL unchanged; returned URLs are not permanent archival links.

Use get_inflight_executions for a bounded current-workspace snapshot of active and recently started executions, including progress_event. Progress is a reported stage, not an estimated completion percentage. The UI uses the shared GET /api/v1/monitoring/in-flight/stream SSE feed instead of polling per viewer.

Use get_monitoring_executions for the execution list and its legacy pipeline_ids parameter to filter any processor kind (Agent, Pipeline or event processor); the summary uses the same processor scope. Use get_monitoring_execution_detail with source=auto to resolve a run, message or event identifier outside the current list page. The detail exposes inputs, outputs (generated content), deliveries (recorded platform sends), events, llm_calls, tool_calls, errors, related, and conversation in pages. Follow each section's has_more and next_offset independently. Start with section=overview to load only inputs, outputs, deliveries and errors. Request conversation, related, calls and events separately when needed; omitting section retains the complete trace response for existing consumers. Conversation history supplies context; historical messages without explicit links must not be asserted to belong to the selected execution. Events without a processor run use source=event. All lookups remain Workspace-scoped.

Monitoring record filters, except for kind="sessions", accept mode (all, real, debug) and execution_statuses (normalized execution statuses). These select the owning execution, not the individual model/tool call outcome. Calls without a recorded execution link are excluded when an execution filter is active.

Session lists support bot_ids, pipeline_ids, start_time, end_time, user_query, is_active, and pagination. For execution status or real/debug filters, use get_monitoring_executions; HTTP /monitoring/sessions rejects them. In HTTP /monitoring/data, sessions and totalCount.sessions use only bot/pipeline/time filters; execution filters apply to the other records.

Workspace message language

get_workspace_message_language reads the current Workspace's backend language (workspace.view). set_workspace_message_language(language) requires workspace.update; supported values are en_US, zh_Hans, zh_Hant, ja_JP, es_ES, ru_RU, th_TH, vi_VN. HTTP equivalents are GET/PUT /api/v1/workspaces/current/language (PUT body: {"language":"ja_JP"}). The API key's Workspace remains authoritative. The setting controls new backend messages and default bot notices, independently of personal UI language. Pipeline output.misc hint fields override defaults; empty values inherit this setting. Existing custom text and historical logs are not rewritten.

Workspace default LLM model

get_starred_model reads the Workspace-wide favorite. set_starred_model requires provider_secret.manage and replaces the single starred model; pass null to clear it. The model must belong to the current Workspace. get_default_model resolves the favorite first, then the Space wizard chat recommendation only when LangBot Models is enabled and the Workspace owner is bound to a LangBot Account. It returns a nullable uuid. New processor LLM selector defaults use this preference; existing configurations are not rewritten. Embedding and rerank models are not eligible.

Reset a bot session context

Use reset_session_context(bot_id, session_id) only when a user asks to start a session afresh. It requires resource.manage, preserves monitoring records, and refuses sessions with active tasks. It clears conversation runner state and excludes earlier transcript entries from subsequent model context. Files and long-term memory are not removed.

Cloud plan platform restrictions

Bot creation and enabling use the same Workspace entitlement policy as HTTP. A disabled platform is rejected even through MCP or plugin calls; do not retry using an Omni or legacy alias to bypass the restriction. The Workspace-scoped HTTP adapter catalog omits disabled platforms.

LLM request diagnostics

get_monitoring_records(kind="llm_calls") includes nullable details on each call. Read details.timing, details.usage, and details.error to distinguish provider latency, retry waits, cached/reasoning tokens, and failures. Timing values are milliseconds since invocation start; first_event_ms includes reasoning/control frames, while first_content_ms measures the first upstream content delta. first_visible_chunk_ms may contain displayed reasoning, not just answer text. Old records have no details. Do not equate total duration with provider TTFT. See dev-docs/LLM_REQUEST_POLICY.md for policy precedence and gateway header behavior.

get_llm_model also exposes optional reasoning_capabilities.budget_tokens min/max bounds. Numeric thinking budgets use reasoning_config.budget_tokens with level enabled; do not combine budgets with effort levels or native thinking arguments. Existing Runner reasoning overrides take precedence. Prompt caching is opt-in through model/call extra_args.prompt_caching; use provider-specific modes documented in dev-docs/LLM_REQUEST_POLICY.md. Cache keys are routing hints, not evidence of hits; read the actual usage counters. preparation_ms measures request construction and preparation_cache_hits counts retry preparation reuse. transport_setup_ms measures managed pool acquisition, including first-use TLS initialization; it is not network TTFT. See dev-docs/LLM_LATENCY_BENCHMARK.md for controlled request-layer measurements and their scope.

Repository

langbot-app/LangBot

Path

skills/skills/langbot-mcp-ops/SKILL.md

Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.