BBS交互终端

基于FastMCP的Telnet客户端,具备自动学习功能,使AI代理能够通过模型上下文协议(MCP)与传统的基于Telnet的BBS系统进行交互。

  • by livingstaccato
  • Python
  • 本地部署
  • 3 星标
  • 更新于
在 GitHub 查看 livingstaccato/mcp-bbs

使用说明

bbsbot

基于FastMCP的telnet客户端,用于BBS(公告板系统)交互,具有自动学习功能。使AI代理能够通过模型上下文协议(MCP)与基于传统telnet的系统进行交互。

⚠️ AI生成代码免责声明

该项目是在人工智能的帮助下生成的。虽然功能正常,但它可能包含错误、安全漏洞或意外行为。使用风险自负。对于因使用本软件而导致的任何问题、损害或损失,作者不承担任何责任。在任何生产环境中使用之前,请彻底检查代码。

概述

bbsbot通过提供:

  • 支持ANSI/CP437的全终端仿真
  • 基于模式的屏幕阅读和导航
  • 自动发现和记录菜单和提示
  • 会话日志记录,用于分析和回放
  • MCP工具曝光,实现无缝AI集成

建筑

bbsbot使用一个干净的分层架构,并适当分离关注点:

graph TB
    subgraph "AI Agent"
        LLM[Claude/LLM]
        MCP[MCP Client]
    end

    subgraph "bbsbot Server"
        App[FastMCP App]
        SM[SessionManager]

        subgraph "Core Layer"
            Session[Session]
        end

        subgraph "Transport Layer"
            Transport[TelnetTransport]
        end

        subgraph "Terminal Layer"
            Emulator[TerminalEmulator<br/>pyte]
        end

        subgraph "Learning Layer"
            Engine[LearningEngine]
            Discovery[Menu Discovery]
        end

        subgraph "Logging Layer"
            Logger[SessionLogger]
        end
    end

    subgraph "BBS System"
        Telnet[Telnet Server :23]
        BBS[BBS Software]
    end

    subgraph "Knowledge Base"
        Prompts[prompt-catalog.md]
        Menus[menu-map.md]
        Flows[navigation-flows.md]
    end

    LLM --> MCP
    MCP -->|MCP Tools| App
    App --> SM
    SM --> Session
    Session --> Transport
    Session --> Emulator
    Session --> Engine
    Session --> Logger
    Transport -->|RFC 854 + IAC Escaping| Telnet
    Telnet --> BBS
    BBS -->|ANSI/CP437| Telnet
    Telnet -->|Raw Bytes| Transport
    Transport --> Emulator
    Engine --> Discovery
    Engine --> Prompts
    Engine --> Menus
    Engine --> Flows

架构层

  • 传输层 (transport/):协议抽象(符合RFC 854的telnet,IAC字节转义)
  • 端子层 (terminal/):使用pyte进行ANSI/CP437终端仿真
  • 核心层 (core/):具有资源限制和状态隔离的会话管理
  • 学习层 (learning/):自动发现菜单/提示,知识库管理
  • 测井层 (logging/):使用原始字节的结构化JSONL会话日志记录

特性

  • 远程登录客户端:具有选项协商的完整RFC 854 telnet协议(BINARY、SGA、NAWS、TTYPE)
  • 终端仿真:配备80x25(可配置)屏幕缓冲区的完整ANSI/CP437终端
  • 屏幕阅读:提取文本、匹配模式、等待具有超时控制的提示
  • 自动学习:发现菜单 [A] Option,提示 Enter name:,以及文档导航流
  • 会话日志记录:JSONL格式,带有时间戳、上下文和原始字节,用于回放/分析
  • MCP集成:25多种用于连接、导航、学习和会话管理的工具
  • 保持连接:可配置间隔以防止空闲断开连接

安装

先决条件

安装 紫外线 (推荐的软件包安装程序):

curl -LsSf https://astral.sh/uv/install.sh | sh

或者看看 紫外线安装文档 对于其他方法。

安装bbsbot

bbsbot是必须在MCP客户端(Claude Desktop、Cline等)中配置的MCP服务器。

选项1:作为工具安装(推荐)

uv tool install bbsbot

然后添加到MCP客户端配置中:

{
  "mcpServers": {
    "bbsbot_local_tw2002": {
      "command": "bbsbot"
    }
  }
}

本地TW2002 MCP与外部MCP连接器

