🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@msgmesh/mcp-server

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@msgmesh/mcp-server - npm Package Compare versions

Comparing version
0.1.3
to
0.1.4
+237
-43
dist/index.js
#!/usr/bin/env node
// src/index.ts
import { createRequire } from "module";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

@@ -10,2 +11,70 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

// src/handlers.ts
import { MsgMeshError } from "@msgmesh/sdk";
// src/config.ts
var HOSTED_API_URL = "https://msgmesh-api.alderflux.com";
var PANEL_URL = "https://msgmesh-panel.alderflux.com";
var ENV = {
apiKey: "MQ_API_KEY",
controlPlaneUrl: "MQ_CONTROL_PLANE_URL",
gatewayUrl: "MQ_GATEWAY_URL",
realtimeUrl: "MQ_REALTIME_URL"
};
var KEY_PLACEHOLDER = "<\u4F60\u7684 API Key>";
var PLACEHOLDER_PATTERNS = [
/^<[\s\S]*>$/,
// <你的 API Key>(packages/shared-go/snippet 產生的接入片段用這個)
/^\{\{[\s\S]*\}\}$/,
// {{API_KEY}} 之類的模板語法沒被渲染
/^\$\{?[A-Za-z_][A-Za-z0-9_]*\}?$/,
// $MQ_API_KEY / ${MQ_API_KEY}:client 不做 shell 展開時會原樣傳入
/^mk_x+$/i,
// mk_xxxxxxxx(真 key 的 hex 段不含 x → 不會誤擋)
/^x+$/i,
// xxxxxxxx
/your[\s_-]*api[\s_-]*key/i,
// YOUR_API_KEY / your-api-key / Your API Key
/(你的|換成|請填|填入|替換|貼上)/
// 中文範本語句,如「把這裡換成你的 API Key」
];
function isPlaceholder(v) {
return PLACEHOLDER_PATTERNS.some((re) => re.test(v));
}
function envValue(env, name) {
return (env[name] ?? "").trim();
}
var HOW_TO_GET_KEY = `\u8ACB\u5230\u9762\u677F ${PANEL_URL} \u7684 Keys \u9801\u7C3D\u767C\u4E00\u628A API Key(MCP \u591A\u6578 tool \u5C6C\u6CBB\u7406\u985E\u3001\u9700 admin scope)`;
var CONFIG_EXAMPLE = `\u8A2D\u5B9A\u7BC4\u4F8B:"env": { "${ENV.apiKey}": "${KEY_PLACEHOLDER}" }(\u89D2\u62EC\u865F\u9023\u540C\u88E1\u9762\u7684\u5B57\u4E00\u8D77\u63DB\u6210\u9762\u677F\u7C3D\u51FA\u7684\u5B8C\u6574 key)\u2014\u2014${ENV.controlPlaneUrl} / ${ENV.gatewayUrl} / ${ENV.realtimeUrl} \u672A\u8A2D\u6642\u9810\u8A2D ${HOSTED_API_URL},\u81EA\u67B6\u624D\u9700\u8986\u5BEB\u3002`;
function resolveConfig(env) {
const apiKey = envValue(env, ENV.apiKey);
if (apiKey === "") {
return {
ok: false,
lines: [
`MsgMesh MCP server \u7121\u6CD5\u555F\u52D5:\u74B0\u5883\u8B8A\u6578 ${ENV.apiKey} \u672A\u8A2D\u5B9A\u3002${HOW_TO_GET_KEY},\u586B\u9032 MCP \u8A2D\u5B9A\u7684 env.${ENV.apiKey} \u5F8C\u91CD\u555F\u3002`,
CONFIG_EXAMPLE
]
};
}
if (isPlaceholder(apiKey)) {
return {
ok: false,
lines: [
`MsgMesh MCP server \u7121\u6CD5\u555F\u52D5:\u74B0\u5883\u8B8A\u6578 ${ENV.apiKey} \u9084\u662F\u8A2D\u5B9A\u7BC4\u672C\u7684\u4F54\u4F4D\u5B57\u4E32\u300C${apiKey}\u300D,\u5C1A\u672A\u63DB\u6210\u771F\u7684 key\u3002${HOW_TO_GET_KEY},\u586B\u9032 MCP \u8A2D\u5B9A\u7684 env.${ENV.apiKey} \u5F8C\u91CD\u555F\u3002`,
CONFIG_EXAMPLE
]
};
}
return {
ok: true,
config: {
apiKey,
controlPlaneUrl: envValue(env, ENV.controlPlaneUrl) || HOSTED_API_URL,
gatewayUrl: envValue(env, ENV.gatewayUrl) || HOSTED_API_URL,
realtimeUrl: envValue(env, ENV.realtimeUrl) || HOSTED_API_URL
}
};
}
// src/handlers.ts
function buildHandlers(mq2) {

@@ -133,16 +202,101 @@ return {

}
var HINT_401 = `\u2192 \u4E0B\u4E00\u6B65:${ENV.apiKey} \u7121\u6548\u6216\u5DF2\u64A4\u92B7\u3002\u5230\u9762\u677F ${PANEL_URL} \u7684 Keys \u9801\u91CD\u7C3D\u4E00\u628A,\u66F4\u65B0 MCP \u8A2D\u5B9A\u88E1\u7684 ${ENV.apiKey} \u5F8C\u91CD\u555F\u9019\u500B MCP server\u3002`;
var HINT_403 = `\u2192 \u4E0B\u4E00\u6B65:\u9019\u628A ${ENV.apiKey} \u6B0A\u9650\u4E0D\u8DB3\u3002MCP \u7684\u6CBB\u7406\u985E tool(topic / key / schema / webhook / function / \u65B9\u6848 / \u7A3D\u6838)\u9700 **admin** scope,\u8CC7\u6599\u9762(publish / consume)\u5247\u9700\u5C0D\u61C9 topic \u7684\u80FD\u529B\u3002\u8ACB\u5230\u9762\u677F ${PANEL_URL} \u7684 Keys \u9801\u7C3D\u4E00\u628A admin key \u63DB\u6389 ${ENV.apiKey}\u2014\u2014\u4E0D\u8981\u6539\u7528 create_key \u81EA\u52A9\u958B\u901A,\u5B83\u672C\u8EAB\u4E5F\u8981 admin,\u53EA\u6703\u518D\u88AB\u64CB\u4E00\u6B21\u3002`;
function httpStatusOf(err) {
if (err instanceof MsgMeshError) return err.status;
if (typeof err === "object" && err !== null) {
const e = err;
const shaped = typeof e.status === "number" && typeof e.code === "string" && typeof e.path === "string" && typeof e.name === "string" && e.name.endsWith("Error");
if (shaped) return e.status;
}
return void 0;
}
function withHint(err, hint) {
const copy = Object.create(Object.getPrototypeOf(err));
Object.assign(copy, err);
copy.message = `${err.message}
${hint}`;
copy.name = err.name;
if (typeof err.stack === "string") copy.stack = err.stack.replace(err.message, () => copy.message);
copy.cause = err;
return copy;
}
function mapError(err) {
const status = httpStatusOf(err);
const hint = status === 401 ? HINT_401 : status === 403 ? HINT_403 : void 0;
if (!hint || !(err instanceof Error)) return err;
return withHint(err, hint);
}
function withMappedError(h2) {
const src = h2;
const out = {};
for (const name of Object.keys(src)) {
const fn = src[name];
out[name] = async (...args) => {
try {
return await fn.apply(src, args);
} catch (err) {
throw mapError(err);
}
};
}
return out;
}
// src/index.ts
var mq = new MsgMesh({
apiKey: process.env.MQ_API_KEY ?? "",
controlPlaneUrl: process.env.MQ_CONTROL_PLANE_URL,
gatewayUrl: process.env.MQ_GATEWAY_URL,
realtimeUrl: process.env.MQ_REALTIME_URL
});
var h = buildHandlers(mq);
var requireFromHere = createRequire(import.meta.url);
var { version: SERVER_VERSION } = requireFromHere("../package.json");
var resolved = resolveConfig(process.env);
if (!resolved.ok) {
for (const line of resolved.lines) console.error(line);
process.exit(1);
}
var mq;
try {
mq = new MsgMesh({
apiKey: resolved.config.apiKey,
controlPlaneUrl: resolved.config.controlPlaneUrl,
gatewayUrl: resolved.config.gatewayUrl,
realtimeUrl: resolved.config.realtimeUrl
});
} catch (err) {
console.error(
`MsgMesh MCP server \u7121\u6CD5\u555F\u52D5:\u5EFA\u7ACB SDK \u9023\u7DDA\u8A2D\u5B9A\u5931\u6557(${err instanceof Error ? err.message : String(err)})\u3002\u8ACB\u6AA2\u67E5 MCP \u8A2D\u5B9A\u88E1\u7684 ${ENV.apiKey} \u8207 ${ENV.controlPlaneUrl} / ${ENV.gatewayUrl} / ${ENV.realtimeUrl}\u3002`
);
process.exit(1);
}
var h = withMappedError(buildHandlers(mq));
var text = (s) => ({ content: [{ type: "text", text: s }] });
var server = new McpServer({ name: "msgmesh", version: "0.1.0" });
var READ_ONLY = { readOnlyHint: true, openWorldHint: false };
var ADDITIVE = { readOnlyHint: false, destructiveHint: false, openWorldHint: false };
var MUTATING = { readOnlyHint: false, destructiveHint: true, openWorldHint: false };
var INSTRUCTIONS = [
"MsgMesh \u662F\u67B6\u5728 Kafka \u4E4B\u4E0A\u7684\u591A\u79DF\u6236\u4E8B\u4EF6\u7E3D\u7DDA(topic / \u8A0A\u606F / schema / webhook / DLQ)\u3002",
"\u9019\u500B server \u8B93\u4F60\u76F4\u63A5\u6536\u767C\u4E8B\u4EF6\u4E26\u76E3\u770B\u4E8B\u4EF6\u6D41,\u4E0D\u5FC5\u81EA\u5DF1\u5BEB\u4E00\u5C64\u4E8B\u4EF6\u6A4B\u3002",
"",
"\u5EFA\u8B70\u6D41\u7A0B:",
"1. \u5148\u547C\u53EB get_plan \u9A57\u8B49\u6191\u8B49\u2014\u2014\u6210\u529F\u4EE3\u8868 MQ_API_KEY \u6709\u6548\u4E14\u5177 admin scope;401=key \u7121\u6548\u3001403=scope \u4E0D\u8DB3\u3002",
"2. create_topic \u5EFA\u7ACB topic,\u518D\u7528 publish_message \u767C\u4E8B\u4EF6(message \u53EF\u70BA\u4EFB\u610F JSON)\u3002",
"3. \u76E3\u770B\u4E8B\u4EF6\u7528 watch_topic:\u9577\u8F2A\u8A62\u7B49\u4E0B\u4E00\u6279,\u6536\u5230\u5C31\u8655\u7406\u3001\u518D\u4EE5**\u540C\u4E00\u500B group** \u547C\u53EB\u7E7C\u7E8C\u7B49\u4E0B\u4E00\u6279\u3002",
" consume_messages \u5247\u662F\u300C\u6709\u5C31\u56DE\u3001\u6C92\u6709\u5373\u56DE\u7A7A\u300D,\u9069\u5408\u4E00\u6B21\u6027\u53D6\u7528\u3002",
"",
"\u6CE8\u610F:",
"- \u6CBB\u7406\u985E tool(topic / key / schema / webhook / function / \u65B9\u6848 / \u7A3D\u6838 / \u7528\u91CF)\u9700 **admin** scope \u7684 key;",
" \u8CC7\u6599\u9762(publish / consume / watch / presence / DLQ)\u53E6\u9700\u8A72 topic \u7684\u5C0D\u61C9\u80FD\u529B\u3002",
"- consume_messages / watch_topic / dlq_peek \u6703\u63A8\u9032 consumer group \u4F4D\u79FB(at-most-once):",
" \u540C\u4E00\u6279\u8A0A\u606F\u4E0D\u6703\u518D\u9001\u7B2C\u4E8C\u6B21,\u5225\u7576\u6210\u7121\u526F\u4F5C\u7528\u7684\u67E5\u8A62\u53CD\u8986\u547C\u53EB\u3002",
`- \u9047\u5230 401 / 403 \u4E0D\u8981\u5617\u8A66\u7528 create_key \u81EA\u52A9\u958B\u901A(\u5B83\u672C\u8EAB\u4E5F\u9700 admin,\u53EA\u6703\u518D\u88AB\u64CB);`,
` \u8ACB\u544A\u8A34\u4F7F\u7528\u8005\u5230\u9762\u677F ${PANEL_URL} \u7684 Keys \u9801\u91CD\u7C3D,\u4E26\u66F4\u65B0 MCP \u8A2D\u5B9A\u88E1\u7684 ${ENV.apiKey} \u5F8C\u91CD\u555F\u3002`
].join("\n");
var server = new McpServer(
{ name: "msgmesh", version: SERVER_VERSION },
{ instructions: INSTRUCTIONS }
);
server.registerTool(
"create_topic",
{ description: "\u5EFA\u7ACB\u4E00\u500B\u4E8B\u4EF6 topic", inputSchema: { name: z.string(), partitions: z.number().optional() } },
{
description: "\u5EFA\u7ACB\u4E00\u500B\u4E8B\u4EF6 topic",
inputSchema: { name: z.string(), partitions: z.number().optional() },
annotations: ADDITIVE
},
async (args) => text(await h.createTopic(args))

@@ -152,3 +306,3 @@ );

"list_topics",
{ description: "\u5217\u51FA\u76EE\u524D\u6240\u6709 topic", inputSchema: {} },
{ description: "\u5217\u51FA\u76EE\u524D\u6240\u6709 topic", inputSchema: {}, annotations: READ_ONLY },
async () => text(await h.listTopics())

@@ -158,3 +312,7 @@ );

