feat(mcp): simplify external MCP server config to local/remote modes

Replace the three-way transport choice (stdio / sse / httpstream) for
connecting LangBot to external MCP servers with two modes: local (stdio)
and remote. Remote servers only require a URL; the runtime auto-detects
the transport (tries Streamable HTTP, falls back to SSE).

- provider/tools/loaders/mcp.py: add _init_remote_server() with
  Streamable-HTTP-then-SSE probing; dispatch 'remote' lifecycle, keep
  legacy sse/http branches for back-compat
- plugin/connector.py: normalize legacy http/sse marketplace modes to
  'remote' on Space install, preserving connection params
- entity/persistence/mcp.py: document mode as stdio, remote (legacy: sse, http)
- alembic 0006: idempotent data migration mapping existing sse/http rows
  to remote (downgrade maps back to http)
- api/http/service/mcp.py: stash runtime_info (status + tool list) into
  test task metadata before tearing down the temp session
- web: collapse mode dropdown to local/remote, remote renders URL+timeout
  only, edit auto-maps legacy sse/http to remote; show tools after test in
  create mode from task metadata; remove dead plugins/mcp-server/ tree
- i18n: local/remote labels + mode/url hints across 8 locales
This commit is contained in:
RockChinQ
2026-06-21 11:20:32 -04:00
parent 2ff854f79a
commit 64ed6d994b
21 changed files with 268 additions and 1389 deletions
@@ -0,0 +1,51 @@
"""normalize mcp_servers transport mode to local/remote
The MCP transport selection for servers LangBot connects to was simplified
from three persisted modes (``stdio`` / ``sse`` / ``http``) down to two:
``stdio`` (local, Box-sandboxed) and ``remote`` (the runtime auto-detects
Streamable HTTP vs. legacy SSE from the URL). This migration rewrites any
existing ``sse`` / ``http`` rows to ``remote`` so the stored value matches the
new two-option UI. The connection args (url / headers / timeout /
ssereadtimeout) live in ``extra_args`` and are left untouched — the
auto-detecting remote transport consumes them regardless.
Revision ID: 0006_normalize_mcp_remote_mode
Revises: 0005_add_llm_context_length
Create Date: 2026-06-21
"""
import sqlalchemy as sa
from alembic import op
revision = '0006_normalize_mcp_remote_mode'
down_revision = '0005_add_llm_context_length'
branch_labels = None
depends_on = None
def upgrade() -> None:
# Idempotent data migration: collapse legacy remote transports into the
# unified ``remote`` mode. Guard against the table being absent (truly empty
# DB migrated before create_all()).
conn = op.get_bind()
inspector = sa.inspect(conn)
if 'mcp_servers' not in inspector.get_table_names():
return
conn.execute(
sa.text("UPDATE mcp_servers SET mode = 'remote' WHERE mode IN ('sse', 'http')")
)
def downgrade() -> None:
# The legacy distinction between ``sse`` and ``http`` cannot be recovered
# from ``remote`` alone (the transport is auto-detected at runtime, not
# stored). Map everything that is not ``stdio`` back to ``http`` as a
# best-effort reversal — both legacy modes still route correctly in the
# backend lifecycle dispatch.
conn = op.get_bind()
inspector = sa.inspect(conn)
if 'mcp_servers' not in inspector.get_table_names():
return
conn.execute(
sa.text("UPDATE mcp_servers SET mode = 'http' WHERE mode = 'remote'")
)