bbsbot 在本地提供TW2002工具,但这些工具仅存在于MCP中 您从这个存储库/环境启动的服务器进程。在多连接器中 客户端,您也可能安装了无关的MCP连接器;那些不会 暴露 tw2002_* 工具。

有关群集运行时/ROI诊断和防崩溃控制参考,请参阅:

对TW2002操作使用显式的本地别名和工具筛选器:

{
  "mcpServers": {
    "bbsbot_local_tw2002": {
      "command": "bbsbot",
      "args": ["serve", "--tools", "tw2002"]
    }
  }
}

如果 tw2002_* 缺少工具,首先验证配置的命令是否包括 serve --tools tw2002.

选项2:使用pip安装

pip install bbsbot

然后配置MCP客户端以运行 bbsbot 作为服务器。

开发安装

git clone https://github.com/livingstaccato/bbsbot.git
cd bbsbot
uv pip install -e ".[dev]"

快速入门示例

以下是一个完整的AI代理连接到BBS、导航菜单和阅读消息的示例:

from fastmcp import Client
from fastmcp.mcp_config import StdioMCPServer

# Start bbsbot server
server = StdioMCPServer(command="bbsbot", args=[])

async with Client(server.to_transport()) as client:
    # Connect to BBS
    await client.call_tool("bbs_connect", {
        "host": "bbs.example.com",
        "port": 23,
        "cols": 80,
        "rows": 25,
        "term": "ANSI",
        "send_newline": True
    })

    # Wait for main menu
    screen = await client.call_tool("bbs_read_until_pattern", {
        "pattern": r"\[M\] Main Menu",
        "timeout_ms": 5000
    })

    # Navigate to messages
    await client.call_tool("bbs_send", {"keys": "M\r"})

    # Read until message list appears
    screen = await client.call_tool("bbs_read_until_pattern", {
        "pattern": r"Message #\d+",
        "timeout_ms": 3000
    })

    print(screen["screen"])  # Display the screen

    # Disconnect
    await client.call_tool("bbs_disconnect", {})

用法

作为MCP服务器

作为MCP服务器运行以公开BBS工具:

# Start the server (stdio transport)
bbsbot

# Or specify config
bbsbot --host localhost --port 2002

程序化使用

在没有MCP的情况下直接使用Python API:

from bbsbot.core.session_manager import SessionManager

manager = SessionManager(max_sessions=10)

# Connect and create session
session_id = await manager.create_session(
    host="bbs.example.com",
    port=23,
    cols=80,
    rows=25,
    term="ANSI",
    send_newline=True,
    reuse=False
)

# Get session
session = await manager.get_session(session_id)

# Read screen with timeout
snapshot = await session.read(timeout_ms=250, max_bytes=8192)

# Snapshot contains:
# - screen: formatted text (80x25)
# - screen_hash: SHA256 of screen text
# - cursor: {x, y} position
# - cols, rows, term

print(snapshot["screen"])
print(f"Cursor at: {snapshot['cursor']}")

# Send keys
await session.send("A\r\n")

# Wait for specific pattern (manual implementation)
import re
import asyncio

pattern = re.compile(r"Enter your name:")
timeout = 5.0
interval = 0.1
start_time = asyncio.get_event_loop().time()

matched = False
while asyncio.get_event_loop().time() - start_time < timeout:
    snapshot = await session.read(timeout_ms=int(interval * 1000), max_bytes=8192)
    if pattern.search(snapshot["screen"]):
        matched = True
        break
    await asyncio.sleep(interval)

if matched:
    print("Found prompt!")
    await session.send("Alice\r")

# Disconnect
await manager.close_session(session_id)

注: 为了方便起见,使用MCP工具,它提供更高级的操作,如 bbs_read_until_pattern.直接API是较低级别的,并且需要手动模式匹配循环。

MCP工具参考

当作为MCP服务器运行时,会公开以下工具:

注: 在v0.2.0中,我们删除了重复项 *_screen 变体和实用程序包装器,以简化API。使用 bbs_read()["screen"] 提取屏幕文本并组合操作,而不是使用方便的包装器,如 bbs_expect 或 bbs_play_step.

连接管理

bbs_connect

通过telnet连接到BBS。

{
  "host": "bbs.example.com",
  "port": 23,
  "cols": 80,
  "rows": 25,
  "term": "ANSI",
  "send_newline": true,
  "reuse": false
}

bbs_disconnect