"delete_topic",
{ description: "\u522A\u9664\u6307\u5B9A topic", inputSchema: { name: z.string() } },
{
description: "\u522A\u9664\u6307\u5B9A topic\u3002**\u4E0D\u53EF\u9006**:\u8A72 topic \u7684\u6240\u6709\u8A0A\u606F\u3001\u6B7B\u4FE1\u4F47\u5217\u3001schema\u3001\u51FD\u6578\u8207 webhook \u7D81\u5B9A\u6703\u7ACB\u5373\u88AB\u6E05\u9664,\u540C\u540D\u91CD\u5EFA\u53EA\u6703\u5F97\u5230\u4E00\u500B\u5168\u65B0\u7684\u7A7A topic\u3002\u522A\u9664\u524D\u8ACB\u5148\u5411\u4F7F\u7528\u8005\u78BA\u8A8D\u3002",
inputSchema: { name: z.string() },
annotations: MUTATING
},
async (args) => text(await h.deleteTopic(args))

@@ -166,3 +324,4 @@ );

description: "\u767C\u9001\u4E00\u5247\u8A0A\u606F\u5230\u6307\u5B9A topic(\u53EF\u9078 key \u505A\u5206\u5340\u8DEF\u7531)",
inputSchema: { topic: z.string(), message: z.unknown(), key: z.string().optional() }
inputSchema: { topic: z.string(), message: z.unknown(), key: z.string().optional() },
annotations: ADDITIVE
},

