Skip to main content
Glama
asmydev

asmy-mcp-server

Official
by asmydev

asmy-mcp-server

用于 Asmy Digital Store 的 MCP 服务器。以 MCP 工具的形式公开产品目录、促销代码和商店统计信息,可供代理(Junior.so、Claude Desktop 或任何 MCP 客户端)使用。

数据后端:Firestore。两种传输方式:stdio 和 HTTP(SSE + Streamable HTTP)。

先决条件

  • Node >= 18(推荐使用 Bun,npm 脚本会用到它)

  • 一个启用了 Firestore 的 Firebase 项目

  • 一个 Firebase 服务账号密钥

Related MCP server: shopify-mcp-server

安装

bun install          # ou npm install
cp .env.example .env

配置

Firebase

服务器按以下顺序解析凭据(firebase-config.js):

  1. FIREBASE_SERVICE_ACCOUNT — 完整的 JSON,单行或 base64 格式

  2. FIREBASE_SERVICE_ACCOUNT_FILE — 文件路径

  3. ./firebase-service-account.json — 回退,位于 index.js 旁边

如果 FIREBASE_SERVICE_ACCOUNT 存在但无效,则会回退到文件,并在 stderr 上输出警告,而不是崩溃。

本地:使用文件。生产环境:使用环境变量(base64 可避免 private_key 的转义问题)。

firebase-service-account.json 文件已在 .gitignore 中。没有理由将其移出。

环境变量

变量

默认值

作用

PORT

3000

HTTP 端口

HOST

0.0.0.0

监听接口

ALLOWED_HOSTS

—

允许的主机,以逗号分隔。绑定到 0.0.0.0 时需要

FIREBASE_SERVICE_ACCOUNT

—

服务账号 JSON(单行或 base64)

FIREBASE_SERVICE_ACCOUNT_FILE

—

JSON 的备用路径

MCP_STDIO

—

1 强制使用 stdio 传输

OPENAI_API_KEY

—

仅用于测试客户端

OPENAI_MODEL

gpt-4o-mini

仅用于测试客户端

MCP_SERVER_URL

—

仅用于 test-mcp-url.js

localhost、127.0.0.1、[::1] 和 RAILWAY_PUBLIC_DOMAIN(由 Railway 注入)会自动添加到允许的主机列表中。

注意:env.js 是一个自制的 .env 解析器,无依赖。它支持多行 JSON 值(花括号)——便于将原始服务账号粘贴到文件中。它不支持其他功能:没有插值,没有特殊转义。

启动

bun start          # HTTP sur $PORT
bun run dev        # HTTP + watch
bun run start:stdio  # transport stdio

如果传入 --stdio 参数或设置了 MCP_STDIO=1,服务器会选择 stdio。否则使用 HTTP。

HTTP 端点

路由

方法

描述

/

GET

健康检查,返回服务器名称和端点列表

/mcp

ALL

Streamable HTTP(规范 2025-11-25),通过 mcp-session-id 头管理会话

/sse

GET

旧版 SSE(规范 2024-11-05)——这是 Junior.so 使用的端点

/messages

POST

SSE 传输的返回通道,通过 ?sessionId= 管理会话

两种传输方式共存。在 SSE 中打开的会话不能在 /mcp 上恢复(返回 -32000)。

会话存储在本地对象的内存中。后果:只能单实例。没有粘性会话或共享存储,就无法水平扩展。

暴露的工具

16 个工具,全部定义在 index.js 中。

产品(products 集合)

工具

描述

list_products

目录,包含状态、价格、库存

get_product

按 slug 或 Firestore id 获取详情

create_product

创建。autoFindImage=true 触发图标搜索

update_product

部分更新

set_product_status

active / draft / featured

duplicate_product

复制,可指定新名称

delete_product

永久删除

find_product_image

仅搜索图标,不写入数据库

促销(promotions 集合)

工具

描述

list_promos

所有代码

get_promo

按代码搜索

create_promo

拒绝重复代码

update_promo

代码、折扣或过期时间

delete_promo

删除

其他

工具

描述

get_stats

读取 stats/overview

update_stats

添加条目并重新计算当月总计

get_current_date

当前日期,时区为 Africa/Douala(UTC+1)

get_current_date 存在是因为 LLM 会弄错日期并生成过去的 expiresAt。创建促销代码的代理应首先调用它。