断开与BBS的连接。退出前一定要打电话。

{}

bbs_status

获取连接状态、会话ID、最后RX/TX时间戳、保活信息。

{}

屏幕交互

bbs_read

主要的读取方法。 从telnet流中读取并返回包含屏幕文本、原始输出、光标位置和哈希的完整快照。 始终将原始字节记录到JSONL 因此,如果LLM对屏幕内容不确定,可以参考。

使用 timeout_ms=0 无需等待新数据即可获取当前屏幕状态。

{
  "timeout_ms": 250,
  "max_bytes": 8192
}

退货:

{
  "screen": "formatted 80x25 text...",
  "raw": "raw terminal output",
  "raw_bytes_b64": "base64 encoded raw bytes",
  "screen_hash": "sha256 of screen text",
  "cursor": {"x": 0, "y": 0},
  "cols": 80,
  "rows": 25,
  "term": "ANSI"
}

重要提示: 每个 bbs_read 调用日志记录完整快照,包括 raw_bytes_b64 转到session.json(如果启用了日志记录)。如果LLM误解了屏幕内容,它可以查阅日志文件以获取收到的确切原始字节数。

bbs_read_until_nonblank

继续阅读,直到屏幕上有非空白内容或超时。

{
  "timeout_ms": 5000,
  "interval_ms": 100,
  "max_bytes": 8192
}

bbs_read_until_pattern

读取,直到屏幕匹配正则表达式模式。

{
  "pattern": "Enter your name:",
  "timeout_ms": 5000,
  "interval_ms": 100,
  "max_bytes": 8192
}

返回:带有附加值的快照 "matched": true/false

bbs_send

向BBS发送按键(CP437编码)。

{
  "keys": "A\r\n"
}

使用 \r 对于Enter, \n 对于线路馈电, \x1b 逃跑。

bbs_wake

尝试多个按键序列,直到屏幕发生变化(对空闲超时有用)。

{
  "timeout_ms": 5000,
  "interval_ms": 250,
  "max_bytes": 8192,
  "keys_sequence": ["\r", " ", "\r\n"]
}

自动学习

bbs_auto_learn_enable

启用/禁用提示和菜单的自动学习。

{
  "enabled": true
}

bbs_auto_learn_prompts

配置规则以自动检测提示。

{
  "rules": [
    {
      "prompt_id": "username",
      "regex": "Enter your name:",
      "input_type": "text",
      "example_input": "Alice"
    }
  ]
}

bbs_auto_learn_menus

配置规则以自动检测菜单选项。

{
  "rules": [
    {
      "menu_id": "main",
      "regex": "\\[M\\] Main Menu"
    }
  ]
}

bbs_auto_learn_discover

启用自动发现 [X] 样式菜单选项。

{
  "enabled": true
}

bbs_learn_menu

手动记录菜单。

{
  "menu_id": "main",
  "title": "Main Menu",
  "options": [
    {"key": "M", "label": "Read Messages"},
    {"key": "P", "label": "Post Message"},
    {"key": "Q", "label": "Quit"}
  ],
  "prompt": "Your choice:"
}

bbs_learn_prompt

手动记录提示。

{
  "prompt_id": "username",
  "pattern": "Enter your name:",
  "input_type": "text",
  "example_input": "Alice",
  "notes": "Username for login"
}

bbs_learn_flow

屏幕之间的文档导航。

{
  "from_screen": "main_menu",
  "action": "M",
  "to_screen": "message_list",
  "notes": "Press M to read messages"
}

会话管理

bbs_log_start

启动JSONL会话日志记录。 强烈推荐 -如果LLM误读了屏幕,则允许LLM返回原始会话数据。

{
  "path": "session.jsonl"
}

bbs_log_stop

停止会话日志记录。

{}

bbs_log_note

在日志中添加结构化注释以进行调试。

{
  "note": "Starting message read loop",
  "context": "messages"
}

bbs_set_context

设置附加到所有后续日志条目的元数据。

{
  "context": {
    "menu": "main",
    "action": "reading_messages"
  }
}

保持连接

bbs_keepalive

配置自动保活以防止空闲超时。

{
  "interval_s": 30.0,
  "keys": "\r"
}

集 interval_s 到 0 或 null 禁用。

典型工作流程

