1. 为什么 .NET 工作流引擎需要 MCP Server如果你手上有一套跑了几年的 Slickflow 工作流引擎流程定义、审批节点、待办已办都在 PostgreSQL 里稳稳当当现在想让 AI 编排平台Dify、Coze、n8n、Claude 这类直接调用它最直接的做法是把流程 API 一个个包成 Function Calling。我试过这条路问题很快就暴露出来Dify 一套适配、Coze 一套适配、n8n 再来一套每换一个平台就要重写一遍参数映射和鉴权逻辑维护成本随平台数量线性上涨。MCPModel Context Protocol解决的正是这个重复适配问题。它的思路是你只需要实现一次 MCP Server把工作流能力暴露成标准工具所有支持 MCP 的 AI 客户端都能自动发现并调用。对 Slickflow 这种已经有完整服务层IWorkflowService的引擎来说MCP Server 本质上就是一层薄薄的协议适配——把 C# 方法用 Attribute 标注一下框架自动生成 inputSchema大模型据此生成正确的参数调用。这篇文章面向的是已经有一套 Slickflow 实例、希望让 AI 工具调用工作流能力的 .NET 开发者。我会给出可复制的 MCP Server 配置片段、TaoToken 统一 Key/API 通道的接入方式以及从工具注册到工作流触发的逐步验证动作。核心检索词就三个Slickflow、MCP Server、工作流引擎接入 AI 编排平台。读完你应该能自己跑通一条「AI Agent 发起流程 → 推进审批 → 查询状态」的完整链路。先说清楚 MCP Server 在这里扮演什么角色。它不是替代 Slickflow 引擎也不是替代 AI 编排平台而是夹在中间的一层协议网关对下调用 IWorkflowService 和 KbDocumentService对上用 JSON-RPC 2.0 响应 MCP 客户端的工具发现与调用请求。运行在 .NET 8 之上基于 ModelContextProtocol.AspNetCore v0.3.0-preview.2默认监听 5100 端口。整个 Server 暴露 14 个工具其中 12 个是工作流操作2 个是知识库语义搜索。适合谁跟做有 .NET 8 开发环境、能访问 Slickflow 数据库、手头有 Dify 或 n8n 任意一个可测试的 AI 编排平台。如果你只是想先验证协议通不通用内置的 MCP Client 也能跑不依赖外部平台。2. TaoToken 前置统一 Key 与 API 通道准备在写 MCP Server 之前先把模型侧的通道准备好。Slickflow MCP Server 本身不直接调用大模型但你的 AI 编排平台Dify/Coze/n8n以及 Slickflow.AI 内置的 ReAct Agent 都需要一个稳定的模型入口。这里用 TaoToken 做统一通道好处是 Key 和 Base URL 一套配置多个平台复用不用每个平台单独申请。TaoToken 是什么一个统一的模型 API 通道提供兼容 OpenAI 风格的接口你拿到一个 Key 就能在 Dify、n8n、Claude Code、Cline 等工具里调用模型。适合谁需要把模型调用集中管理、又不想在每个平台重复配置的开发者。第一步打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册账号。注册流程很常规邮箱验证后进控制台。第二步进控制台创建 API Key。地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 在 API Keys 页面点新建复制出来的 Key 形如sk-xxxxxxxx。这个 Key 后面要填到两个地方AI 编排平台的模型配置里以及 Slickflow.AI 的 Agent 节点配置里。第三步确认 Base URL。API 端点是 https://taotoken.net/api 注意这个地址不带任何查询参数。在 Dify 里配置模型时Base URL 填https://taotoken.net/api模型名按你实际要用的填比如gpt-4o、claude-3-5-sonnet这类以控制台模型列表为准。这里有个容易踩的坑Base URL 末尾不要多加/v1。TaoToken 的兼容层已经处理了路径你填https://taotoken.net/api即可多写一层会导致 404。我实测下来Dify 的 OpenAI 兼容 Provider 直接填这个地址就能通。如果你用的是 Claude Code 或 Cline 这类编码工具配置方式略有不同需要设置环境变量或 settings 文件。Claude Code 的接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有完整的 Base URL Key Model ID 三件套写法。Cline 的 MCP 配置同理后面第五节会给出具体片段。Key 准备好后先别急着写 Server用模型对话页面验证一下 Key 是否可用https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。发一句「你好」能正常返回就说明通道没问题。这一步花两分钟能省掉后面排查 401 的时间。需要提醒的是TaoToken 只是模型通道它不参与 Slickflow 工作流的执行。工作流的启动、推进、查询全部走你自己的 MCP Server模型只负责决定「调用哪个工具、传什么参数」。两者职责分离排查问题时也好定位。3. 可复制配置MCP Server 注册与工具声明这一节是全文技术核心给出可以直接抄的配置片段。先看 Server 注册三行代码搞定builder.Services.AddMcpServer() .WithHttpTransport(options options.EnableLegacySse true) .WithToolsWorkflowTools() .WithToolsKnowledgeBaseTools(); // ... 中间是其他中间件注册 app.MapMcp(/mcp);EnableLegacySse true这行很关键。它让 Server 同时暴露GET /mcp/sse和POST /mcp/message两个端点兼容 n8n 这类尚未实现 Streamable HTTP 的客户端。如果你只用 Dify 或 Coze可以关掉但建议留着多一个兼容通道不亏。工具声明用 Attribute 驱动每个工具就是一个普通 C# 方法[McpServerToolType] public class WorkflowTools(IWorkflowService wfService) { [McpServerTool, Description(启动一个流程实例。返回流程实例ID(ProcessInstanceIdStarted)。)] public string start_process( [Description(流程代码从 list_processes 获取)] string processCode, [Description(发起人用户ID)] string userId, [Description(业务单据ID)] string appInstanceId) { var process wfService.GetProcessByCode(processCode, version); var runner new WfAppRunner { ProcessId process.ProcessId, Version process.Version, UserId userId, AppInstanceId appInstanceId }; var result wfService.StartProcess(runner); return JsonSerializer.Serialize(new { result.Status, result.ProcessInstanceIdStarted }); } }注意start_process里的一个细节引擎需要ProcessId Version不能只传ProcessCode。所以工具层先调GetProcessByCode查出实体再填入WfAppRunner。这是踩过的坑直接传 Code 会报参数缺失。鉴权通过中间件实现支持两种 Header 格式// X-Api-Key: your-key // 或 // Authorization: Bearer your-key/health端点跳过鉴权供 Docker/K8s 健康探针使用。空 Key 时自动进入开发模式免鉴权方便本地调试但生产环境务必配上强 Key。速率限制用固定窗口限流器每 IP 每分钟最多 100 次RateLimitPartition.GetFixedWindowLimiter( ctx.Connection.RemoteIpAddress?.ToString(), _ new FixedWindowRateLimiterOptions { PermitLimit 100, Window TimeSpan.FromMinutes(1) });超限返回 HTTP 429响应头带Retry-After。生产部署用 docker-compose核心片段如下services: sfmcp: build: . ports: - 5100:5100 environment: - ConnectionStrings__WfDBConnectionString${DB_CONNECTION} - McpAuth__ApiKey${MCP_API_KEY} - RateLimit__PermitLimit100 healthcheck: test: [CMD, curl, -f, http://localhost:5100/health] interval: 30s timeout: 5s retries: 3对应的.env.exampleDB_CONNECTIONHostxxx;Databasewfdb;Usernamexxx;Passwordxxx MCP_API_KEYyour-strong-api-key-here RATELIMIT_PERMITLIMIT100 RATELIMIT_WINDOWMINUTES1敏感配置通过.env注入不进镜像。这套配置我在测试环境跑过PostgreSQL 里 42 个已发布流程、402 条知识库文档14 个工具全部验证通过。如果你要把这个 MCP Server 接到 Cline 或 Claude Code 里做本地调试配置片段长这样以 Cline 的 MCP 配置为例{ mcpServers: { slickflow: { url: http://your-host:5100/mcp, headers: { X-Api-Key: your-api-key } } } }三件套齐全Base URL 是http://your-host:5100/mcpKey 是X-Api-Key的值Model ID 在 Cline 的模型设置里单独配走 TaoToken 的话填https://taotoken.net/api加你的模型名。Codex 的auth.json写法类似把 Base URL 和 Key 填进对应字段即可。4. 验证请求从工具发现到工作流触发配置写完怎么确认真的通了分四步验证每步都有明确的成功标志。第一步健康检查。启动 Server 后执行curl -f http://localhost:5100/health返回 200 即服务活着。这一步不涉及鉴权用来排除端口占用、容器没起来这类基础问题。第二步工具发现。用 MCP 协议发一个tools/list请求curl -X POST http://localhost:5100/mcp \ -H Content-Type: application/json \ -H X-Api-Key: your-api-key \ -d { jsonrpc: 2.0, id: 1, method: tools/list, params: {} }成功的话返回一个 JSONresult.tools数组里应该有 14 个工具包括list_processes、start_process、run_process、get_running_tasks、search_knowledge_base等。如果只返回部分工具检查WithToolsT()有没有漏注册。第三步只读工具验证。先调list_processes确认能读到流程定义curl -X POST http://localhost:5100/mcp \ -H Content-Type: application/json \ -H X-Api-Key: your-api-key \ -d { jsonrpc: 2.0, id: 2, method: tools/call, params: { name: list_processes, arguments: {} } }返回里应该有你数据库里已发布的流程列表。这一步验证了数据库连接和IWorkflowService注入都正常。第四步写入工具验证。调start_process发起一个真实流程实例curl -X POST http://localhost:5100/mcp \ -H Content-Type: application/json \ -H X-Api-Key: your-api-key \ -d { jsonrpc: 2.0, id: 3, method: tools/call, params: { name: start_process, arguments: { processCode: leave_approval, userId: user_001, appInstanceId: BIZ_20250101_001 } } }成功返回里会有ProcessInstanceIdStarted拿这个 ID 再调get_process_instance能查到状态调get_running_tasks能看到待办任务。到这里从工具注册到工作流触发的完整链路就验证完了。在 Dify 里接入时工作流加一个「工具」节点选 MCP ServerTransport 选 Streamable HTTPURL 填http://your-host:5100/mcpHeaders 加X-Api-Key: your-api-key。Coze 需要额外加一个MCP-Protocol-Version: 2025-03-26的 Header。n8n 当前版本不支持 Streamable HTTP走 SSESSE URL 填http://your-host:5100/mcp/sseMessage URL 填http://your-host:5100/mcp/messageServer 端EnableLegacySse true已经帮你开好了。Slickflow.AI 内置的McpServerClient可以自动发现远程工具Agent 节点运行时无需手动注册var client new McpServerClient(http://your-host:5100); var tools await client.DiscoverToolsAsync(); AgentToolRegistry.Global.Register(MY_ACTIVITY_ID, tools);McpClientTool内部走 JSON-RPC 2.0对 ReAct Agent 来说和本地 Function 完全透明。5. 本篇常见错排查401、SSE 兼容与参数缺失这一节对照真实报错给出定位思路。都是我在测试环境实际撞到的。报错一401 Unauthorized。最常见的原因是 Header 格式不对。Server 支持X-Api-Key: key和Authorization: Bearer key两种但不要同时传也不要写成X-Api-Key: Bearer key。另一个原因是 Key 里有空格复制时带上了首尾空白。排查方法先用/health确认服务活着再用一个空 Key 请求看是否进入开发模式返回正常说明是 Key 问题不是服务问题。报错二local proxy failed / connection refused。这个通常出现在 n8n 或 Dify 容器里。原因是容器内的localhost指向容器自己不是宿主机。把 URL 里的localhost换成宿主机的实际 IP 或 Docker 网络里的服务名。如果是 docker-compose 部署两个服务放同一个 network用服务名sfmcp:5100访问。报错三reading choices / 模型返回格式异常。这个报错一般不在 MCP Server 侧而在模型通道侧。如果你用 TaoToken 做模型入口检查 Base URL 是不是多写了/v1以及模型名是否在控制台列表里。Dify 的 OpenAI 兼容 Provider 对返回格式敏感Base URL 填错会导致解析失败。用模型对话页面 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 单独测一下模型能返回就说明通道没问题问题在编排平台的配置。报错四OAuth 相关错误。如果你在 Claude Code 或 Cline 里接入报 OAuth 错误通常是因为工具把 MCP Server 当成了需要 OAuth 的远程服务。实际上我们的 Server 用的是 API Key 鉴权不需要 OAuth 流程。检查配置里是不是误开了 OAuth 选项或者 Base URL 填成了需要 OAuth 的地址。Claude Code 的接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有正确的鉴权配置写法。报错五start_process 参数缺失。报错信息类似「ProcessId is required」。原因是工具层没有先查流程定义。引擎需要ProcessId Version只传ProcessCode不够。修复方法就是在工具方法里先调GetProcessByCode把查到的实体字段填进WfAppRunner。这个坑我在第一节的代码片段里已经规避了。报错六n8n SSE 连不上。n8n SDK 升级到 1.4.0 后需要 Server 端EnableLegacySse true才能走旧 SSE 通道。如果你关掉了这个选项n8n 会连不上。另外确认 SSE URL 和 Message URL 分别填对两个地址不一样。报错七PowerShell 下 curl 传 JSON 失败。这是 Windows 环境的坑。PowerShell 的curl是Invoke-WebRequest的别名inline JSON 的双引号会被剥离。解决办法是用curl.exe并改用-d file.json方式把 JSON 写到文件里再传。或者直接用 Git Bash 执行。排查顺序建议先/health确认服务再tools/list确认工具注册再只读工具确认数据库最后写入工具确认引擎。逐层排除比一上来就调start_process高效得多。6. 长期编码与 Agent 场景的通道选择MCP Server 跑通之后接下来要考虑的是长期使用场景。如果你只是偶尔验证一下工作流调用用模型对话页面手动测就够了。但如果你要把 Slickflow 工作流接入一个持续运行的 AI Agent或者用 Claude Code、Cline 这类编码工具长期开发建议走 Coding Plan 通道。Coding Plan 适合谁需要长期调用模型做编码、Agent 编排、工作流自动化的开发者。它的优势是配额稳定、Key 复用不用每次调试都担心额度。配置入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有套餐说明和接入方式。具体到 Slickflow 场景长期 Agent 的典型链路是Agent 收到业务请求 → 调search_knowledge_base查规则 → 根据规则决定流程走向 → 调start_process发起流程 → 调run_process推进审批 → 调get_approval_trace查轨迹。这条链路里模型调用频繁用 Coding Plan 比按次计费更划算。如果你在 Claude Code 里开发这个 MCP Server接入配置需要 Base URL Key Model ID 三件套。Base URL 用https://taotoken.net/apiKey 用控制台创建的 API KeyModel ID 按实际模型填。Claude Code 的完整配置在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 里面有 settings 文件的写法。Cline 的 MCP 配置在第四节已经给过 JSON 片段把url指向你的 MCP Serverheaders里放 Key 即可。API Keys 管理页面在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以创建多个 Key 分别给不同环境用生产环境和测试环境隔离出问题好定位。最后说一个实用技巧MCP Server 的工具描述[Description]注解会直接影响大模型生成参数的准确率。描述写得越具体模型越不容易传错参数。比如start_process的processCode描述里写上「从 list_processes 获取」模型就会先调list_processes再调start_process而不是瞎猜一个 Code。这个细节比任何 prompt 工程都管用因为它是协议层面的约束。整套跑下来从 TaoToken 拿 Key 到 MCP Server 验证通过顺利的话半天能搞定。卡住的地方大概率在鉴权 Header 和 n8n 的 SSE 兼容上对照第五节的报错清单逐个排就行。