CheckSlip MCP

CheckSlip MCP

A remote MCP server for verifying Thai bank transfer slips using slip images, QR payloads, or transaction references, with OAuth 2.1 authentication and duplicate detection.

Category
访问服务器

README

CheckSlip MCP

A deployable remote MCP server (Streamable HTTP) for verifying Thai bank transfer slips. It exposes MCP tools over HTTP so any MCP-compatible client can verify a slip's amount, receiver, transfer date, and detect duplicate usage.

This server runs on Replit and is built into the monorepo's Express service. The MCP endpoint is served at the root path (/mcp), protected by a full OAuth 2.1 flow so MCP clients (e.g. Claude's "Connect") can sign in. /health, /, and the OAuth discovery/authorization endpoints are public.

Endpoints

  • POST /mcp — MCP Streamable HTTP (initialize + requests). Requires a valid OAuth access token (Authorization: Bearer <token>).
  • GET /mcp — MCP server-to-client stream (requires an active session)
  • DELETE /mcp — terminate an MCP session
  • GET /health — { "ok": true, "name": "CheckSlip MCP", "version": "1.0.0" }
  • GET / — basic server info
  • GET /admin — password-gated merchant console (create/list/revoke/rotate keys)
  • OAuth (public): GET /.well-known/oauth-protected-resource, GET /.well-known/oauth-authorization-server, POST /register (DCR), GET|POST /authorize, POST /token

Authentication (OAuth 2.1)

The /mcp endpoint is protected by an OAuth 2.1 Authorization Code flow with PKCE, designed for MCP clients like Claude's custom connector:

  1. The client reads /.well-known/oauth-protected-resource (advertised via the WWW-Authenticate header on a 401) to discover the authorization server.
  2. It registers dynamically via POST /register (DCR), then opens /authorize in a browser.
  3. The user signs in with their Merchant Name and API Key (issued from the /admin console). On success an authorization code is redirected back.
  4. The client exchanges the code at /token (verifying PKCE) for a short-lived JWT access token (signed with SESSION_SECRET, audience <base>/mcp) plus a rotating refresh token.

Merchants and their API keys are managed in the /admin console, gated by ADMIN_PASSWORD. A static MCP_AUTH_TOKEN is still accepted as a fallback for server-to-server callers when set, but is no longer required.

MCP tools

check_slip

Verifies a slip via a slip image, a QR payload, or a transaction reference.

Input:

{
  "slip_image_base64": "base64 PNG/JPEG (optional)",
  "qr_payload": "string (optional)",
  "transaction_ref": "string (optional)",
  "expected_amount": "number > 0 (optional)",
  "expected_receiver_name": "string (optional)",
  "expected_receiver_account_last4": "4 digits (optional)",
  "expected_transfer_date": "YYYY-MM-DD (optional)",
  "order_id": "string (optional)",
  "mark_as_used": "boolean (default false)"
}

At least one of slip_image_base64, qr_payload, or transaction_ref is required. When only slip_image_base64 is given (raw base64 or a data:image/...;base64, data URL), the server decodes the QR code from the image and uses it as the QR payload. The result is returned as JSON text content with status one of verified | failed | duplicate | provider_error | config_error.

Comparison rules:

  • Amount: exact numeric match.
  • Receiver name: case-insensitive, whitespace-trimmed.
  • Receiver account last 4: digits only.
  • Date: compares the YYYY-MM-DD part of the slip's transfer datetime.
  • Fields you don't pass are omitted from checks (not reported as false).

When mark_as_used is true and all checks pass, the slip's transaction id is recorded so future checks of the same slip return status: "duplicate".

slip_checker_status

Returns configuration/health without exposing secrets (provider, whether an API URL/key is set, duplicate store path, auth config (OAuth enabled + whether the static token fallback is set), allowed-origins count).

