@systemdox/mcp-server 0.1.19 → 0.1.21
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/dist/cli.js +1 -1
- package/dist/http.js +38 -2
- package/dist/index.js +1 -1
- package/dist/lib/metrics.d.ts +41 -0
- package/dist/lib/metrics.js +40 -0
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1979,7 +1979,7 @@ var init_server = __esm({
|
|
|
1979
1979
|
init_create_project_rule();
|
|
1980
1980
|
init_get_prompt_templates();
|
|
1981
1981
|
init_create_prompt_template();
|
|
1982
|
-
SERVER_VERSION = true ? "0.1.
|
|
1982
|
+
SERVER_VERSION = true ? "0.1.21" : "0.0.0-dev";
|
|
1983
1983
|
}
|
|
1984
1984
|
});
|
|
1985
1985
|
|
package/dist/http.js
CHANGED
|
@@ -117,6 +117,41 @@ var SystemDoxApiClient = class {
|
|
|
117
117
|
}
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
+
// src/lib/metrics.ts
|
|
121
|
+
var NAMESPACE = "SystemDox/Mcp";
|
|
122
|
+
var METRIC_NAME = "McpToolCall";
|
|
123
|
+
function buildMcpToolCallMetric(tenant, tool, timestamp = Date.now()) {
|
|
124
|
+
return {
|
|
125
|
+
_aws: {
|
|
126
|
+
Timestamp: timestamp,
|
|
127
|
+
CloudWatchMetrics: [
|
|
128
|
+
{
|
|
129
|
+
Namespace: NAMESPACE,
|
|
130
|
+
Dimensions: [["tenant"]],
|
|
131
|
+
Metrics: [{ Name: METRIC_NAME, Unit: "Count" }]
|
|
132
|
+
}
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
tenant,
|
|
136
|
+
tool,
|
|
137
|
+
[METRIC_NAME]: 1
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function emitMcpToolCalls(tenant, rawBody, log = console.log) {
|
|
141
|
+
try {
|
|
142
|
+
const parsed = JSON.parse(rawBody);
|
|
143
|
+
const messages = Array.isArray(parsed) ? parsed : [parsed];
|
|
144
|
+
for (const message of messages) {
|
|
145
|
+
if (typeof message === "object" && message !== null && message.method === "tools/call") {
|
|
146
|
+
const params = message.params;
|
|
147
|
+
const tool = typeof params?.name === "string" ? params.name : "unknown";
|
|
148
|
+
log(JSON.stringify(buildMcpToolCallMetric(tenant || "unknown", tool)));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
120
155
|
// src/server.ts
|
|
121
156
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
122
157
|
|
|
@@ -1790,7 +1825,7 @@ function registerCreatePromptTemplate(server, apiClient) {
|
|
|
1790
1825
|
}
|
|
1791
1826
|
|
|
1792
1827
|
// src/server.ts
|
|
1793
|
-
var SERVER_VERSION = true ? "0.1.
|
|
1828
|
+
var SERVER_VERSION = true ? "0.1.21" : "0.0.0-dev";
|
|
1794
1829
|
function createServer(apiClient) {
|
|
1795
1830
|
const server = new McpServer({
|
|
1796
1831
|
name: "systemdox-mcp-server",
|
|
@@ -1836,9 +1871,9 @@ function jsonError(statusCode, message) {
|
|
|
1836
1871
|
async function handler(event) {
|
|
1837
1872
|
const headers = lowercaseHeaders(event.headers);
|
|
1838
1873
|
const host = (headers["host"] ?? "").toLowerCase();
|
|
1874
|
+
const keyTenant = event.requestContext?.authorizer?.tenant_slug ?? "";
|
|
1839
1875
|
if (host.endsWith(MCP_HOST_SUFFIX)) {
|
|
1840
1876
|
const hostTenant = host.slice(0, -MCP_HOST_SUFFIX.length);
|
|
1841
|
-
const keyTenant = event.requestContext?.authorizer?.tenant_slug ?? "";
|
|
1842
1877
|
if (!hostTenant || hostTenant.includes(".") || hostTenant !== keyTenant) {
|
|
1843
1878
|
return jsonError(403, "API key does not belong to this tenant");
|
|
1844
1879
|
}
|
|
@@ -1860,6 +1895,7 @@ async function handler(event) {
|
|
|
1860
1895
|
return jsonError(401, "Missing bearer API key");
|
|
1861
1896
|
}
|
|
1862
1897
|
const rawBody = event.isBase64Encoded ? Buffer.from(event.body ?? "", "base64").toString("utf8") : event.body ?? "";
|
|
1898
|
+
emitMcpToolCalls(keyTenant, rawBody);
|
|
1863
1899
|
const apiClient = new SystemDoxApiClient({
|
|
1864
1900
|
apiKey,
|
|
1865
1901
|
apiUrl: process.env.SYSTEMDOX_API_URL ?? "https://api.puglieseweb.com/systemdox",
|
package/dist/index.js
CHANGED
|
@@ -1806,7 +1806,7 @@ function registerCreatePromptTemplate(server2, apiClient2) {
|
|
|
1806
1806
|
}
|
|
1807
1807
|
|
|
1808
1808
|
// src/server.ts
|
|
1809
|
-
var SERVER_VERSION = true ? "0.1.
|
|
1809
|
+
var SERVER_VERSION = true ? "0.1.21" : "0.0.0-dev";
|
|
1810
1810
|
function createServer(apiClient2) {
|
|
1811
1811
|
const server2 = new McpServer({
|
|
1812
1812
|
name: "systemdox-mcp-server",
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CloudWatch EMF telemetry for hosted MCP tool calls (issue #978).
|
|
3
|
+
*
|
|
4
|
+
* One metric answers two standing questions:
|
|
5
|
+
* - activation: "which tenants had ≥1 agent MCP call this week?" —
|
|
6
|
+
* `McpToolCall` dimensioned by `tenant`, joined against the repo
|
|
7
|
+
* `connectedAt` cohort in DynamoDB;
|
|
8
|
+
* - the deprecated-alias removal gate (README "Deprecated tool names"):
|
|
9
|
+
* per-tool-name counts come from the `tool` property via Logs Insights,
|
|
10
|
+
* kept out of the dimensions so metric cardinality stays = tenants.
|
|
11
|
+
*
|
|
12
|
+
* EMF is a formatted console.log — no SDK dependency, no latency, and the
|
|
13
|
+
* Lambda's existing log group is the transport. Telemetry must never break
|
|
14
|
+
* the request path: emitters swallow their own failures.
|
|
15
|
+
*/
|
|
16
|
+
declare const METRIC_NAME = "McpToolCall";
|
|
17
|
+
export interface McpToolCallMetric {
|
|
18
|
+
_aws: {
|
|
19
|
+
Timestamp: number;
|
|
20
|
+
CloudWatchMetrics: {
|
|
21
|
+
Namespace: string;
|
|
22
|
+
Dimensions: string[][];
|
|
23
|
+
Metrics: {
|
|
24
|
+
Name: string;
|
|
25
|
+
Unit: string;
|
|
26
|
+
}[];
|
|
27
|
+
}[];
|
|
28
|
+
};
|
|
29
|
+
tenant: string;
|
|
30
|
+
tool: string;
|
|
31
|
+
[METRIC_NAME]: number;
|
|
32
|
+
}
|
|
33
|
+
/** Build the EMF envelope for a single tool call. Pure — unit-testable. */
|
|
34
|
+
export declare function buildMcpToolCallMetric(tenant: string, tool: string, timestamp?: number): McpToolCallMetric;
|
|
35
|
+
/**
|
|
36
|
+
* Parse a JSON-RPC request body (single message or batch) and emit one EMF
|
|
37
|
+
* line per `tools/call`. Anything unparseable or non-tool (initialize,
|
|
38
|
+
* tools/list, notifications) is ignored. Never throws.
|
|
39
|
+
*/
|
|
40
|
+
export declare function emitMcpToolCalls(tenant: string, rawBody: string, log?: (line: string) => void): void;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/metrics.ts
|
|
4
|
+
var NAMESPACE = "SystemDox/Mcp";
|
|
5
|
+
var METRIC_NAME = "McpToolCall";
|
|
6
|
+
function buildMcpToolCallMetric(tenant, tool, timestamp = Date.now()) {
|
|
7
|
+
return {
|
|
8
|
+
_aws: {
|
|
9
|
+
Timestamp: timestamp,
|
|
10
|
+
CloudWatchMetrics: [
|
|
11
|
+
{
|
|
12
|
+
Namespace: NAMESPACE,
|
|
13
|
+
Dimensions: [["tenant"]],
|
|
14
|
+
Metrics: [{ Name: METRIC_NAME, Unit: "Count" }]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
tenant,
|
|
19
|
+
tool,
|
|
20
|
+
[METRIC_NAME]: 1
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function emitMcpToolCalls(tenant, rawBody, log = console.log) {
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(rawBody);
|
|
26
|
+
const messages = Array.isArray(parsed) ? parsed : [parsed];
|
|
27
|
+
for (const message of messages) {
|
|
28
|
+
if (typeof message === "object" && message !== null && message.method === "tools/call") {
|
|
29
|
+
const params = message.params;
|
|
30
|
+
const tool = typeof params?.name === "string" ? params.name : "unknown";
|
|
31
|
+
log(JSON.stringify(buildMcpToolCallMetric(tenant || "unknown", tool)));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
buildMcpToolCallMetric,
|
|
39
|
+
emitMcpToolCalls
|
|
40
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@systemdox/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
|
+
"mcpName": "io.github.puglieseweb/systemdox",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"description": "Give AI coding agents your architecture context over MCP — checks, specs, ADRs, project rules, and docs from SystemDox, delivered at write time",
|
|
6
7
|
"main": "./dist/index.js",
|