feat(wecom): 企微 API 插件增加 MCP Streamable HTTP 端点

与 REST/OpenAPI 并存,按实例权限自动 tools/list,免手填工具。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-08 16:57:42 +08:00
parent cae426fbc2
commit 976bde37cc
23 changed files with 1212 additions and 63 deletions
@@ -19,8 +19,10 @@ import {
import type { ColumnsType } from 'antd/es/table';
import {
WECOM_PLUGIN_API_KEY_HEADER,
WECOM_PLUGIN_MCP_TRANSPORT,
WECOM_PLUGIN_PERMISSION_GROUPS,
WECOM_PLUGIN_PERMISSION_LABELS,
resolveWecomPluginMcpUrl,
resolveWecomPluginPublicUrl,
type WecomApiPluginDto,
type WecomApiPluginSecretDto,
@@ -53,6 +55,7 @@ export default function WecomApiPluginsPage() {
const [revealed, setRevealed] = useState<WecomApiPluginSecretDto | null>(null);
const pluginUrl = resolveWecomPluginPublicUrl(window.location.hostname);
const mcpUrl = resolveWecomPluginMcpUrl(window.location.hostname);
const permissionsWatch = Form.useWatch('permissions', form) as WecomPluginPermission[] | undefined;
const { data, loading, page, pageSize, setPage, setPageSize, reload } =
@@ -224,7 +227,7 @@ export default function WecomApiPluginsPage() {
{settingsModal}
<AdminListHeader
settings={settingsButton}
description="每个实例对应企微里一只 API 插件:共用 Base URL,用不同 X-Api-Key 区分,并按勾选权限放行工具。"
description="每个实例对应企微里一只插件:共用 URL,用不同 X-Api-Key 区分,并按勾选权限放行工具。优先配 MCP 插件;API 插件(OpenAPI)仍可用。"
actions={
<Button type="primary" onClick={openCreate}>
@@ -236,20 +239,24 @@ export default function WecomApiPluginsPage() {
type="info"
showIcon
style={{ marginBottom: 16 }}
message="填企微「添加 API 插件」第 1 步"
message="填企微「添加插件」"
description={
<div>
<div>
URL
MCP URL{WECOM_PLUGIN_MCP_TRANSPORT}
<Typography.Text copyable>{mcpUrl}</Typography.Text>
</div>
<div>
API URL OpenAPI
<Typography.Text copyable>{pluginUrl}</Typography.Text>
</div>
<div>
OpenAPI Key
OpenAPIAPI 2 Key
<Typography.Text copyable>{`${pluginUrl}/openapi.json`}</Typography.Text>
</div>
<Typography.Text type="secondary">
Service token / API keyHeader {WECOM_PLUGIN_API_KEY_HEADER}
2 GET + Query
MCP API 2 GET
</Typography.Text>
</div>
}