Muni - MCP是一款专业的建筑规范合规助手,它通过Municode API与市政建筑规范对接。旨在帮助专业承包商、经验丰富的建筑商和高级DIY爱好者精准且合规地应对复杂的建筑规范要求。
Muni - MCP能让你轻松访问市政建筑规范和合规数据,以下为你详细介绍如何开启使用之旅。
在开始之前,请确保你已完成以下准备:
git clone https://github.com/yourusername/muni - mcp.git
cd muni - mcp
npm install
npm install -g wrangler
npx wrangler kv namespace create "OAUTH_KV"
⚠️ 重要提示
此数据库名称必须为 "OAUTH_KV",不能使用其他名称。
id 和 preview_id 值的文本。wrangler.jsonc 文件。"kv_namespaces": [ 部分。"kv_namespaces": [
{
"binding": "OAUTH_KV",
"id": "paste - your - id - here",
"preview_id": "paste - your - preview - id - here"
}
]
cp .dev.vars.example .dev.vars
.dev.vars 文件。http://localhost:8787/callback/google
.dev.vars 文件中:GOOGLE_CLIENT_ID="paste - your - client - id - here"
GOOGLE_CLIENT_SECRET="paste - your - client - secret - here"
完成此步骤后,若你不需要GitHub登录,可直接进入步骤5。
若你更喜欢使用GitHub进行登录,而非Google:
http://localhost:8787。http://localhost:8787/callback/github。.dev.vars 文件中:GITHUB_CLIENT_ID="paste - your - client - id - here"
GITHUB_CLIENT_SECRET="paste - your - client - secret - here"
src/index.ts。import { GoogleHandler } from "./auth/google - handler";。import { GitHubHandler } from "./auth/github - handler";。defaultHandler: GoogleHandler as any, 的行。defaultHandler: GitHubHandler as any,。
完成步骤4a或4b后,进入步骤5。sk_test_ 开头)。price_ 开头)。.dev.vars 文件中:STRIPE_SECRET_KEY="sk_test_your - key - here"
STRIPE_SUBSCRIPTION_PRICE_ID="price_your - price - id - here"
STRIPE_METERED_PRICE_ID="your - stripe - metered - price - id"
此模板包含一个工具(check_user_subscription_status),可向最终用户提供其Stripe客户计费门户的链接。此门户允许用户管理其订阅,例如取消订阅或切换不同的计划(如果你进行了相应配置)。
初始设置(重要): 默认情况下,Stripe客户计费门户可能未在你的Stripe账户中完全配置,尤其是在测试环境中。
check_user_subscription_status 工具(例如,通过MCP Inspector或通过AI助手触发它)。billingPortal.message 包含类似如下的错误:"Could not generate a link to the customer billing portal: No configuration provided and your test mode default configuration has not been created. Provide a configuration or create your default by saving your customer portal settings in test mode at https://dashboard.stripe.com/test/settings/billing/portal."https://dashboard.stripe.com/test/settings/billing/portal),并在Stripe中保存你的门户设置。这将为你的测试环境激活该门户。你需要为生产环境进行类似的检查和配置。
激活后,check_user_subscription_status 工具将在其JSON响应的 billingPortal.url 字段中提供一个直接链接,用户可以使用该链接。允许用户切换计划(可选): 默认情况下,计费门户允许用户取消其现有订阅。如果你为MCP服务器提供多个订阅产品,并希望允许用户在它们之间切换:
https://dashboard.stripe.com/settings/billing/portal 用于生产模式,或 https://dashboard.stripe.com/test/settings/billing/portal 用于测试模式)。确保你的 .dev.vars 文件包含以下所有值:
BASE_URL="http://localhost:8787"
COOKIE_ENCRYPTION_KEY="generate - a - random - string - at - least - 32 - characters"
GOOGLE_CLIENT_ID="your - google - client - id"
GOOGLE_CLIENT_SECRET="your - google - client - secret"
STRIPE_SECRET_KEY="your - stripe - secret - key"
STRIPE_SUBSCRIPTION_PRICE_ID="your - stripe - price - id"
STRIPE_METERED_PRICE_ID="your - stripe - metered - price - id"
对于 COOKIE_ENCRYPTION_KEY,你可以使用以下命令生成一个随机字符串:
openssl rand -hex 32
npx wrangler dev
http://localhost:8787 启动。http://localhost:8787/sse。你可以通过以下方式连接到服务器进行测试:
http://localhost:8787/sse。{
"mcpServers": {
"my_server": {
"command": "npx",
"args": [
"mcp - remote",
"http://localhost:8787/sse"
]
}
}
}
npx @modelcontextprotocol/inspector@0.11.0
⚠️ 重要提示
MCP Inspector的最新版本是0.12.0,但目前使用
npx @modelcontextprotocol/inspector@latest无法正常工作,正在处理此问题。
http://localhost:8787/sse。当你准备好将服务器上线时:
npx wrangler deploy
https://your - worker - name.your - account.workers.dev 的URL。
3a. 更新你的Google OAuth设置:
https://your - worker - name.your - account.workers.dev/callback/google。https://your - worker - name.your - account.workers.dev/callback/github。npx wrangler secret put BASE_URL
npx wrangler secret put COOKIE_ENCRYPTION_KEY
npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret put STRIPE_SUBSCRIPTION_PRICE_ID
npx wrangler secret put STRIPE_METERED_PRICE_ID
对于 BASE_URL,使用你的Cloudflare URL:https://your - worker - name.your - account.workers.dev。
以下工具可供所有经过身份验证的用户使用:
search_building_codes这是查找特定规范要求的主要工具。
get_municipality_codes用于检索完整的市政规范结构。
validate_code_compliance将项目规格与适用规范进行交叉引用。
get_permit_requirements提供详细的许可证要求、费用和流程。
compare_jurisdictional_requirements比较多个管辖区域的规范要求。
search_building_codes 开始:
get_municipality_codes:
validate_code_compliance:
get_permit_requirements:
compare_jurisdictional_requirements:
始终考虑监管层级:
对于以下情况,建议寻求专业咨询:
你可以通过在 src/tools 文件夹中添加新文件来轻松创建自己的AI工具。该项目提供了免费和付费工具的示例,包括专门的建筑规范合规工具。
要创建免费工具(用户无需支付即可访问):
src/tools 文件夹中创建一个新文件(例如:myTool.ts)。add.ts 示例中复制以下模板:import { z } from "zod";
import { experimental_PaidMcpAgent as PaidMcpAgent } from "@stripe/agent - toolkit/cloudflare";
export function myTool(agent: PaidMcpAgent<Env, any, any>) {
const server = agent.server;
// @ts - ignore
server.tool(
"my_tool_name", // 工具名称
"This tool does something cool.", // 工具功能描述
{ // 输入参数
input1: z.string(), // 使用Zod定义参数
input2: z.number() // 例如,字符串、数字、布尔值
},
async ({ input1, input2 }: { input1: string; input2: number }) => ({
// 工具调用时运行的函数
content: [{ type: "text", text: `You provided: ${input1} and ${input2}` }],
})
);
}
myTool)。my_tool_name)。src/tools/index.ts:// 与其他导出一起添加此行
export * from './myTool';
src/index.ts 中注册你的工具:// 在init()方法内添加:
tools.myTool(this);
该项目包含专门的建筑规范合规工具,展示了专业级别的工具开发:
searchBuildingCodesTool:使用专业术语搜索建筑规范。getMunicipalityCodesTool:检索完整的市政规范结构。validateCodeComplianceTool:将项目规格与规范进行交叉引用。getPermitRequirementsTool:获取详细的许可证要求和费用。compareJurisdictionalRequirementsTool:比较多个管辖区域的要求。
这些工具展示了如何创建专业级工具,具有以下特点:你可以通过三种方式创建需要付费的工具:定期订阅、计量使用或一次性支付。
如果你想向用户收取定期费用(例如每月)以访问某个工具或一组工具,此选项很合适。
Stripe订阅计费设置
price_xxxxxxxxxxxxxx)。这是你将在 .dev.vars 文件中用于 STRIPE_SUBSCRIPTION_PRICE_ID 以及注册工具时使用的ID。工具实现
src/tools 文件夹中创建一个新文件(例如:mySubscriptionTool.ts)。subscriptionAdd.ts 示例中复制以下模板:import { z } from "zod";
import { experimental_PaidMcpAgent as PaidMcpAgent } from "@stripe/agent - toolkit/cloudflare";
import { REUSABLE_PAYMENT_REASON } from "../helpers/constants";
export function mySubscriptionTool(
agent: PaidMcpAgent<Env, any, any>,
env?: { STRIPE_SUBSCRIPTION_PRICE_ID: string; BASE_URL: string }
) {
const priceId = env?.STRIPE_SUBSCRIPTION_PRICE_ID || null;
const baseUrl = env?.BASE_URL || null;
if (!priceId || !baseUrl) {
throw new Error("Stripe Price ID and Base URL must be provided for paid tools");
}
agent.paidTool(
"my_subscription_tool_name", // 工具名称
{
// 输入参数
input1: z.string(), // 使用Zod定义参数
input2: z.number(), // 例如,字符串、数字、布尔值
},
async ({ input1, input2 }: { input1: string; input2: number }) => ({
// 工具调用时运行的函数
content: [
{ type: "text", text: `You provided: ${input1} and ${input2}` },
],
}),
{
priceId, // 使用Stripe订阅产品的价格ID
successUrl: `${baseUrl}/payment/success`,
paymentReason: REUSABLE_PAYMENT_REASON, // 显示给用户的通用原因
}
);
}
mySubscriptionTool)。my_subscription_tool_name)。src/tools/index.ts:// 与其他导出一起添加此行
export * from './mySubscriptionTool';
src/index.ts 中注册你的工具:// 在init()方法内添加:
tools.mySubscriptionTool(this, {
STRIPE_SUBSCRIPTION_PRICE_ID: this.env.STRIPE_SUBSCRIPTION_PRICE_ID, // 确保这与订阅价格ID匹配
BASE_URL: this.env.BASE_URL
});
如果你想根据用户对MCP工具的使用量收费,此选项很合适。
Stripe计量计费设置
price_xxxxxxxxxxxxxx)。metered_add_usage),你将在工具代码中使用它。你通常可以在产品的 “Usage” 标签下或定义计量价格时设置这个。工具实现
src/tools 文件夹中创建一个新文件(例如:myMeteredTool.ts)。meteredAdd.ts 示例启发的模板:import { z } from "zod";
import { experimental_PaidMcpAgent as PaidMcpAgent } from "@stripe/agent - toolkit/cloudflare";
import { METERED_TOOL_PAYMENT_REASON } from "../helpers/constants"; // 你可能需要一个特定的常量
export function myMeteredTool(
agent: PaidMcpAgent<Env, any, any>,
env?: { STRIPE_METERED_PRICE_ID: string; BASE_URL: string }
) {
const priceId = env?.STRIPE_METERED_PRICE_ID || null;
const baseUrl = env?.BASE_URL || null;
if (!priceId || !baseUrl) {
throw new Error("Stripe Metered Price ID and Base URL must be provided for metered tools");
}
agent.paidTool(
"my_metered_tool_name", // 工具名称
{
// 输入参数
a: z.number(),
b: z.number(),
},
async ({ a, b }: { a: number; b: number }) => {
// 工具调用时运行的函数
// 重要:你的工具的业务逻辑
const result = a + b; // 示例逻辑
return {
content: [{ type: "text", text: String(result) }],
};
},
{
checkout: {
success_url: `${baseUrl}/payment/success`,
line_items: [
{
price: priceId, // 使用Stripe计量产品的价格ID
},
],
mode: 'subscription', // 计量计划通常设置为订阅
},
paymentReason:
"METER INFO: Details about your metered usage. E.g., Your first X uses are free, then $Y per use. " +
METERED_TOOL_PAYMENT_REASON, // 自定义此消息
meterEvent: "your_meter_event_name_from_stripe", // ** 重要:使用你在Stripe meter设置中的事件名称 **
// 例如,"metered_add_usage"
}
);
}
myMeteredTool)。my_metered_tool_name)。meterEvent 以匹配你在Stripe meter中配置的事件名称。paymentReason 以向用户清楚解释计量计费。src/tools/index.ts:// 与其他导出一起添加此行
export * from './myMeteredTool';
src/index.ts 中注册你的工具:// 在init()方法内添加:
tools.myMeteredTool(this, {
STRIPE_METERED_PRICE_ID: this.env.STRIPE_METERED_PRICE_ID, // 确保这与你的计量价格ID匹配
BASE_URL: this.env.BASE_URL
});
如果你想向用户收取一次性费用以访问某个工具,而不是定期订阅或基于使用量计费,此选项很合适。
Stripe一次性支付设置
price_xxxxxxxxxxxxxx)。这是你将用于新环境变量(例如 STRIPE_ONE_TIME_PRICE_ID)的ID。工具实现
src/tools 文件夹中创建一个新文件(例如:myOnetimeTool.ts)。onetimeAdd.ts 示例启发的模板:import { z } from "zod";
import { experimental_PaidMcpAgent as PaidMcpAgent } from "@stripe/agent - toolkit/cloudflare";
import { REUSABLE_PAYMENT_REASON } from "../helpers/constants"; // 或更具体的原因
export function myOnetimeTool(
agent: PaidMcpAgent<Env, any, any>, // 根据需要调整AgentProps
env?: { STRIPE_ONE_TIME_PRICE_ID: string; BASE_URL: string }
) {
const priceId = env?.STRIPE_ONE_TIME_PRICE_ID || null;
const baseUrl = env?.BASE_URL || null;
if (!priceId || !baseUrl) {
throw new Error("Stripe One - Time Price ID and Base URL must be provided for this tool");
}
agent.paidTool(
"my_onetime_tool_name", // 工具名称
{
// 输入参数
input1: z.string(), // 使用Zod定义参数
},
async ({ input1 }: { input1: string }) => ({
// 工具调用时运行的函数
content: [
{ type: "text", text: `You processed: ${input1}` },
],
}),
{
checkout: { // 定义一次性支付结账会话
success_url: `${baseUrl}/payment/success`,
line_items: [
{
price: priceId, // 使用Stripe一次性支付产品的价格ID
quantity: 1,
},
],
mode: 'payment', // 指定这是一次性支付,不是订阅
},
paymentReason: "Enter a clear reason for this one - time charge. E.g., 'Unlock premium feature X for a single use.'", // 自定义此消息
}
);
}
myOnetimeTool)。my_onetime_tool_name)。checkout.mode 设置为 'payment'。paymentReason 以向用户清楚解释一次性收费。src/tools/index.ts:// 与其他导出一起添加此行
export * from './myOnetimeTool';
src/index.ts 中注册你的工具:// 在init()方法内添加:
tools.myOnetimeTool(this, {
STRIPE_ONE_TIME_PRICE_ID: this.env.STRIPE_ONE_TIME_PRICE_ID, // 确保这与你的一次性支付价格ID匹配
BASE_URL: this.env.BASE_URL
});
STRIPE_ONE_TIME_PRICE_ID 添加到你的 .dev.vars 文件和Cloudflare秘密中:
在 .dev.vars 中:STRIPE_ONE_TIME_PRICE_ID="price_your - onetime - price - id - here"
对于生产环境:
npx wrangler secret put STRIPE_ONE_TIME_PRICE_ID
你可以通过在Stripe仪表板中创建额外的价格ID并将它们作为环境变量传递,来使用不同的Stripe产品(订阅或计量)创建不同的付费工具。
当用户尝试访问未购买的付费工具时:
本项目基于 @iannuttall 的开源MCP模板构建,具备用户认证、支付处理等功能,并通过Municode API与市政建筑规范集成。在开发过程中,运用了Zod进行参数验证,确保输入数据的准确性;对于不同类型的付费工具,在Stripe中进行了相应的设置,以实现订阅、计量和一次性支付的功能。同时,项目在处理用户请求时,会根据规范层级考虑不同规范的优先级,确保提供的建议符合最严格的要求。
文档未提及相关许可证信息。
上述基本设置足以让你开始使用。内置的Stripe集成在用户尝试访问付费工具时会直接验证支付,自动检查一次性支付和订阅情况。 Webhooks是完全可选的,但在未来更复杂的支付场景中可能会有用,例如:
http://localhost:8787/webhooks/stripe。https://your - worker - name.your - account.workers.dev/webhooks/stripe。.dev.vars:STRIPE_WEBHOOK_SECRET="whsec_your - webhook - secret - here"
npx wrangler secret put STRIPE_WEBHOOK_SECRET
如果你遇到任何错误或在使用模板时遇到问题,请在GitHub仓库上提交一个issue。请注意,此项目按原样提供,不提供直接支持。