约定

  • 促销代码规范化为大写,expiresAt 格式为 YYYY-MM-DD,discount 在 1 到 100 之间。

  • 产品 slug 从名称派生(NFD,去除重音,非字母数字字符替换为连字符)。

  • 返回的每个产品都带有基于 https://asmystore.shop/abonnements/{slug} 构建的 url。

  • update_stats 推送到 history,然后通过过滤 YYYY-MM 前缀重新计算 monthTotal 和 monthOrders。写入两次相同条目会计算两次——没有去重。

图片搜索

product-image.js 分两轮解析产品图标:

  1. Clearbit(logo.clearbit.com/{domain}),带有品牌 → 域名映射表和 {slug}.com / {slug}.io 回退

  2. DuckDuckGo Images

每个候选都通过 HEAD(如果 HEAD 没有返回可用内容,则使用带 Range 的 GET)验证,以确保 content-type 确实是图片。

需要记住两点:DuckDuckGo 的 i.js 端点不是公共 API——需要先抓取 vqd 令牌,并且可能随时失效。此外,获取的徽标属于相关品牌;你需要自行确认在商店中展示是否合法。

如果失败,工具会返回明确的错误,产品将在没有图标的情况下创建。

测试

两个测试客户端,都连接到 OpenAI 以进行自然语言工具调用。需要 OPENAI_API_KEY。

bun run test:mcp                          # spawn le serveur en stdio
bun run test:mcp "Liste les produits actifs"

MCP_SERVER_URL=https://xxx.up.railway.app bun run test:mcp:url
bun test-mcp-url.js https://xxx.up.railway.app "Quelle est la date ?"

不带参数时,两者都进入 REPL 模式。最多 10 轮工具调用。

部署(Railway)

  1. 将仓库(私有)推送到 GitHub

  2. Railway → New Project → Deploy from GitHub

  3. 变量:FIREBASE_SERVICE_ACCOUNT(base64),如果需要则设置 PORT

  4. RAILWAY_PUBLIC_DOMAIN 会自动注入并添加到允许的主机中——否则,手动填写 ALLOWED_HOSTS

服务器处理 SIGINT / SIGTERM:在退出前关闭打开的传输。

从 Junior.so 连接

仪表板 → 代理 → Integrations → Create → Custom → MCP,然后使用 SSE URL:

https://<ton-domaine>.up.railway.app/sse

Junior 使用 2024-11-05 规范,因此使用 /sse 而不是 /mcp。连接后会自动列出 16 个工具。

促销迁移

migrate-promos.js 是一个一次性脚本,用于将前端的 localStorage 中的促销代码迁移到 Firestore。

  1. 在 asmystore.shop 上,打开开发者控制台:localStorage.getItem("asmy-admin-promos")

  2. 将 JSON 粘贴到脚本的 PROMOS_JSON 常量中

  3. bun migrate-promos.js

注意:此脚本硬编码读取 firebase-service-account.json,不经过 firebase-config.js。环境变量在此不起作用,需要文件。该脚本旨在运行一次后即被遗忘。

前端方面,记得将促销的读写从 localStorage 切换到 promotions 集合,否则两个来源会不一致。

故障排除

启动时出现 Firebase non configuré — 未找到 FIREBASE_SERVICE_ACCOUNT、FIREBASE_SERVICE_ACCOUNT_FILE 或默认文件。

JSON Firebase incomplet — JSON 已解析,但缺少 type: "service_account" 或 private_key。通常是复制粘贴不完整或 base64 结尾错误。

生产环境请求被拒绝,但本地正常 — 针对 DNS 重绑定的保护。主机不在 allowedHosts 中。请填写 ALLOWED_HOSTS。

/messages 上出现 Session not found — SSE 会话已过期或服务器已重启。会话在内存中,重新部署会清除所有会话。

客户端看不到任何工具 — 检查是否确实访问的是 /sse(旧版规范)而不是 /mcp,并且 GET / 有响应。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    A production-grade MCP server and CLI tool that enables AI agents to manage Shopify stores through 49 built-in tools across products, orders, inventory, and analytics. It supports natural language workflows for tasks like inventory tracking, customer support, and sales reporting.
    93 npm
    18
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Exposes the Loyverse API as MCP tools to manage stores, products, inventory, customers, receipts, and more from AI assistants.
    54
    MIT