@costgate/momentum-mcp 0.1.33 → 0.1.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/momentum-mcp.mjs +90 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ MOMENTUM_TOKEN=mom_agent_xxx \
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
整条命令不用自己拼 —— 在 Momentum 的「设置 › Agent」里签发令牌时会直接给出,
|
|
12
|
-
默认用 `@latest`,发新版不用改配置;想固定某一版时把 latest 换成版本号(当前是 0.1.
|
|
12
|
+
默认用 `@latest`,发新版不用改配置;想固定某一版时把 latest 换成版本号(当前是 0.1.35)。
|
|
13
13
|
|
|
14
14
|
| 环境变量 | 必填 | 说明 |
|
|
15
15
|
|---|---|---|
|
|
@@ -18,4 +18,4 @@ MOMENTUM_TOKEN=mom_agent_xxx \
|
|
|
18
18
|
| `MOMENTUM_CF_ACCESS_CLIENT_ID` | 否 | 部署在 Cloudflare Access 后面时才需要 |
|
|
19
19
|
| `MOMENTUM_CF_ACCESS_CLIENT_SECRET` | 否 | 同上 |
|
|
20
20
|
|
|
21
|
-
版本 0.1.
|
|
21
|
+
版本 0.1.35。客户端和服务端版本不一致时,启动日志(stderr)会明确警告。
|
package/momentum-mcp.mjs
CHANGED
|
@@ -15339,7 +15339,7 @@ var allowErrorProps = SuperJSON.allowErrorProps;
|
|
|
15339
15339
|
|
|
15340
15340
|
// src/version.ts
|
|
15341
15341
|
var UNKNOWN = "unknown";
|
|
15342
|
-
var MCP_VERSION = true ? "0.1.
|
|
15342
|
+
var MCP_VERSION = true ? "0.1.35" : versionFromRepo();
|
|
15343
15343
|
var CLIENT_HEADER = `momentum-mcp/${MCP_VERSION}`;
|
|
15344
15344
|
function compareVersions(a, b) {
|
|
15345
15345
|
const parse4 = (v) => {
|
|
@@ -23621,6 +23621,12 @@ function hostUsageReader(env = process.env, opts = {}) {
|
|
|
23621
23621
|
const home = opts.home ?? homedir();
|
|
23622
23622
|
return async (runId, since) => {
|
|
23623
23623
|
try {
|
|
23624
|
+
const records = opts.reported?.since(since) ?? [];
|
|
23625
|
+
if (env.MOMENTUM_USAGE_FILE) {
|
|
23626
|
+
records.push(...parseHostReportFile(await readOptional(env.MOMENTUM_USAGE_FILE), since, opts.log));
|
|
23627
|
+
}
|
|
23628
|
+
const reported = sumHostReported(records);
|
|
23629
|
+
if (reported) return reported;
|
|
23624
23630
|
if (env.CLAUDE_CODE_SESSION_ID) {
|
|
23625
23631
|
const dir = env.CLAUDE_CONFIG_DIR ?? join(home, ".claude");
|
|
23626
23632
|
return await claudeCodeUsage(dir, env.CLAUDE_CODE_SESSION_ID, runId, since);
|
|
@@ -23734,6 +23740,74 @@ function sumCodex(bodies, threadId, since) {
|
|
|
23734
23740
|
total.modelRequests = items.length;
|
|
23735
23741
|
return total;
|
|
23736
23742
|
}
|
|
23743
|
+
var HOST_USAGE_META_KEY = "ai.costgate.momentum/usage";
|
|
23744
|
+
var HostReports = class {
|
|
23745
|
+
constructor(log2) {
|
|
23746
|
+
this.log = log2;
|
|
23747
|
+
}
|
|
23748
|
+
items = [];
|
|
23749
|
+
/** 只吃 `_meta`。工具参数是模型写的,哪怕里面也叫 `_meta`,也不会走到这里 */
|
|
23750
|
+
record(meta, at = /* @__PURE__ */ new Date()) {
|
|
23751
|
+
if (!meta || typeof meta !== "object") return;
|
|
23752
|
+
const value = meta[HOST_USAGE_META_KEY];
|
|
23753
|
+
if (value === void 0) return;
|
|
23754
|
+
for (const item of Array.isArray(value) ? value : [value]) {
|
|
23755
|
+
const report = toHostReport(item);
|
|
23756
|
+
if (report) this.items.push({ ...report, at: at.getTime() });
|
|
23757
|
+
else this.log?.(` \u5FFD\u7565\u4E00\u6761\u683C\u5F0F\u4E0D\u5BF9\u7684\u5BBF\u4E3B\u7528\u91CF\uFF1A${JSON.stringify(item).slice(0, 200)}`);
|
|
23758
|
+
}
|
|
23759
|
+
}
|
|
23760
|
+
since(since) {
|
|
23761
|
+
return this.items.filter((r) => r.at >= since.getTime());
|
|
23762
|
+
}
|
|
23763
|
+
};
|
|
23764
|
+
function parseHostReportFile(body, since, log2) {
|
|
23765
|
+
const out = [];
|
|
23766
|
+
for (const line of body.split("\n")) {
|
|
23767
|
+
if (!line.trim()) continue;
|
|
23768
|
+
const entry = parseLine(line);
|
|
23769
|
+
if (!entry || !inWindow(entry.timestamp, since)) continue;
|
|
23770
|
+
const report = toHostReport(entry);
|
|
23771
|
+
if (report) out.push(report);
|
|
23772
|
+
else log2?.(` \u5FFD\u7565\u4E00\u6761\u683C\u5F0F\u4E0D\u5BF9\u7684\u5BBF\u4E3B\u7528\u91CF\uFF1A${line.slice(0, 200)}`);
|
|
23773
|
+
}
|
|
23774
|
+
return out;
|
|
23775
|
+
}
|
|
23776
|
+
function sumHostReported(reports) {
|
|
23777
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23778
|
+
const total = emptyUsage("host_reported");
|
|
23779
|
+
for (const r of reports) {
|
|
23780
|
+
if (r.requestId !== void 0) {
|
|
23781
|
+
if (seen.has(r.requestId)) continue;
|
|
23782
|
+
seen.add(r.requestId);
|
|
23783
|
+
}
|
|
23784
|
+
total.modelRequests += 1;
|
|
23785
|
+
total.inputTokens += r.inputTokens;
|
|
23786
|
+
total.cachedInputTokens += r.cachedInputTokens;
|
|
23787
|
+
total.outputTokens += r.outputTokens;
|
|
23788
|
+
total.reasoningTokens += r.reasoningTokens;
|
|
23789
|
+
}
|
|
23790
|
+
return total.modelRequests > 0 ? total : null;
|
|
23791
|
+
}
|
|
23792
|
+
function toHostReport(value) {
|
|
23793
|
+
if (!value || typeof value !== "object") return null;
|
|
23794
|
+
const v = value;
|
|
23795
|
+
const count = (x, fallback) => x === void 0 && fallback !== void 0 ? fallback : Number.isSafeInteger(x) && x >= 0 ? x : null;
|
|
23796
|
+
const inputTokens = count(v.inputTokens);
|
|
23797
|
+
const outputTokens = count(v.outputTokens);
|
|
23798
|
+
const cachedInputTokens = count(v.cachedInputTokens, 0);
|
|
23799
|
+
const reasoningTokens = count(v.reasoningTokens, 0);
|
|
23800
|
+
if (inputTokens === null || outputTokens === null || cachedInputTokens === null || reasoningTokens === null) return null;
|
|
23801
|
+
if (cachedInputTokens > inputTokens || reasoningTokens > outputTokens) return null;
|
|
23802
|
+
if (v.requestId !== void 0 && (typeof v.requestId !== "string" || v.requestId.length > 200)) return null;
|
|
23803
|
+
return {
|
|
23804
|
+
...typeof v.requestId === "string" ? { requestId: v.requestId } : {},
|
|
23805
|
+
inputTokens,
|
|
23806
|
+
cachedInputTokens,
|
|
23807
|
+
outputTokens,
|
|
23808
|
+
reasoningTokens
|
|
23809
|
+
};
|
|
23810
|
+
}
|
|
23737
23811
|
var RunMeters = class {
|
|
23738
23812
|
runs = /* @__PURE__ */ new Map();
|
|
23739
23813
|
open(runId, since = /* @__PURE__ */ new Date()) {
|
|
@@ -23780,6 +23854,14 @@ function inWindow(timestamp, since) {
|
|
|
23780
23854
|
const at = timestamp ? Date.parse(timestamp) : Number.NaN;
|
|
23781
23855
|
return Number.isFinite(at) && at >= since.getTime();
|
|
23782
23856
|
}
|
|
23857
|
+
async function readOptional(path) {
|
|
23858
|
+
try {
|
|
23859
|
+
return await readFile(path, "utf8");
|
|
23860
|
+
} catch (err) {
|
|
23861
|
+
if (err.code === "ENOENT") return "";
|
|
23862
|
+
throw err;
|
|
23863
|
+
}
|
|
23864
|
+
}
|
|
23783
23865
|
async function isFile(path) {
|
|
23784
23866
|
try {
|
|
23785
23867
|
return (await stat(path)).isFile();
|
|
@@ -23884,7 +23966,8 @@ function createTools(client, profile = "full", options = {}) {
|
|
|
23884
23966
|
{ log: options.log }
|
|
23885
23967
|
);
|
|
23886
23968
|
const meters = new RunMeters();
|
|
23887
|
-
const
|
|
23969
|
+
const reported = options.hostReports ?? new HostReports(options.log);
|
|
23970
|
+
const readUsage = options.readUsage ?? hostUsageReader(process.env, { log: options.log, reported });
|
|
23888
23971
|
async function measured(runId) {
|
|
23889
23972
|
const meter = meters.get(runId);
|
|
23890
23973
|
if (!meter) return {};
|
|
@@ -24863,7 +24946,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24863
24946
|
const selected = profile === "work" ? tools.filter((tool) => WORK_TOOL_NAMES.has(tool.name)) : tools;
|
|
24864
24947
|
return selected.map((tool) => ({
|
|
24865
24948
|
...tool,
|
|
24866
|
-
handler: async (args) => {
|
|
24949
|
+
handler: async (args, meta) => {
|
|
24950
|
+
reported.record(meta);
|
|
24867
24951
|
const argBytes = byteLength(JSON.stringify(args ?? {}));
|
|
24868
24952
|
const charged = meters.beginCall(argBytes);
|
|
24869
24953
|
let result;
|
|
@@ -24947,8 +25031,9 @@ function createMcpServer(client, profile = "work", options = {}) {
|
|
|
24947
25031
|
server.registerTool(
|
|
24948
25032
|
tool.name,
|
|
24949
25033
|
{ description: tool.description, inputSchema: tool.inputSchema },
|
|
24950
|
-
// SDK 会先按 inputSchema
|
|
24951
|
-
|
|
25034
|
+
// SDK 会先按 inputSchema 校验再调进来,这里的形状转换是安全的。
|
|
25035
|
+
// extra._meta 是请求 params._meta,宿主可以在里面上报用量(IMMO-215)
|
|
25036
|
+
(args, extra) => tool.handler(args, extra._meta)
|
|
24952
25037
|
);
|
|
24953
25038
|
}
|
|
24954
25039
|
return server;
|