sequenceDiagram
    participant LLM as AI Agent (LLM)
    participant MCP as bbsbot
    participant BBS as BBS System
    participant Log as session.jsonl
    participant KB as Knowledge Base

    LLM->>MCP: bbs_log_start("session.jsonl")
    MCP->>Log: Create log file

    LLM->>MCP: bbs_connect(host, port, ...)
    MCP->>BBS: Telnet connection
    BBS-->>MCP: Welcome screen (ANSI)
    MCP->>Log: Log connection + raw bytes

    LLM->>MCP: bbs_auto_learn_enable(true)
    LLM->>MCP: bbs_auto_learn_discover(true)

    LLM->>MCP: bbs_read_until_pattern("Main Menu")
    MCP->>BBS: Read telnet stream
    BBS-->>MCP: Raw bytes + ANSI codes
    MCP->>MCP: Parse terminal, extract text
    MCP->>Log: Log screen + raw bytes
    MCP->>KB: Discover menu options [A], [B]
    MCP-->>LLM: screen + cursor + hash

    Note over LLM: LLM analyzes screen,<br/>decides to press 'M'

    LLM->>MCP: bbs_send("M\r")
    MCP->>BBS: Send 'M' + Enter
    MCP->>Log: Log keystroke

    LLM->>MCP: bbs_read(250, 8192)
    BBS-->>MCP: Message list screen
    MCP->>Log: Log screen + raw bytes
    MCP-->>LLM: Full snapshot

    Note over LLM: If LLM is uncertain about<br/>screen content, it can<br/>refer to session.jsonl<br/>for raw bytes

    LLM->>MCP: bbs_disconnect()
    MCP->>BBS: Close connection
    MCP->>Log: Log disconnect
    LLM->>MCP: bbs_log_stop()

要点

  1. 始终启动会话日志记录 (bbs_log_start)-使用原始字节创建完整记录
  2. 使用 bbs_read 对于一切 -始终以JSONL格式记录原始数据的单一方法
  3. 启用自动学习 早期-为未来的会议建立知识库
  4. 如果不确定,LLM可以参考日志 -每一个 bbs_read 包括 raw_bytes_b64 会话日志
  5. 没有单独的“获取屏幕”方法 -使用 bbs_read(timeout_ms=0) 获取当前状态
  6. 知识库积累 -菜单、提示、流程记录在 .bbs-knowledge/

为什么是单读法?

以前,读取新数据和获取当前屏幕有不同的方法。这令人困惑且容易出错。现在:

  • 单一真相来源: bbs_read 始终读取,始终记录原始字节
  • LLM安全: 如果不确定屏幕内容,LLM可以检查 raw_bytes_b64 来自session.jsonl
  • 一致的日志记录: 每次屏幕观察都会完整记录
  • 更简单的API: 不混淆使用哪种方法

配置

知识库

默认情况下,学习到的知识按照XDG基本目录规范存储在特定于平台的用户数据目录中:

  • Linux/BSD: ~/.local/share/bbsbot (或 $XDG_DATA_HOME/bbsbot)
  • macOS: ~/Library/Application Support/bbsbot
  • 视窗: %LOCALAPPDATA%\bbsbot

用以下内容覆盖默认位置:

export BBSBOT_KNOWLEDGE_ROOT=/path/to/knowledge

保持每个项目的知识库(而不是整个用户):

export BBSBOT_KNOWLEDGE_ROOT=$(pwd)/.bbs-knowledge

终端设置

通过MCP工具配置终端大小和保活:

# Using MCP client
await client.call_tool("bbs_set_size", {"cols": 80, "rows": 25})
await client.call_tool("bbs_keepalive", {"interval_s": 30.0, "keys": "\r"})

或者以编程方式:

# Using SessionManager
session = await manager.get_session(session_id)
await session.set_size(cols=80, rows=25)
# Keepalive is configured per-session through the session manager

发展

设置

uv pip install -e ".[dev]"

代码质量

该项目使用现代Python 3.11+功能和严格的质量工具:

  • 类型检查: mypy src/bbsbot
  • 掉毛: ruff check src/bbsbot
  • 格式化: ruff format src/bbsbot
  • 测试: pytest
  • 类型验证: ty src/bbsbot

运行所有检查

ruff check src/bbsbot
ruff format --check src/bbsbot
mypy src/bbsbot
pytest

重新生成图表

架构和工作流程图是使用Mermaid文件生成的 mermaid-py.

使用make生成SVG图:

make diagrams