@@ -174,4 +333,5 @@ async (args) => text(await h.publishMessage(args))

{
description: "\u5F9E\u6307\u5B9A topic \u62C9\u53D6\u8A0A\u606F(\u53EF\u6307\u5B9A consumer group \u8207\u6700\u5927\u7B46\u6578)",
inputSchema: { topic: z.string(), group: z.string().optional(), max: z.number().optional() }
description: "\u5F9E\u6307\u5B9A topic \u62C9\u53D6\u8A0A\u606F(\u53EF\u6307\u5B9A consumer group \u8207\u6700\u5927\u7B46\u6578)\u3002\u26A0\uFE0F \u6703\u63D0\u4EA4 consumer group \u4F4D\u79FB(at-most-once):\u53D6\u56DE\u7684\u8A0A\u606F\u4E0D\u6703\u518D\u9001\u7B2C\u4E8C\u6B21,\u4E0D\u662F\u552F\u8B80\u67E5\u8A62\u3002",
inputSchema: { topic: z.string(), group: z.string().optional(), max: z.number().optional() },
annotations: MUTATING
},

@@ -183,4 +343,5 @@ async (args) => text(await h.consumeMessages(args))

{
description: "\u8A02\u95B1\u4E26\u300E\u7B49\u5F85\u300F\u67D0 topic \u7684\u4E0B\u4E00\u6279\u4E8B\u4EF6:\u9577\u8F2A\u8A62\u5230\u6709\u4E8B\u4EF6\u624D\u56DE(\u6216\u7B49\u5F85\u8996\u7A97\u903E\u6642\u56DE\u7A7A+\u63D0\u793A\u518D\u547C\u53EB)\u3002\u9069\u5408 AI agent \u76E3\u770B\u4E8B\u4EF6\u6D41\u2014\u2014\u6536\u5230\u5F8C\u8655\u7406\u3001\u518D\u6B21\u4EE5\u540C\u4E00 group \u547C\u53EB\u5373\u53EF\u7E7C\u7E8C\u7B49\u4E0B\u4E00\u6279\u3002\u8207 consume_messages(\u6709\u5C31\u56DE\u3001\u6C92\u6709\u5373\u56DE\u7A7A)\u4E0D\u540C\u3002maxWaitSec \u9810\u8A2D 25\u3001\u4E0A\u9650 55\u3002",
inputSchema: { topic: z.string(), group: z.string().optional(), maxWaitSec: z.number().optional() }
description: "\u8A02\u95B1\u4E26\u300E\u7B49\u5F85\u300F\u67D0 topic \u7684\u4E0B\u4E00\u6279\u4E8B\u4EF6:\u9577\u8F2A\u8A62\u5230\u6709\u4E8B\u4EF6\u624D\u56DE(\u6216\u7B49\u5F85\u8996\u7A97\u903E\u6642\u56DE\u7A7A+\u63D0\u793A\u518D\u547C\u53EB)\u3002\u9069\u5408 AI agent \u76E3\u770B\u4E8B\u4EF6\u6D41\u2014\u2014\u6536\u5230\u5F8C\u8655\u7406\u3001\u518D\u6B21\u4EE5\u540C\u4E00 group \u547C\u53EB\u5373\u53EF\u7E7C\u7E8C\u7B49\u4E0B\u4E00\u6279\u3002\u8207 consume_messages(\u6709\u5C31\u56DE\u3001\u6C92\u6709\u5373\u56DE\u7A7A)\u4E0D\u540C\u3002maxWaitSec \u9810\u8A2D 25\u3001\u4E0A\u9650 55\u3002\u26A0\uFE0F \u540C\u6A23\u6703\u63D0\u4EA4 consumer group \u4F4D\u79FB(at-most-once),\u4E0D\u662F\u552F\u8B80\u67E5\u8A62\u3002",
inputSchema: { topic: z.string(), group: z.string().optional(), maxWaitSec: z.number().optional() },
annotations: MUTATING
},

