You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

9.1 KiB

name description
educoder-skill 提供 Educoder 用户与课堂相关查询能力,当前支持用户基本信息、课堂列表、课堂作业列表、作业学生列表、课堂考试列表、考试学生列表查询。

MCP 服务地址

  • 线上地址:http://47.98.32.66:48000/mcp
  • 本地开发:http://localhost:8001/mcp

使用 streamable-http 模式连接,不使用 SSE。

接入方式

  • 客户端应使用 streamable-http MCP 客户端
  • 使用 OpenClaw 安装本 skill 时MCP 服务地址直接填写线上地址:http://47.98.32.66:48000/mcp
  • 不要使用 sse_client
  • 本地开发端口默认是 8001,线上端口使用 48000
  • MCP 路径默认是 /mcp

前置配置

接入 OpenClaw 时,多个会话使用同一个 Authorization token。调用端每次建立 MCP 连接时,都从环境变量 EDUCODER_AUTHORIZATION 读取 token并放到请求头里。

Authorization 配置

在运行 OpenClaw 或 MCP 客户端的进程环境中配置:

export EDUCODER_AUTHORIZATION="xxxxx"

MCP 客户端每次连接时应读取环境变量并注入:

headers = {
    "Authorization": os.getenv("EDUCODER_AUTHORIZATION", "").strip()
}

Authorization 的 header 值直接传 token 原文,不要拼接 Bearer 前缀。例如:

Authorization: xxxxx

不要传成:

Authorization: Bearer xxxxx

然后在创建 MCP 连接时透传:

async with streamable_http_client(self.server_url, headers=headers or None) as (read, write, _):
    yield read, write

Authorization 走 MCP 连接层请求头,不放在工具参数里。

多会话共享 Token

多个会话共用同一个 EDUCODER_AUTHORIZATION。不要让用户在每个会话里单独输入 token也不要把 token 放到工具参数里。

正确做法是:

  1. 在 OpenClaw 运行环境中配置 EDUCODER_AUTHORIZATION
  2. 每次创建 MCPClient 或建立 MCP 连接时,从 os.getenv("EDUCODER_AUTHORIZATION") 读取最新值
  3. 把读取到的 token 原文放进 MCP transport headers 的 Authorization,不要添加 Bearer 前缀
  4. 多个会话可以分别创建 MCPClient 实例,但认证 token 都来自同一个环境变量

401 Token 过期处理

如果调用 MCP 工具或后端接口时返回 401 Unauthorized,说明当前 EDUCODER_AUTHORIZATION 已过期或无效。

处理流程:

  1. 停止继续使用当前 token 重试
  2. 提示用户重新输入新的 Authorization
  3. 将用户输入的新 token 更新到环境变量 EDUCODER_AUTHORIZATION
  4. 重新创建 MCP 连接,并从环境变量读取最新 token
  5. 使用新 token 重新发起本次工具调用

示例提示:

当前 Educoder 授权已过期,请重新输入 Authorization token。

更新环境变量示例:

export EDUCODER_AUTHORIZATION="new-token"

更新 token 后必须重新建立 MCP 连接,不能复用已经携带旧 headers 的连接。

OpenClaw 接入建议

如果使用 OpenClaw推荐按下面的方式接入

  1. 安装 skill 时MCP 服务地址填写:http://47.98.32.66:48000/mcp
  2. 在 OpenClaw 运行环境中配置 EDUCODER_AUTHORIZATION
  3. 当前用户发起工具调用时,后端创建 MCPClient
  4. MCPClient 建连时从环境变量读取 EDUCODER_AUTHORIZATION
  5. MCPClient 把读取到的 token 原文放进 MCP headers不要添加 Bearer 前缀
  6. 如果调用返回 401 Unauthorized,提示用户重新输入 token更新 EDUCODER_AUTHORIZATION 后重新建连并重试

参考流程:

import os

tool_server_url = "http://47.98.32.66:48000/mcp"

client = MCPClient(
    server_url=tool_server_url,
)

tool_result = await client.call_tool(tool_name, tool_arguments)

MCPClient 示例:

class MCPClient:
    def __init__(self, server_url: str):
        self.server_url = server_url

    def _build_headers(self) -> dict[str, str]:
        headers = {}
        authorization = os.getenv("EDUCODER_AUTHORIZATION", "").strip()
        if authorization:
            headers["Authorization"] = authorization
        return headers

