Skip to main content
Glama
eddii1

Payment Delay MCP

by eddii1

Payment Delay MCP - 通过 MCP 将生产级 ML 模型提供给任意 LLM

一个部署在 FastAPI 微服务背后的 scikit-learn 分类器,以 Model Context Protocol 工具的形式发布给语言模型——因此现成的聊天客户端无需编写任何针对它的集成代码,即可正确发现并调用该模型。

gpt-oss-120b 选择正确的 MCP 工具并调用模型 API

核心论点

模型是载荷,而不是重点。

大多数"AI 驱动"的演示都将模型调用硬编码进一个定制应用中。本项目将其反转:分类器以协议的形式发布,因此 LLM 客户端是可替换的。同一个服务器驱动着 Docker 中的 OpenWebUI、CLI 上的 OpenCode 以及 Claude Desktop——无需任何代码改动,也无需任何客户端专属适配器。


概述

一家电信运营商想知道哪些客户会延迟付款。一个训练好的分类器可以回答这个问题,但一个 .pkl 文件并不是产品——仍然需要有人编写胶水代码来调用它,而且这套胶水代码每新增一个消费者就要重写一次。

本仓库就是这套胶水代码,以协议的形式只写一次。共四层,每一层都可独立部署:

flowchart TB
    subgraph reasoning["Reasoning path"]
        UI["OpenWebUI<br/>:3000"] -->|OpenAI protocol| LL["LiteLLM<br/>:4000"]
        LL -->|bedrock_mantle| BR["AWS Bedrock<br/>gpt-oss-120b"]
    end

    subgraph tools["Tool path"]
        UI -->|OpenAPI| MCPO["mcpo<br/>:8001"]
        MCPO -->|MCP over stdio| FM["FastMCP server<br/>5 tools · 2 resources · 1 prompt"]
        FM -->|HTTP| API["FastAPI service<br/>:8000"]
        API --> PRED["inference.predictor<br/>the only code that<br/>opens the pickle"]
        PRED --> PKL[("models/*.pkl<br/>RandomForest +<br/>RandomOverSampler")]
    end

    style reasoning fill:#1f2a3710,stroke:#8884
    style tools fill:#1f372a10,stroke:#8884

这两条路径是刻意分离的。LLM 从不执行任何东西。 它发出一条 tool_calls 消息,指明一个工具及其参数;客户端执行该工具并回放结果。正是这种区分使得模型可替换——也正是为什么无论推理层是 Bedrock、本地 Ollama 还是 Claude,这套技术栈都能以完全相同的方式工作。


Related MCP server: Company API MCP Server

核心思想:工具选择是一个文档问题

LLM 根据工具的名称、签名和 docstring 来选择工具——仅此而已。没有微调、没有示例、没有路由逻辑。因此 docstring 就是接口,编写 docstring 是工程工作,而不是注释。

这里有两个工具高度重叠。两者都预测付款延迟。要让模型在无提示的情况下正确选择,需要将操作约束直接编码进描述中:

工具

模型应选择它的时机

消歧信号

predict_payment_delay

用户有一个 CSV,以路径或粘贴文本形式提供

docstring 警告:当服务器运行在无法看到用户文件系统的容器中时,csv_path 会失败,应优先使用 csv_text

predict_single_customer

用户用自然语言描述一个客户

docstring 说明"适用于 LLM 从自然语言中提取单个客户并填入结构化特征的情况"

已验证的结果: 给定一个用纯英文描述的客户,gpt-oss-120b 在无辅助的情况下选择了 predict_single_customer 而非 predict_payment_delay,从自然语言中填充了特征字典,并返回了一个有依据的答案。两跳的日志中都得到了确认——mcpo 处 POST /predict_single_customer 200,随后模型服务处 POST /predict 200

这就是本项目的全部主张,而且它是可证伪的:禁用该工具后,同一个模型会以同样的自信回答同一个问题,但答案是错的,且两个日志面板都是空的。


一次请求的完整链路

大多数工具调用示意图遗漏的部分是:一个用户问题需要两次到模型的往返,且中间的助手消息必须逐字回放,否则 tool_call_id 就会悬空:

sequenceDiagram
    participant U as User
    participant W as OpenWebUI
    participant L as LiteLLM
    participant M as Bedrock model
    participant O as mcpo
    participant S as FastMCP
    participant A as FastAPI + model

    U->>W: "Will customer X pay late?"
    W->>L: messages[] + tools[]
    L->>M: translated to Bedrock
    M-->>W: finish_reason: tool_calls
    Note over W: the client executes,<br/>not the model
    W->>O: POST /predict_single_customer
    O->>S: MCP call over stdio
    S->>A: POST /predict
    A-->>S: {prediction, probability_yes}
    S-->>O: result
    O-->>W: 200 OK
    W->>L: messages[] + assistant(tool_calls) + tool(result)
    L->>M: second round trip
    M-->>U: grounded natural-language answer

tools[] 数组在每次请求时都会重新发送——模型是无状态的,每一轮都会重新发现工具集。


已验证的内容

四个检查点,每一个都对照日志确认,而非凭假设:

#

证据

1

模型服务

GET /health 200;单行 POST /predict 返回 noconfidence 0.985

2

mcpo 桥接层

:8001/docs 处渲染出 5 个工具;predict_single_customer 已通过 curl 执行

3

LiteLLM 到 Bedrock

/v1/models 列出该模型;一个工具调用请求返回 finish_reason: tool_calls

4

完整自主循环

从一个纯英文问题出发,mcpo 处 POST /predict_single_customer 200 API 处 POST /predict 200

检查点 3 比看起来更重要:finish_reason: tool_calls 是区分"模型拒绝使用工具"与"工具从未提供给模型"的唯一方式。这两种失败在聊天窗口中看起来完全一样。


模型

数据集披露。 训练数据是一个公开的电信流失基准数据集,为本次练习的目的将目标列重新标记为 payment_delay。特征是通话记录和账户字段,而非账单历史。建模是真实的,流水线是真实的;业务框架是合成的。请将这些数字视为一个工作示例,而非经过验证的信用风险模型。

属性

行数 / 列数

3,000 / 20

类别平衡

no 2,587(86.23%)· yes 413(13.77%)

流水线

ColumnTransformer -> RandomOverSampler -> RandomForestClassifier(imblearn)

划分

80/20 分层划分

推理时的特征数

36 - 19 个原始特征加 17 个派生 <column>_is_outlier 标志

决策阈值

0.35,作为工件持久化

阈值不是 0.5,也不是硬编码的。它以 models/threshold.pkl 的形式随附,并且可以在每次请求时覆盖,因为在正样本仅占 13.77% 的目标上,默认截断值优化的是错误的东西。更低的阈值能捕获更多延迟付款者,代价是更多误报,而哪种权衡是正确的属于业务决策,而非建模决策——因此 API 将其作为参数暴露。

代码库中没有任何地方硬编码列名。特征顺序来自 feature_columns.pkl,离群值边界来自 outlier_bounds.pkl,因此重新训练不需要修改代码。


值得辩护的工程决策

MCP 服务器从不导入模型。 它通过 HTTP 调用 API。这使 MCP 进程保持轻量——没有 sklearn,没有常驻的 9 MB pickle——并让模型服务像任何其他微服务一样进行扩展、部署和监控。协议适配器不应包含任何业务逻辑。

预测在事件循环之外运行。 推理调用通过 run_in_threadpool 分发,因此在并发请求下,CPU 密集型的评分永远不会阻塞 FastAPI 的异步循环。

stdio 纪律。 基于 stdio 的 MCP 要求 stdout 只承载 JSON-RPC 帧,不能有其他内容,因此一个多余的 print() 就会破坏流并终止会话。因此所有日志都路由到 stderr,httpxhttpcore 被静音,launcher.py 将 uvicorn 的输出重定向到日志文件,等待 /health,然后才将干净的 stdio 交给客户端。

两个入口点对应两种拓扑。 server.py 是容器入口点,API 是独立服务。launcher.py 是本地入口点,它自行启动 API 并等待其就绪——这适合期望一个进程拥有其依赖项的桌面 MCP 客户端。