@@ -192,4 +353,5 @@ async (args) => text(await h.watchEvents(args))

{
description: "\u70BA topic \u8A3B\u518A JSON Schema(compatibility:none/backward)",
inputSchema: { topic: z.string(), schema: z.unknown(), compatibility: z.string().optional() }
description: "\u70BA topic \u8A3B\u518A JSON Schema(compatibility:none/backward)\u3002\u6BCF\u6B21\u547C\u53EB\u90FD\u6703\u65B0\u589E\u4E00\u500B\u7248\u672C(\u975E\u51AA\u7B49)",
inputSchema: { topic: z.string(), schema: z.unknown(), compatibility: z.string().optional() },
annotations: ADDITIVE
},

@@ -200,3 +362,3 @@ async (args) => text(await h.registerSchema(args))

"get_schema",
{ description: "\u53D6\u5F97 topic \u6700\u65B0\u7248\u672C\u7684 schema", inputSchema: { topic: z.string() } },
{ description: "\u53D6\u5F97 topic \u6700\u65B0\u7248\u672C\u7684 schema", inputSchema: { topic: z.string() }, annotations: READ_ONLY },
async (args) => text(await h.getSchema(args))

@@ -206,3 +368,3 @@ );

"list_schemas",
{ description: "\u5217\u51FA topic \u6240\u6709 schema \u7248\u672C", inputSchema: { topic: z.string() } },
{ description: "\u5217\u51FA topic \u6240\u6709 schema \u7248\u672C", inputSchema: { topic: z.string() }, annotations: READ_ONLY },
async (args) => text(await h.listSchemas(args))