Setup on Replit

  1. The project already runs on Replit. Add these Secrets / env vars:

    Key Required Notes
    SESSION_SECRET Yes Signs OAuth access tokens and admin sessions. Server refuses to start without it.
    ADMIN_PASSWORD Yes Gates the /admin merchant console. Server refuses to start without it.
    MCP_AUTH_TOKEN No Optional static Bearer token fallback for server-to-server callers.
    SLIP_PROVIDER No mock (default), uex, or generic.
    ALLOWED_ORIGINS No Comma-separated allowlist. Empty allows requests with no Origin.
    UEX_ACCOUNT_NO uex only Secret. UEX bank account number (used in the request path).
    UEX_LICENSE_KEY uex only Secret. UEX x-license-key.
    UEX_ACCESS_KEY uex only Secret. UEX access-key.
    UEX_API_BASE_URL No UEX base URL (default https://api-fin.uexchange.io/v1/fin/bank).
    SLIP_API_URL generic only Custom provider verify endpoint.
    SLIP_API_KEY generic only Custom provider API key.
    SLIP_API_AUTH_HEADER No Header name for the key (default Authorization).
    SLIP_API_KEY_PREFIX No Prefix for the key value (default Bearer).
    SHOP_RECEIVER_NAME No Default receiver name for the mock provider.
    SHOP_RECEIVER_ACCOUNT_LAST4 No Default receiver last 4 for the mock provider.
  2. Run (development): the workflow runs the server automatically. To run the commands manually:

    pnpm --filter @workspace/api-server run dev
    
  3. MCP endpoint (after publishing):

    https://<your-replit-url>/mcp
    
  4. Authentication: point your MCP client at the /mcp URL and use its "Connect" flow. It will discover the OAuth endpoints, open the browser login, and ask for your Merchant Name and API Key (created in /admin). The client then attaches Authorization: Bearer <access_token> automatically.

    To create a merchant + API key, open https://<your-replit-url>/admin, sign in with ADMIN_PASSWORD, add a merchant, and copy the one-time API key.

Mock test

With SLIP_PROVIDER=mock, call check_slip with:

{
  "qr_payload": "MOCK_OK",
  "expected_amount": 1590,
  "expected_receiver_name": "ABC SHOP",
  "expected_receiver_account_last4": "1234",
  "order_id": "ORDER-TEST-001",
  "mark_as_used": true
}

Mock values:

  • MOCK_OK → verified slip (amount 1590).
  • MOCK_890 → verified slip (amount 890).
  • MOCK_FAIL → provider reports not verified.

UEX provider (real Thai bank verification)

Verifies slips through the UEX (uexchange.io) Qr Scan API.

SLIP_PROVIDER=uex
UEX_ACCOUNT_NO=<your account number>   # secret
UEX_LICENSE_KEY=<your x-license-key>   # secret
UEX_ACCESS_KEY=<your access-key>       # secret
# UEX_API_BASE_URL defaults to https://api-fin.uexchange.io/v1/fin/bank

How it works:

  • check_slip's qr_payload (or the QR decoded from slip_image_base64, or transaction_ref) is sent as the qrString to POST {UEX_API_BASE_URL}/{UEX_ACCOUNT_NO}/qrScan with the x-license-key and access-key headers.
  • A response with inner statusCode: "0000" is a verified slip; its fields (transaction ref, amount, receiver name/account, transfer date, bank) are mapped into the internal slip shape.
  • 8xx data errors such as 8404 ("Transaction Reference does not exist") are reported as failed (the slip is invalid/not found). System errors are reported as provider_error.

Switching to a custom provider

SLIP_PROVIDER=generic
SLIP_API_URL=https://your-slip-provider.example.com/verify
SLIP_API_KEY=your_api_key

The generic provider POSTs { qr_payload, transaction_ref } and normalizes common provider field names into the internal slip format.

Automated tests

Vitest + Supertest cover the OAuth 2.1 security boundary and the admin/merchant console. They run against the dev Postgres database (DATABASE_URL) and create their own uniquely-named merchants, cleaning up afterward.

pnpm --filter @workspace/api-server run test

Covered: DCR, authorize → token with PKCE (happy path + wrong verifier), single-use auth codes, refresh-token rotation invalidating the old token, exact aud/iss enforcement on /mcp, invalid/expired token rejection, merchant credential validation, and the admin password gate + create/revoke/rotate. The suite is registered as the test validation (CI) check.

Smoke test

Checks /health and prints example check_slip input (no MCP client needed):

pnpm --filter @workspace/scripts run smoke

Warning

This server verifies slips through a provider API, never from the picture alone. When you pass slip_image_base64, the server only reads the slip's QR code from the image and forwards that QR payload to the provider; the rest of the image is not trusted. Slips without a readable QR code must be supplied as a qr_payload or transaction_ref instead.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选