一个记录了真实事故的版本钉住。 mcp>=1.2.0,<2.0:mcp 2.x 重命名了 streamablehttp_client,而 mcpo 0.0.20 仍导入旧名称,因此 mcpo 在 2.x 上会崩溃循环。该上限在 requirements.txt 中附有原因注释,因为没有原因的版本钉住会被下一个读到它的人删除。


仓库结构

mcp-payment-delay/
├── src/payment_delay/
│   ├── config.py                 # single source of truth for paths + endpoints, all env-overridable
│   ├── inference/predictor.py    # the only code that opens the pickle; imports no web framework
│   ├── api/main.py               # thin FastAPI adapter over the predictor
│   └── mcp_server/
│       ├── server.py             # FastMCP tools, resources, prompt (container entrypoint)
│       ├── api_client.py         # HTTP calls into the model service
│       └── launcher.py           # starts the API, then serves MCP on clean stdio (local entrypoint)
├── models/                       # model, threshold, outlier bounds, feature order
├── data/telecomunicatii.csv      # sample dataset
├── deploy/litellm_config.yaml    # Bedrock routing
├── scripts/bedrock_smoke_test.py # asserts a tool call comes back, not merely a 200
├── docs/                         # architecture + Docker runbook
├── Dockerfile                    # one image, serves both the API and the mcpo bridge
└── docker-compose.yml            # API + mcpo + LiteLLM + OpenWebUI

快速开始

单独运行模型服务——无需云凭证

python3 -m venv .venv && source .venv/bin/activate
make install                       # pip install -e ".[dev]"
make api                           # http://localhost:8000/docs

端点

用途

GET /health

服务已启动,模型已加载

GET /model/info

模型类型、类别、特征、阈值

GET /schema

所需的 CSV 列

POST /predict

一行(JSON 对象或单行 CSV)-> 一个是/否

POST /predict/batch

多行 CSV -> 每行一个是/否

POST /predict/summary

多行 CSV -> 整个文件一个是/否

curl -F "file=@data/telecomunicatii.csv" \
     "http://localhost:8000/predict/summary?threshold=0.35"

接入你自己的 MCP 客户端

python3 -m payment_delay.mcp_server.launcher

通过 stdio 提供工具,并在 API 尚未健康时启动它。opencode.json 将其接入 OpenCode;Claude Desktop 和任何其他 stdio MCP 客户端以相同方式接入。

运行完整技术栈

cp .env.example .env               # add your Bedrock key
python3 scripts/bedrock_smoke_test.py
make stack                         # http://localhost:3000

完整运行手册,包括凭证设置和故障排查:docs/docker-stack.md


MCP 表面

五个工具、两个资源、一个提示词模板:

get_api_health           service + model status
get_model_info           model metadata, classes, features, endpoints
get_input_schema         expected CSV columns
predict_payment_delay    CSV in (path or text), per-row or aggregate, threshold configurable
predict_single_customer  one customer as a JSON object

payment-delay://context       business + modelling context, injected as a resource
payment-delay://api-contract  the HTTP contract these tools call

interpret_payment_delay_result   prompt template for business-language explanation

资源和提示词是 MCP 中被低估的一半。上下文资源意味着客户端不需要被告知模型是做什么的——它可以自己读取。


技术栈

FastAPI · FastMCP · mcpo · scikit-learn · imbalanced-learn · pandas · LiteLLM · AWS Bedrock · OpenWebUI · Docker Compose · uvicorn · httpx

文档


Eduard-Gabriel Tudoran,2026 年。

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes enterprise KPIs, health scores, forecasting, and anomaly detection as MCP tools, resources, and prompts for use by any MCP-compatible agent.
    2
    AGPL 3.0
  • F
    license
    Not graded
    quality
    C
    maintenance
    Exposes internal company services as LLM-callable MCP tools, enabling AI agents to perform business operations like customer management, order processing, and support ticketing through natural language.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Exposes a governed lending portfolio (loans, customers, risk-tier history) to any MCP-compatible AI client via read-only tools, schema resources, and analysis prompts, wrapping an existing API gateway instead of connecting directly to the database.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/eddii1/mcp-payment-delay'

If you have feedback or need assistance with the MCP directory API, please join our Discord server