@@ -214,3 +376,4 @@ );

description: "\u522A\u9664 topic \u7684\u6307\u5B9A schema \u7248\u672C(\u4E0D\u53EF\u522A\u6700\u65B0\u7248,\u5426\u5247\u56DE 409)",
inputSchema: { topic: z.string(), version: z.number() }
inputSchema: { topic: z.string(), version: z.number() },
annotations: MUTATING
},

@@ -223,3 +386,4 @@ async (args) => text(await h.deleteSchema(args))

description: "\u5EFA\u7ACB webhook:topic \u6709\u65B0\u8A0A\u606F\u6642 POST \u5230\u6307\u5B9A URL(\u53EF\u9078 secret \u505A HMAC \u7C3D\u7AE0)",
inputSchema: { topic: z.string(), url: z.string(), secret: z.string().optional() }
inputSchema: { topic: z.string(), url: z.string(), secret: z.string().optional() },
annotations: ADDITIVE
},

@@ -230,3 +394,3 @@ async (args) => text(await h.createWebhook(args))

"list_webhooks",
{ description: "\u5217\u51FA\u76EE\u524D\u6240\u6709 webhook", inputSchema: {} },
{ description: "\u5217\u51FA\u76EE\u524D\u6240\u6709 webhook", inputSchema: {}, annotations: READ_ONLY },
async () => text(await h.listWebhooks())

@@ -236,3 +400,3 @@ );

"delete_webhook",
{ description: "\u522A\u9664\u6307\u5B9A webhook(\u4EE5 id)", inputSchema: { id: z.string() } },
{ description: "\u522A\u9664\u6307\u5B9A webhook(\u4EE5 id)", inputSchema: { id: z.string() }, annotations: MUTATING },
async (args) => text(await h.deleteWebhook(args))

@@ -243,4 +407,7 @@ );

{
description: "\u70BA topic \u8A3B\u518A\u8A0A\u606F\u8F49\u63DB\u51FD\u6578(\u8A0A\u606F\u9032\u5165\u6642\u57F7\u884C)\u3002language \u9810\u8A2D javascript(JS \u7A0B\u5F0F\u78BC);\u50B3 wasm \u5247 code \u9808\u70BA base64 \u7DE8\u78BC\u7684 WASI \u6A21\u7D44(\u8B80 stdin JSON\u3001\u5BEB stdout JSON)",
inputSchema: { topic: z.string(), code: z.string(), language: z.string().optional() }
description: "\u70BA topic \u8A3B\u518A\u8A0A\u606F\u8F49\u63DB\u51FD\u6578(\u8A0A\u606F\u9032\u5165\u6642\u57F7\u884C)\u3002language \u9810\u8A2D javascript(JS \u7A0B\u5F0F\u78BC);\u50B3 wasm \u5247 code \u9808\u70BA base64 \u7DE8\u78BC\u7684 WASI \u6A21\u7D44(\u8B80 stdin JSON\u3001\u5BEB stdout JSON)\u3002\u26A0\uFE0F \u540C\u4E00 topic \u53EA\u6709\u4E00\u500B\u51FD\u6578:\u91CD\u8907\u8A3B\u518A\u6703**\u8986\u5BEB**\u65E2\u6709\u7684,\u820A\u7A0B\u5F0F\u78BC\u4E0D\u4FDD\u7559\u3002",
inputSchema: { topic: z.string(), code: z.string(), language: z.string().optional() },
// 與其他 register_* 不同:store.UpsertFunction 是 ON CONFLICT DO UPDATE(覆寫既有函數),
// 不是新增一個版本,故標 MUTATING 而非 ADDITIVE。
annotations: MUTATING
},

@@ -251,3 +418,3 @@ async (args) => text(await h.registerFunction(args))