不推荐的做法:

  • 让用户在每个会话里重复输入 Authorization
  • Authorization 放到工具参数里
  • Authorization 自动拼接 Bearer 前缀
  • 在进程启动后只读取一次 token导致环境变量更新后无法生效

触发场景

意图 → 工具 速查表

用户意图 调用工具
查询当前用户基本信息 educoder_user_info
查询当前用户的课堂列表 educoder_user_course_list
查询某个课堂中的作业列表 educoder_course_homeworks
查询某次作业下的学生列表 educoder_homework_student_works
查询某个课堂中的考试列表 educoder_course_exercises
查询某场考试下的学生列表 educoder_exercise_users

不要触发的情况

  • 与课堂、作业、考试数据查询无关的问题
  • 需要新增、修改、删除数据的写操作
  • 纯闲聊场景

组合调用示例

用户说:“帮我查一下我有哪些课堂,再看看某个课堂里的作业和考试”

依次调用:

  1. educoder_user_info
  2. educoder_user_course_list
  3. educoder_course_homeworks
  4. educoder_course_exercises

用户说:“帮我看一下这次作业和这场考试的学生列表”

依次调用:

  1. educoder_homework_student_works
  2. educoder_exercise_users

工具详细说明

全局规则

  • 当前工具都是查询类工具,没有写操作
  • 调用时必须传入完整的结构化 JSON 参数对象
  • 参数名必须严格匹配工具定义
  • 当前查询逻辑还是占位实现,后续会接外部 HTTP 接口
  • course_idexercise_id 当前按字符串传入
  • 客户端每次连接 MCP 服务时,请从环境变量 EDUCODER_AUTHORIZATION 读取 token 原文,并在 transport headers 中传 Authorization,不要添加 Bearer 前缀

1. educoder_user_info

获取当前用户基本信息。

参数:

参数 必填 说明
school 可选的 school 查询参数

典型问法:

  • “查询当前用户信息”
  • “我是谁”
  • “获取我的基本资料”

2. educoder_user_course_list

获取当前用户课堂列表。

参数:

典型问法:

  • “查询我有哪些课堂”
  • “我的课堂列表”
  • “获取当前用户的课堂信息”

返回字段:

  • status
  • message
  • data
  • size

3. educoder_course_homeworks

获取课堂中的作业列表。

参数:

参数 必填 说明
course_id 课堂 ID

典型问法:

  • “查询课堂中的作业列表”
  • “这个课堂有哪些作业”
  • “帮我看一下课堂作业”

4. educoder_homework_student_works

获取某次作业下的学生列表。

参数:

参数 必填 说明
exercise_id 作业 ID

典型问法:

  • “查询某次作业下的学生列表”
  • “这次作业有哪些学生提交了”
  • “帮我看一下作业学生情况”

5. educoder_course_exercises

获取课堂中的考试列表。

参数:

参数 必填 说明
course_id 课堂 ID

典型问法:

  • “查询课堂中的考试列表”
  • “这个课堂有哪些考试”
  • “帮我看一下课堂考试”

6. educoder_exercise_users

获取某场考试下的学生列表。

参数:

参数 必填 说明
exercise_id 考试 ID

典型问法:

  • “查询某场考试下的学生列表”
  • “这场考试有哪些学生”
  • “帮我看一下考试参与学生”

客户端调用示例

import os

import httpx
from mcp import ClientSession
from mcp.client.streamable_http import streamable_http_client


async def main():
    headers = {
        "Authorization": os.getenv("EDUCODER_AUTHORIZATION", "").strip()
    }

    async with httpx.AsyncClient(headers=headers) as http_client:
        async with streamable_http_client("http://47.98.32.66:48000/mcp", http_client=http_client) as (read, write, _):
            async with ClientSession(read, write) as session:
                await session.initialize()

                tools = await session.list_tools()
                print([tool.name for tool in tools.tools])

                result = await session.call_tool("educoder_user_info", {})
                print(result)

注意事项

  • 当前服务使用 streamable-http,不是 SSE
  • 如果客户端使用了 sse_client,将无法正常调用当前服务
  • Authorization 应从环境变量 EDUCODER_AUTHORIZATION 读取 token 原文,通过 MCP 连接层 headers 传入,不放在工具参数里,也不要添加 Bearer 前缀
  • 调用接口返回 401 Unauthorized 时,视为 token 过期或无效,应要求用户重新输入 token并更新到环境变量 EDUCODER_AUTHORIZATION
  • 当前工具返回空 data 数组属于预期行为,因为外部接口尚未接入
  • 后续新增或调整工具时,需要同步更新本文件