可用目标:

  • make diagrams 或 make diagrams-svg -生成SVG图(默认)
  • make diagrams-png -生成PNG图表
  • make clean -删除所有生成的图表文件
  • make help -显示所有可用目标

或者,直接运行脚本:

python3 docs/generate_diagrams.py --format svg

源文件:

  • docs/diagrams/architecture.mmd → architecture.svg
  • docs/diagrams/workflow.mmd → workflow.svg
  • docs/diagrams/session-flow.mmd → session-flow.svg

智能机器人与模式测试

bbsbot包括一个智能机器人系统,该系统使用提示检测来自主导航BBS游戏并测试提示模式。

TW2002交易机器人

运行TW2002交易机器人:

bbsbot tw2002 bot -c tw2002_bot_config.yaml

目标可视化(人工智能策略)

当 trading.strategy: ai_strategy 处于活动状态,显示目标进度:

  • 紧凑的状态线 trading.ai_strategy.visualization_interval 回合
  • 目标发生变化时的完整时间表
  • 会议结束时的总结报告

要禁用所有目标可视化输出,请执行以下操作:

trading:
  ai_strategy:
    show_goal_visualization: false

间谍/监视插座

您可以通过TCP广播实时终端流,并从另一个终端连接到它:

# Start bot with watch socket enabled (raw ANSI stream)
bbsbot tw2002 bot -c tw2002_bot_config.yaml --watch-socket

# Attach viewer
bbsbot spy

如果你想要结构化的JSON事件(包括目标可视化事件),请使用JSON协议:

# Start bot with JSON watch protocol
bbsbot tw2002 bot -c tw2002_bot_config.yaml --watch-socket --watch-socket-protocol json

# Attach and view JSON lines (the "viz" events include compact/timeline/summary text)
bbsbot spy --encoding utf-8

目标可视化观察事件如下:

{"event":"viz","data":{"kind":"compact|timeline|summary","text":"...","turn":123,"character_name":"..."}}

MCP“间谍”工具(进行中)

如果你在MCP服务器进程中运行机器人,你可以按需查询目标进度:

  • tw2002_get_goal_visualization (呈现压缩/时间线/摘要)
  • tw2002_get_goal_phases (原始相位数据)
  • tw2002_capabilities (返回分组工具图+快速入口点)
  • tw2002_list_sessions / tw2002_set_active_session (确定性会话定位)
  • tw2002_bootstrap (一次通话连接+登录)

快速开始

# Run intelligent bot with pattern testing
bbsbot script play_tw2002_intelligent

# Run systematic pattern validation
bbsbot script test_all_patterns

特性

  • 反应性检测:Bot等待提示,检测它们,并做出适当的响应
  • 自动分页:自动处理“更多”提示和分页
  • 模式验证:测试所有13个定义的提示模式
  • 流量跟踪:记录操作→提示序列
  • 综合报告:生成JSON和Markdown结果

建筑

智能机器人使用 混合反应方法:

  1. 第一阶段:纯反应式-检测出现的提示
  2. 第2阶段:跟踪提示序列和流程
  3. 第三期:添加常见模式的预测(未来)

看 docs/guides/INTELLIGENT_BOT.md 以获取完整的文档。

机器人使用示例

from bbsbot.commands.scripts.play_tw2002_intelligent import IntelligentTW2002Bot

bot = IntelligentTW2002Bot()
await bot.connect()

# Navigate to game
await bot.navigate_twgs_to_game()
await bot.enter_game_as_player("BotName")

# Test commands with automatic prompt detection
await bot.test_command("D\r", "Display computer")
await bot.test_command("I\r", "Show inventory")

# Auto-handles pagination
snapshot = await bot.send_and_wait("L\r", "Long range scan")
snapshot = await bot.handle_pagination(snapshot)

# Generate results
await bot.generate_report()

模式测试

测试了13种模式:

  • login_username, login_password
  • twgs_main_menu, twgs_select_game
  • main_menu, command_prompt_generic
  • sector_command, planet_command
  • press_any_key, more_prompt
  • yes_no_prompt, quit_confirm
  • enter_number

结果保存到 logs/reports/intelligent-bot-{timestamp}.json

已知警告

  • 你可以看到 UserWarning: Field name "validate" ... shadows an attribute 从Pydantic开始 bbsbot。这目前是无害的,不会影响运行时行为。

许可证

GNU Affero通用公共许可证v3或更高版本-版权所有(c)2025-2026 provide.io llc

看 许可证 了解详情。