"get_function",
{ description: "\u53D6\u5F97 topic \u7D81\u5B9A\u7684\u8A0A\u606F\u8F49\u63DB\u51FD\u6578", inputSchema: { topic: z.string() } },
{ description: "\u53D6\u5F97 topic \u7D81\u5B9A\u7684\u8A0A\u606F\u8F49\u63DB\u51FD\u6578", inputSchema: { topic: z.string() }, annotations: READ_ONLY },
async (args) => text(await h.getFunction(args))

@@ -257,3 +424,3 @@ );

"delete_function",
{ description: "\u522A\u9664 topic \u7D81\u5B9A\u7684\u8A0A\u606F\u8F49\u63DB\u51FD\u6578", inputSchema: { topic: z.string() } },
{ description: "\u522A\u9664 topic \u7D81\u5B9A\u7684\u8A0A\u606F\u8F49\u63DB\u51FD\u6578", inputSchema: { topic: z.string() }, annotations: MUTATING },
async (args) => text(await h.deleteFunction(args))

@@ -263,3 +430,7 @@ );

"list_keys",
{ description: "\u5217\u51FA\u76EE\u524D\u6240\u6709 API key(\u50C5 prefix,\u4E0D\u542B\u5B8C\u6574 key)", inputSchema: {} },
{
description: "\u5217\u51FA\u76EE\u524D\u6240\u6709 API key(\u50C5 prefix,\u4E0D\u542B\u5B8C\u6574 key)",
inputSchema: {},
annotations: READ_ONLY
},
async () => text(await h.listKeys())

@@ -270,3 +441,3 @@ );

{
description: '\u5EFA\u7ACB\u65B0\u7684 API key\u3002scope:admin|producer|consumer\u3002\u53EF\u9078 capabilities \u505A\u7D30\u7C92\u5EA6\u6388\u6B0A(scope \u9808 producer/consumer):[{ops:["publish"|"subscribe"],topics:["orders","support*","*"]}]',
description: '\u5EFA\u7ACB\u65B0\u7684 API key(\u672C\u8EAB\u9700 admin scope,\u6B0A\u9650\u4E0D\u8DB3\u6642\u4E0D\u8981\u7528\u5B83\u81EA\u52A9\u958B\u901A)\u3002scope:admin|producer|consumer\u3002\u53EF\u9078 capabilities \u505A\u7D30\u7C92\u5EA6\u6388\u6B0A(scope \u9808 producer/consumer):[{ops:["publish"|"subscribe"],topics:["orders","support*","*"]}]',
inputSchema: {

@@ -276,3 +447,4 @@ scope: z.string(),

capabilities: z.array(z.object({ ops: z.array(z.string()), topics: z.array(z.string()) })).optional()
}
},
annotations: ADDITIVE
},

@@ -283,3 +455,3 @@ async (args) => text(await h.createKey(args))

"delete_key",
{ description: "\u522A\u9664\u6307\u5B9A API key(\u4EE5 id)", inputSchema: { id: z.string() } },
{ description: "\u522A\u9664\u6307\u5B9A API key(\u4EE5 id)", inputSchema: { id: z.string() }, annotations: MUTATING },
async (args) => text(await h.deleteKey(args))

@@ -289,3 +461,7 @@ );

"get_plan",
{ description: "\u67E5\u8A62\u76EE\u524D\u65B9\u6848\u8207\u914D\u984D\u9650\u5236", inputSchema: {} },
{
description: "\u67E5\u8A62\u76EE\u524D\u65B9\u6848\u8207\u914D\u984D\u9650\u5236(\u4E5F\u662F\u6700\u8F15\u91CF\u7684\u6191\u8B49\u6AA2\u67E5:\u6210\u529F=key \u6709\u6548\u4E14\u5177 admin scope)",
inputSchema: {},
annotations: READ_ONLY
},
async () => text(await h.getPlan())

@@ -295,3 +471,3 @@ );

"set_plan",
{ description: "\u5207\u63DB\u65B9\u6848(free/pro/team)", inputSchema: { plan: z.string() } },
{ description: "\u5207\u63DB\u65B9\u6848(free/pro/team)", inputSchema: { plan: z.string() }, annotations: MUTATING },
async (args) => text(await h.setPlan(args))

@@ -301,3 +477,7 @@ );

"get_billing",
{ description: "\u67E5\u8A62\u9918\u984D/\u8A08\u8CBB\u72C0\u614B/\u7E8C\u822A\u5929\u6578(PAYG \u9810\u4ED8\u5E33\u672C)", inputSchema: {} },
{
description: "\u67E5\u8A62\u9918\u984D/\u8A08\u8CBB\u72C0\u614B/\u7E8C\u822A\u5929\u6578(PAYG \u9810\u4ED8\u5E33\u672C)",
inputSchema: {},
annotations: READ_ONLY
},
async () => text(await h.getBilling())

@@ -307,3 +487,7 @@ );

