Payment Delay MCP
Payment Delay MCP - 프로덕션 ML 모델을 MCP를 통해 모든 LLM에 제공하기
FastAPI 마이크로서비스 뒤에 배포되고 Model Context Protocol 도구로 언어 모델에 게시된 scikit-learn 분류기 - 그래서 기성 채팅 클라이언트가 모델을 발견하고 올바르게 호출하며, 이를 위해 작성된 통합 코드가 전혀 없습니다.

핵심 주장
모델은 페이로드이지, 핵심이 아닙니다.
대부분의 "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은 아무것도 실행하지 않습니다. LLM은 도구와 그 인자를 지정하는 tool_calls 메시지를 내보내고, 클라이언트가 이를 실행하고 결과를 재생합니다. 그 구분이 모델을 교체 가능하게 만드는 이유이며, 추론 계층이 Bedrock이든, 로컬 Ollama든, Claude든 이 스택이 동일하게 작동하는 이유입니다.
Related MCP server: Company API MCP Server
핵심 아이디어: 도구 선택은 문서화 문제입니다
LLM은 도구의 이름, 시그니처, docstring에서만 도구를 선택합니다 - 그 외에는 아무것도 없습니다. 파인튜닝도, 예시도, 라우팅 로직도 없습니다. 따라서 docstring이 인터페이스이며, docstring을 작성하는 것은 주석이 아니라 엔지니어링 작업입니다.
여기 두 도구는 크게 겹칩니다. 둘 다 지불 지연을 예측합니다. 모델이 프롬프트 없이 올바르게 선택하게 하려면 운영상의 제약을 설명에 직접 인코딩해야 했습니다:
도구 | 모델이 선택해야 하는 경우 | 구분 신호 |
| 사용자가 CSV를 경로 또는 붙여넣은 텍스트로 가진 경우 | docstring은 |
| 사용자가 한 고객을 자연어로 설명하는 경우 | docstring은 "LLM이 한 고객을 구조화된 피처로 추출하는 자연어 사례용"이라고 말합니다 |
검증된 결과: 평범한 영어로 설명된 고객이 주어졌을 때, gpt-oss-120b는 도움 없이 predict_payment_delay 대신 predict_single_customer를 선택했고, 산문에서 피처 사전을 채웠으며, 근거 있는 답변을 반환했습니다. 두 홉 모두의 로그에서 확인됨 - 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 answertools[] 배열은 모든 요청에 재전송됩니다 - 모델은 상태가 없으며 매 턴 도구 세트를 다시 발견합니다.
검증된 것
네 개의 체크포인트, 각각 가정이 아닌 로그로 확인됨:
# | 계층 | 증거 |
1 | 모델 서비스 |
|
2 | mcpo 브리지 |
|
3 | LiteLLM에서 Bedrock으로 |
|
4 | 전체 자율 루프 | 평범한 영어 질문에서 mcpo의 |
체크포인트 3은 보기보다 중요합니다: finish_reason: tool_calls는 "모델이 도구 사용을 거부했다"와 "도구가 모델에게 제공되지 않았다"를 구분하는 유일한 방법입니다. 그 실패들은 채팅 창에서 동일하게 보입니다.
모델
데이터셋 공개. 훈련 데이터는 이 연습을 위해 타겟 컬럼이
payment_delay로 재명명된 공개 통신 이탈(churn) 벤치마크입니다. 피처는 통화 기록 및 계정 필드이며, 청구 이력이 아닙니다. 모델링은 실제이고 파이프라인은 실제입니다; 비즈니스 프레임은 합성입니다. 숫자를 검증된 신용 위험 모델이 아닌 작업 예시로 취급하십시오.
속성 | 값 |
행 / 열 | 3,000 / 20 |
클래스 균형 |
|
파이프라인 |
|
분할 | 80/20 계층적(stratified) |
추론 시 피처 | 36 - 19개 원본 + 17개 파생 |
결정 임계값 | 0.35, 아티팩트로 영속화 |
임계값은 0.5가 아니며 하드코딩되지 않습니다. models/threshold.pkl로 제공되며 요청별로 재정의할 수 있습니다. 양성 타겟이 13.77%인 경우 기본 컷오프는 잘못된 것을 최적화하기 때문입니다. 더 낮은 임계값은 더 많은 오탐지 비용으로 더 많은 연체자를 잡아내며, 어떤 트레이드오프가 올바른지는 모델링 결정이 아니라 비즈니스 결정입니다 - 그래서 API는 이를 매개변수로 노출합니다.
코드베이스 어디에도 컬럼 이름이 하드코딩되어 있지 않습니다. 피처 순서는 feature_columns.pkl에서, 이상치 경계는 outlier_bounds.pkl에서 오므로, 재훈련에 코드 변경이 필요하지 않습니다.
방어할 가치가 있는 엔지니어링 결정
MCP 서버는 모델을 절대 임포트하지 않습니다. HTTP를 통해 API를 호출합니다. 이는 MCP 프로세스를 작게 유지하고 - sklearn도, 9MB pickle도 상주하지 않으며 - 모델 서비스가 다른 마이크로서비스처럼 확장, 배포, 모니터링되게 합니다. 프로토콜 어댑터는 비즈니스 로직을 담지 않아야 합니다.
예측은 이벤트 루프 밖에서 실행됩니다. 추론 호출은 run_in_threadpool로 디스패치되어, CPU 바운드 스코어링이 동시 요청에서 FastAPI의 비동기 루프를 차단하지 않습니다.
stdio 규율. stdio를 통한 MCP는 stdout이 JSON-RPC 프레임만 전달해야 하며 다른 것은 전달하지 않아야 하므로, 잘못된 print()는 스트림을 손상시키고 세션을 죽입니다. 따라서 모든 로깅은 stderr로 라우팅되고, httpx와 httpcore는 침묵하며, 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엔드포인트 | 용도 |
| 서비스 가동, 모델 로드됨 |
| 모델 유형, 클래스, 피처, 임계값 |
| 필수 CSV 컬럼 |
| 한 행(JSON 객체 또는 한 행 CSV) -> 하나의 yes/no |
| 다중 행 CSV -> 행당 하나의 yes/no |
| 다중 행 CSV -> 전체 파일에 대해 하나의 yes/no |
curl -F "file=@data/telecomunicatii.csv" \
"http://localhost:8000/predict/summary?threshold=0.35"자신의 MCP 클라이언트 연결
python3 -m payment_delay.mcp_server.launcherstdio를 통해 도구를 제공하고 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
문서
아키텍처 - 계층, 예측 파이프라인, 그리고 분할이 그 위치에 있는 이유
Docker 스택 런북 - 자격 증명, 시작, 상태 확인, 문제 해결
docs/assignment/ - 원래 브리프
Eduard-Gabriel Tudoran, 2026.
This server cannot be installed
Maintenance
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
Unified MCP Server is a remote MCP connector for AI agents and vertical AI products that provides access to 22,000+ authorized SaaS tools across 400+ integrations and 24 categories directly inside LLMs (Claude, GPT, Gemini, Cohere). Tools operate only on explicitly authorized customer connections, enabling agents to safely read and write against live third-party systems.
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
Connect MCP clients to 2,000+ AI models without managing provider API keys.
Discover and call 10,000+ production APIs from one MCP server. Pay-per-call billing for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceExposes enterprise KPIs, health scores, forecasting, and anomaly detection as MCP tools, resources, and prompts for use by any MCP-compatible agent.2AGPL 3.0
- FlicenseNot gradedqualityCmaintenanceExposes 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.
- FlicenseNot gradedqualityCmaintenanceExposes 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.
- FlicenseAqualityBmaintenanceMCP server exposing a fictional payment domain as tools, resources, and prompts, enabling reasoning over transactions, payment hubs, services, and system health.8
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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