"get_audit",
{ description: "\u67E5\u8A62\u64CD\u4F5C\u5BE9\u8A08\u7D00\u9304(\u53EF\u6307\u5B9A\u7B46\u6578\u4E0A\u9650)", inputSchema: { limit: z.number().optional() } },
{
description: "\u67E5\u8A62\u64CD\u4F5C\u5BE9\u8A08\u7D00\u9304(\u53EF\u6307\u5B9A\u7B46\u6578\u4E0A\u9650)",
inputSchema: { limit: z.number().optional() },
annotations: READ_ONLY
},
async (args) => text(await h.getAudit(args))

@@ -314,4 +498,5 @@ );

{
description: "\u67E5\u770B topic \u7684\u6B7B\u4FE1\u4F47\u5217(DLQ)\u8A0A\u606F,\u4E0D\u5F71\u97FF\u5F8C\u7E8C\u91CD\u653E",
inputSchema: { topic: z.string(), group: z.string().optional(), max: z.number().optional() }
description: "\u67E5\u770B topic \u7684\u6B7B\u4FE1\u4F47\u5217(DLQ)\u8A0A\u606F\u3002\u26A0\uFE0F \u5E95\u5C64\u8D70 committing poll:\u6703\u63D0\u4EA4 DLQ consumer group \u4F4D\u79FB,\u770B\u904E\u7684\u8A0A\u606F\u4E0D\u6703\u518D\u56DE\u4E00\u6B21,\u4E0D\u662F\u552F\u8B80\u67E5\u8A62(\u8981\u628A\u6B7B\u4FE1\u653E\u56DE\u4E3B topic \u8ACB\u7528 dlq_replay)",
inputSchema: { topic: z.string(), group: z.string().optional(), max: z.number().optional() },
annotations: MUTATING
},

@@ -324,3 +509,4 @@ async (args) => text(await h.dlqPeek(args))

description: "\u5C07 topic \u6B7B\u4FE1\u4F47\u5217(DLQ)\u8A0A\u606F\u91CD\u653E\u56DE\u539F topic(\u53EF\u9650\u5236\u7B46\u6578)",
inputSchema: { topic: z.string(), max: z.number().optional() }
inputSchema: { topic: z.string(), max: z.number().optional() },
annotations: MUTATING
},

@@ -331,3 +517,7 @@ async (args) => text(await h.dlqReplay(args))

"get_presence",
{ description: "\u67E5\u8A62 topic \u76EE\u524D\u7DDA\u4E0A\u9023\u7DDA\u6578(realtime \u670D\u52D9)", inputSchema: { topic: z.string() } },
{
description: "\u67E5\u8A62 topic \u76EE\u524D\u7DDA\u4E0A\u9023\u7DDA\u6578(realtime \u670D\u52D9)",
inputSchema: { topic: z.string() },
annotations: READ_ONLY
},
async (args) => text(await h.getPresence(args))

@@ -337,3 +527,3 @@ );

"get_docs",
{ description: "\u53D6\u5F97\u7531\u79DF\u6236 topics+schema \u751F\u6210\u7684 Markdown \u4F7F\u7528\u6587\u4EF6", inputSchema: {} },
{ description: "\u53D6\u5F97\u7531\u79DF\u6236 topics+schema \u751F\u6210\u7684 Markdown \u4F7F\u7528\u6587\u4EF6", inputSchema: {}, annotations: READ_ONLY },
async () => text(await h.getDocs())

@@ -343,3 +533,3 @@ );

"get_connection_snippet",
{ description: "\u53D6\u5F97\u53EF\u8CBC\u7D66 AI \u7684\u63A5\u5165\u63D0\u793A", inputSchema: {} },
{ description: "\u53D6\u5F97\u53EF\u8CBC\u7D66 AI \u7684\u63A5\u5165\u63D0\u793A", inputSchema: {}, annotations: READ_ONLY },
async () => text(await h.getConnectionSnippet())

@@ -349,3 +539,7 @@ );

"get_usage",
{ description: "\u67E5\u8A62\u79DF\u6236\u7528\u91CF(\u53EF\u6307\u5B9A\u65E5\u671F period=YYYY-MM-DD)", inputSchema: { period: z.string().optional() } },
{
description: "\u67E5\u8A62\u79DF\u6236\u7528\u91CF(\u53EF\u6307\u5B9A\u65E5\u671F period=YYYY-MM-DD)",
inputSchema: { period: z.string().optional() },
annotations: READ_ONLY
},
async (args) => text(await h.getUsage(args))

@@ -352,0 +546,0 @@ );

+3
-3
{
"name": "@msgmesh/mcp-server",
"version": "0.1.3",
"description": "MsgMesh MCP server — 讓 Claude / Cursor 等 AI agent 原生訂閱事件流(watch_topic)並自助開通(create_key / create_topic)。",
"version": "0.1.4",
"description": "MsgMesh MCP server — 讓 Claude / Cursor 等 AI agent 原生訂閱事件流(watch_topic)並管理 topic / schema / webhook。",
"license": "MIT",
"author": "LukeLogix",
"homepage": "https://msg.alderflux.com",
"homepage": "https://msgmesh.alderflux.com",
"repository": {

@@ -9,0 +9,0 @@ "type": "git",

+41
-15

@@ -5,4 +5,4 @@ # @msgmesh/mcp-server

[MsgMesh](https://msg.alderflux.com) 是架在 Kafka 之上的多租戶事件總線。把這個 MCP server 加進
Claude Desktop / Cursor,agent 就能用自然語言收發事件、監看 topic、甚至自己開通金鑰——
[MsgMesh](https://msgmesh.alderflux.com) 是架在 Kafka 之上的多租戶事件總線。把這個 MCP server 加進
Claude Desktop / Cursor,agent 就能用自然語言收發事件、監看 topic、管理 topic 與 schema——
你不必為它寫一層事件橋。

@@ -27,5 +27,3 @@

"env": {
"MQ_API_KEY": "<你的 API Key>",
"MQ_CONTROL_PLANE_URL": "https://msgapi.alderflux.com",
"MQ_GATEWAY_URL": "https://msgapi.alderflux.com"
"MQ_API_KEY": "<你的 API Key>"
}

@@ -37,23 +35,47 @@ }

只需要一把 key:服務位址預設指向官方託管的 `https://msgmesh-api.alderflux.com`,自架才需覆寫(見下表)。
不需要事先安裝:`npx -y` 會在首次啟動時自動取得。
把 `<你的 API Key>` 連同角括號一起換成面板簽出的 key。沒填、或還留著佔位字串(`<...>`、
`YOUR_API_KEY`、`mk_xxxxxxxx`、`$MQ_API_KEY` 這類)時,server 會拒絕啟動並在 stderr 印出該
去哪拿 key——不會裝出「已連線」卻在第一次呼叫才吐 401。
### 還沒有 API Key?
[面板](https://msgpanel.alderflux.com)註冊後可簽發一把。或者——直接讓 agent 自己開通:
到[面板](https://msgmesh-panel.alderflux.com)註冊後,在 Keys 頁簽發一把。
**建議簽 `admin` scope**:29 個 tool 裡多數是治理類(topic / key / schema / webhook /
function / 方案 / 稽核 / 用量),後端要求 admin;`producer` / `consumer` key 只能用資料面
(`publish_message` / `consume_messages` / `watch_topic` / `get_presence` / DLQ)。
權限不足時後端回 403 —— 這時**不能**叫 agent 用 `create_key` 自己開通(簽發金鑰本身也需要
admin,只會再被擋一次),請到面板換一把。
拿到 key 之後,可以直接這樣用:
```
「用 create_key 建一把能 publish + subscribe 的 key,然後監看 support.tickets。」
「建一個 support.tickets topic,然後幫我監看它,有新工單就告訴我。」
```
agent 有 `create_key` / `create_topic` / `watch_topic`,會自我 bootstrap 後開始監看。
(自助開通需要一把有 `admin` scope 的 key;完全沒有 key 時請先到面板簽發。)
agent 會呼叫 `create_topic` → `watch_topic`,長輪詢等下一批事件。
## 環境變數
| 變數 | 說明 |
|---|---|
| `MQ_API_KEY` | API Key(必要)。 |
| `MQ_CONTROL_PLANE_URL` | 管理 API(建 topic / 簽 key / 查用量)。 |
| `MQ_GATEWAY_URL` | 收發 API(publish / consume)。 |
| 變數 | 說明 | 預設 |
|---|---|---|
| `MQ_API_KEY` | API Key(**必要**;缺少或仍是佔位字串則不啟動)。 | — |
| `MQ_CONTROL_PLANE_URL` | 管理 API(建 topic / 簽 key / 查用量)。 | `https://msgmesh-api.alderflux.com` |
| `MQ_GATEWAY_URL` | 收發 API(publish / consume / DLQ)。 | `https://msgmesh-api.alderflux.com` |
| `MQ_REALTIME_URL` | 即時服務(`get_presence` 用)。 | `https://msgmesh-api.alderflux.com` |
自架時三個 URL 各自指向你的服務,例如本機開發:
```json
"env": {
"MQ_API_KEY": "<你的 API Key>",
"MQ_CONTROL_PLANE_URL": "http://localhost:8080",
"MQ_GATEWAY_URL": "http://localhost:8081",
"MQ_REALTIME_URL": "http://localhost:8082"
}
```
## 工具

@@ -74,5 +96,9 @@

每個 tool 都帶 MCP `annotations`,client 可據此自動放行查詢、對會改動狀態的操作要求確認。
注意 `consume_messages` / `watch_topic` / `dlq_peek` **不是唯讀**:它們會提交 consumer group
位移(at-most-once),取回的訊息不會再送第二次。
## 相關
- API 參考(可線上試打):<https://msgapi.alderflux.com/docs>
- API 參考(可線上試打):<https://msgmesh-api.alderflux.com/docs>
- TypeScript SDK:[`@msgmesh/sdk`](https://www.npmjs.com/package/@msgmesh/sdk)

@@ -79,0 +105,0 @@